惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Forbes - Security
Forbes - Security
L
Lohrmann on Cybersecurity
Simon Willison's Weblog
Simon Willison's Weblog
P
Proofpoint News Feed
P
Privacy International News Feed
The Hacker News
The Hacker News
AWS News Blog
AWS News Blog
S
Securelist
P
Proofpoint News Feed
Recent Announcements
Recent Announcements
GbyAI
GbyAI
B
Blog RSS Feed
A
About on SuperTechFans
C
CXSECURITY Database RSS Feed - CXSecurity.com
Y
Y Combinator Blog
Microsoft Azure Blog
Microsoft Azure Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Cyberwarzone
Cyberwarzone
I
Intezer
T
Tor Project blog
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
Recorded Future
Recorded Future
aimingoo的专栏
aimingoo的专栏
Cisco Talos Blog
Cisco Talos Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
W
WeLiveSecurity
D
DataBreaches.Net
U
Unit 42
Project Zero
Project Zero
Martin Fowler
Martin Fowler
V
V2EX
The Last Watchdog
The Last Watchdog
Security Archives - TechRepublic
Security Archives - TechRepublic
C
Cisco Blogs
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V2EX - 技术
V2EX - 技术
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Threat Research - Cisco Blogs
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Tenable Blog
F
Full Disclosure
T
The Exploit Database - CXSecurity.com
H
Heimdal Security Blog
Latest news
Latest news
Webroot Blog
Webroot Blog

酷 壳 – CoolShell

感染新冠的经历 | 酷 壳 - CoolShell 从一次经历谈 TIME_WAIT 的那些事 | 酷 壳 - CoolShell 网络数字身份认证术 | 酷 壳 - CoolShell 我做系统架构的一些原则 | 酷 壳 - CoolShell 源代码特洛伊木马攻击 | 酷 壳 - CoolShell Go编程模式 : 泛型编程 | 酷 壳 - CoolShell 如何做一个有质量的技术分享 | 酷 壳 - CoolShell Go 编程模式:k8s Visitor 模式 | 酷 壳 - CoolShell Go编程模式:Pipeline | 酷 壳 - CoolShell Go编程模式:委托和反转控制 | 酷 壳 - CoolShell Go 编程模式:Go Generation | 酷 壳 - CoolShell Go编程模式:Map-Reduce | 酷 壳 - CoolShell Go 编程模式:错误处理 | 酷 壳 - CoolShell Go编程模式:切片,接口,时间和性能 | 酷 壳 - CoolShell 百度为什么掉队了 | 酷 壳 - CoolShell 程序员如何把控自己的职业 | 酷 壳 - CoolShell 计时攻击 Timing Attacks | 酷 壳 - CoolShell Rust语言的编程范式 | 酷 壳 - CoolShell HTTP的前世今生 | 酷 壳 - CoolShell 记一次Kubernetes/Docker网络排障 | 酷 壳 - CoolShell 可视化编程 | 酷 壳 - CoolShell 程序的本质复杂性和元语言抽象 | 酷 壳 - CoolShell 伙伴分配器的一个极简实现 | 酷 壳 - CoolShell C++11的Lambda使用一例:华容道求解 | 酷 壳 - CoolShell C++面试中string类的一种正确写法 | 酷 壳 - CoolShell C++模板”>>”编译问题与词法消歧设计 | 酷 壳 - CoolShell 数据即代码:元驱动编程 | 酷 壳 - CoolShell 数据的游戏:冰与火 | 酷 壳 - CoolShell 7个示例科普CPU Cache | 酷 壳 - CoolShell 加班与效率 | 酷 壳 - CoolShell 类型的本质和函数式实现 | 酷 壳 - CoolShell C语言全局变量那些事儿 | 酷 壳 - CoolShell 二叉树迭代器算法 | 酷 壳 - CoolShell Alan Cox:大教堂、市集与市议会 | 酷 壳 - CoolShell IoC/DIP其实是一种管理思想 | 酷 壳 - CoolShell 无锁HashMap的原理与实现 | 酷 壳 - CoolShell 浏览器的渲染原理简介 | 酷 壳 - CoolShell 疫苗:Java HashMap的死循环 | 酷 壳 - CoolShell Unix考古记:一个“遗失”的shell | 酷 壳 - CoolShell PFIF网上寻人协议 | 酷 壳 - CoolShell 实例分析Java Class的文件结构 | 酷 壳 - CoolShell 并发框架Disruptor译文 | 酷 壳 - CoolShell AWK 简明教程 | 酷 壳 - CoolShell Linus:利用二级指针删除单向链表 | 酷 壳 - CoolShell 从面向对象的设计模式看软件设计 | 酷 壳 - CoolShell 应该知道的Linux技巧 | 酷 壳 - CoolShell Web工程师的工具箱 | 酷 壳 - CoolShell 程序员疫苗:代码注入 | 酷 壳 - CoolShell 如何测试洗牌程序 | 酷 壳 - CoolShell TF-IDF模型的概率解释 | 酷 壳 - CoolShell xkcd 神图“Click and Drag” | 酷 壳 - CoolShell Bret Victor – Learnable Programming | 酷 壳 - CoolShell C/C++语言中闭包的探究及比较 | 酷 壳 - CoolShell 对九个超级程序员的采访 | 酷 壳 - CoolShell “单元测试要做多细?” | 酷 壳 - CoolShell 一次Ajax查错的经历 | 酷 壳 - CoolShell GCC 用 C++ 来编译 | 酷 壳 - CoolShell K Nearest Neighbor 算法 | 酷 壳 - CoolShell 对技术的态度 | 酷 壳 - CoolShell InfoQ的ArchSummit大会对我的采访 | 酷 壳 - CoolShell 各式各样的验证码 | 酷 壳 - CoolShell 代码执行的效率 | 酷 壳 - CoolShell 28个Unix/Linux的命令行神器 | 酷 壳 - CoolShell 少即是极多 | 酷 壳 - CoolShell 关于闰秒 | 酷 壳 - CoolShell K-Means 算法 | 酷 壳 - CoolShell 持续部署,并不简单! | 酷 壳 - CoolShell Git显示漂亮日志的小技巧 | 酷 壳 - CoolShell 性能调优攻略 | 酷 壳 - CoolShell 抄袭,腾讯 和 产品 | 酷 壳 - CoolShell Lisp的永恒之道 | 酷 壳 - CoolShell Javascript 中的 var | 酷 壳 - CoolShell Huffman 编码压缩算法 | 酷 壳 - CoolShell 扎克伯格的一封信:关于Facebook IPO | 酷 壳 - CoolShell 用Unix的设计思想来应对多变的需求 | 酷 壳 - CoolShell 做个环保主义的程序员 | 酷 壳 - CoolShell 游戏:VIM大冒险 | 酷 壳 - CoolShell 我们需要专职的QA吗? | 酷 壳 - CoolShell 谈谈数据安全和云存储 | 酷 壳 - CoolShell 需求变化与IoC | 酷 壳 - CoolShell 再谈javascript面向对象编程 | 酷 壳 - CoolShell 千万别惹程序员 | 酷 壳 - CoolShell 由一个问题到 Resin ClassLoader 的学习 | 酷 壳 - CoolShell 腾讯,竞争力 和 用户体验 | 酷 壳 - CoolShell SteveY对Amazon和Google平台的吐槽 | 酷 壳 - CoolShell 千万不要把 bool 设计成函数参数 | 酷 壳 - CoolShell 重构代码的7个阶段 | 酷 壳 - CoolShell 10个必需的iOS开发工具和资源 | 酷 壳 - CoolShell 你确信你了解时间吗? | 酷 壳 - CoolShell 为什么Scrum不行? | 酷 壳 - CoolShell 一个空格引发的惨剧 | 酷 壳 - CoolShell 一些软件设计的原则 | 酷 壳 - CoolShell 再谈“我是怎么招聘程序员的”(上) | 酷 壳 - CoolShell 再谈“我是怎么招聘程序员的”(下) | 酷 壳 - CoolShell 超强的验证码 | 酷 壳 - CoolShell 我是怎么招聘程序员的 | 酷 壳 - CoolShell 到处都是Unix的胎记 | 酷 壳 - CoolShell 谁写了Linux | 酷 壳 - CoolShell 在线代码编译服务Codepad.org | 酷 壳 - CoolShell 简单实用的Code Review工具 | 酷 壳 - CoolShell
为什么我反对纯算法面试题 | 酷 壳 - CoolShell
陈皓 · 2012-08-22 · via 酷 壳 – CoolShell

算法面试可能是微软搞出来的面试方法,现在很多公司都在效仿,而且我们的程序员也乐于解算法题,我个人以为,这是应试教育的毒瘤!我在《再谈“我是怎么招程序员”》中比较保守地说过,“问难的算法题并没有错,错的很多面试官只是在肤浅甚至错误地理解着面试算法题的目的。”,今天,我想加强一下这个观点——我反对纯算法题面试!(注意,我说的是纯算法题)

图片源Wikipedia(点击图片查看词条)

我再次引用我以前的一个观点——

能解算法题并不意味着这个人就有能力就能在工作中解决问题,你可以想想,小学奥数题可能比这些题更难,但并不意味着那些奥数能手就能解决实际问题。

好了,让我们来看一个示例(这个示例是昨天在微博上的一个讨论),这个题是——“找出无序数组中第2大的数”,几乎所有的人都用了O(n)的算法,我相信对于我们这些应试教育出来的人来说,不用排序用O(n)算法是很正常的事,连我都不由自主地认为O(n)算法是这个题的标准答案。我们太习惯于标准答案了,这是我国教育最悲哀的地方。(广义的洗脑就是让你的意识依赖于某个标准答案,然后通过给你标准答案让你不会思考而控制你)

功能性需求分析

试想,如果我们在实际工作中得到这样一个题 我们会怎么做?我一定会分析这个需求,因为我害怕需求未来会改变,今天你叫我找一个第2大的数,明天你找我找一个第4大的数,后天叫我找一个第100大的数,我不搞死了。需求变化是很正常的事。分析完这个需求后,我会很自然地去写找第K大数的算法——难度一下子就增大了。

很多人会以为找第K大的需求是一种“过早扩展”的思路,不是这样的,我相信我们在实际编码中写过太多这样的程序了,你一定不会设计出这样的函数接口—— Find2ndMaxNum(int* array, int len),就好像你不会设计出 DestroyBaghdad(); 这样的接口,而是设计一个DestoryCity( City& ); 的接口,而把Baghdad当成参数传进去!所以,你应该是声明一个叫FindKthMaxNum(int* array, int len, int kth),把2当成参数传进去。这是最基本的编程方法,用数学的话来说,叫代数!最简单的需求分析方法就是把需求翻译成函数名,然后看看是这个接口不是很二?!

(注:不要纠结于FindMaxNum()或FindMinNum(),因为这两个函数名的业务意义很清楚了,不像Find2ndMaxNum()那么二)

非功能性需求分析

性能之类的东西从来都是非功能性需求,对于算法题,我们太喜欢研究算法题的空间和时间复杂度了。我们希望做到空间和时间双丰收,这是算法学术界的风格。所以,习惯于标准答案的我们已经失去思考的能力,只会机械地思考算法之内的性能,而忽略了算法之外的性能

如果题目是——“从无序数组中找到第K个最大的数”,那么,我们一定会去思考用O(n)的线性算法找出第K个数。事实上,也有线性算法——STL中可以用nth_element求得类似的第n大的数,其利用快速排序的思想,从数组S中随机找出一个元素X,把数组分为两部分Sa和Sb。Sa中的元素大于等于X,Sb中元素小于X。这时有两种情况:1)Sa中元素的个数小于k,则Sb中的第k-|Sa|个元素即为第k大数;2) Sa中元素的个数大于等于k,则返回Sa中的第k大数。时间复杂度近似为O(n)。

搞学术的nuts们到了这一步一定会欢呼胜利!但是他们哪里能想得到性能的需求分析也是来源自业务的!

我们一说性能,基本上是个人都会问,请求量有多大?如果我们的FindKthMaxNum()的请求量是m次,那么你的这个每次都要O(n)复杂度的算法得到的效果就是O(n*m),这一点,是书呆子式的学院派人永远想不到的。因为应试教育让我们不会从实际思考了。

工程式的解法

根据上面的需求分析,有软件工程经验的人的解法通常会这样:

1)把数组排序,从大到小。

2)于是你要第k大的数,就直接访问 array[k]。

排序只需要一次,O(n*log(n)),然后,接下来的m次对FindKthMaxNum()的调用全是O(1)的,整体复杂度反而成了线性的。

其实,上述的还不是工程式的最好的解法,因为,在业务中,那数组中的数据可能会是会变化的,所以,如果是用数组排序的话,有数据的改动会让我重新排序,这个太耗性能了,如果实际情况中会有很多的插入或删除操作,那么可以考虑使用B+树。

工程式的解法有以下特点:

1)很方便扩展,因为数据排好序了,你还可以方便地支持各种需求,如从第k1大到k2大的数据(那些学院派写出来的代码在拿到这个需求时又开始挠头苦想了)

2)规整的数据会简化整体的算法复杂度,从而整体性能会更好。(公欲善其事,必先利其器)

3)代码变得清晰,易懂,易维护!(学院派的和STL一样的近似O(n)复杂度的算法没人敢动)

争论

你可能会和我有以下争论,

  • 如果程序员做这个算法题用排序的方式,他一定不会像你想那么多。是的,你说得对。但是我想说,很多时候,我们直觉地思考,恰恰是正确的路。因为“排序”这个思路符合人类大脑处理问题的方式,而使用学院派的方式是反大脑直觉的。反大脑直觉的,通常意味着晦涩难懂,维护成本上升。
  • 就是一道面试题,我就是想测试一下你的算法技能,这也扯太多了。没问题,不过,我们要清楚我们是在招什么人?是一个只会写算法的人,还是一个会做软件的人?这个只有你自己最清楚。
  • 这个算法题太容易诱导到学院派的思路了。是的这道“找出第K大的数”,其实可以变换为更为业务一点的题目——“我要和别的商户竞价,我想排在所有竞争对手报价的第K名,请写一个程序,我输入K,和一个商品名,系统告诉我应该订多少价?(商家的所有商品的报价在一数组中)”——业务分析,整体性能,算法,数据结构,增加需求让应聘者重构,这一个问题就全考了。
  • 你是不是在说算法不重要,不用学?千万别这样理解我,搞得好像如果面试不面,我就可以不学。算法很重要,算法题能锻炼我们的思维,而且也有很多实际用处。我这篇文章不是让大家不要去学算法,这是完全错误的,我是让大家带着业务问题去使用算法。问你业务问题,一样会问到算法题上来。

小结

看过这上面的分析,我相信你明白我为什么反对纯算法面试题了。原因就是纯算法的面试题根本不能反应一个程序的综合素质

那么,在面试中,我们应该要考量程序员的那些综合素质呢?我以为有下面这些东西:

  1. 会不会做需求分析?怎么理解问题的?
  2. 解决问题的思路是什么?想法如何?
  3. 会不会对基础的算法和数据结构灵活运用?

另外,我们知道,对于软件开发来说,在工程上,难是的下面是这些挑战:

  • 软件的维护成本远远大于软件的开发成本。
  • 软件的质量变得越来越重要,所以,测试工作也变得越来越重要。
  • 软件的需求总是在变的,软件的需求总是一点一点往上加的。
  • 程序中大量的代码都是在处理一些错误的或是不正常的流程。

所以,对于编程能力上,我们应该主要考量程序员的如下能力:

  1. 设计是否满足对需求的理解,并可以应对可能出现的需求变化。
  2. 程序是否易读,易维护?
  3. 重构代码的能力如何?
  4. 会不会测试自己写好的程序?

所以,这段时间,我越来越倾向于问应聘者一些有业务意义的题,而且应增加或更改需求来看程序员的重构代码的能力,写完程序后,让应聘者设计测试案例。

比如:解析加减乘除表达式,字符串转数字,洗牌程序,口令生成器,通过ip地址找地点,英汉词典双向检索……

总之,我反对纯算法面试题!

(全文完)

Loading...