算法重要吗?
都听说算法重要,可是大部分人内心深处是很不认同这一说法的,因为自己平时工作好像压根就用不到算法,认为算法就是没有意义的智力题。真的如此吗,下面是一些事实和分析。
事实
- 国外公司Google, Amozon, 微软等公司面试内容一般只有算法,4-5面,一面到三面每一面2-3到题,四面1-2道题目,五面谈人生。
- 国内公司,工资越高的公司面试中算法占比越大。
- ACM比赛获奖者在职场上很受青睐,因为思维快,解决问题能力强。
- 新兴方向中,例如AI对求职者算法水平要求更高。
分析
- 工作中算法用得到吗?先思考以下问题
- 10亿的黑名单,要查询某个用户是否在黑名单内,如何做?10亿的黑名单,要查询某个用户是否在黑名单内,如何做?
- 比如业务上需要调度器有某些很特殊的性质,市面上没有,需要自己造一个的时候,怎么做?
- 社交网络,一个信息传达从一个用户传达到另一个用户最短要几次转发?(最短路径)
- 要你写个功能,有个算法能很完美的实现,但是你不知道,你照着最直白的思路去实现,可以用,业务上线,然后用户量增大,服务器卡爆!所以说没有用到算法,一方面可能是确实不需要算法,还有另一种可能就是需要用到但是你不知道,压根没往这方面想,比如刚才的黑名单问题(布隆过滤器),还有Hot Spot问题(一致性哈希),算法就是为了解决工程而存在,算法水平也应该是软件工程师的基础能力。
- 假如你的工作就是写写接口,调调API,调调参数这些培训两个月就能搞定的事情,那公司裁员的时候裁谁?
- 面试中用算法筛选求职者对公司来说是很省成本的方式,算法好的面试者一般能说明他思维不差,用心准备了,基础素质过关。即使最后验证真的不是合适的人选,不还有试用期呢吗。虽然这会造成能胜任工作,其他能力过关,而算法是短板的求职者被不幸刷掉,可是这又如何呢,公司要的是适合岗位的人,不是所有适合岗位的人。这种误伤是可以被公司接受的。只是站在求职者角度说非常难以理解而已。
总结
- 找工作需要算法,为了前(钱)景,即使算法不重要,你也要学习算法。
- 职业前景需要算法,你是要造航母还是要当一辈子的拧螺丝的?
- 解决问题需要算法,算法水平的积累与提高会帮助我们更好的理解问题,寻求更快更省更优雅的解决方案。
- 算法本身就挺有意思的,你坚持刷下去会看到它的美。
所以,算法重要,而且很重要。
学习路线
学习算法很常见的一个场景是,
- 开始刷Leetcode
- 看了题目半天没有思路
- 苦思冥想之后还是不行,大致看下别人思路,开始coding
- 提交,“Wrong Answer”
- “奥,没考虑这个条件”
- 修改,提交,“Wrong Answer”
- “奥,没考虑这种case”
- 修改,提交,“Wrong Answer”
- one thousand years later…
- “Accept”
- “卧槽,太艰难了,果然我智商不行,算法不适合我,不学了不学了”
算法学习的特点:学习路径相对陡峭,挫败性很强。很多人都是陷入对自己深深的怀疑然后放弃算法学习的。但是实际原因是没有循序渐进的去学习,你二叉树都没搞明白呢想去撸一个红黑树;回溯都不知道想去做n皇后;堆结构是个啥没概念想去弄堆排序。这不是找虐吗?但是假如你会了归并,那两个有序链表的归并肯定不在话下;你会了快排,那荷兰国旗就不是个大问题。
算法问题很多都是以其他算法为基础的,很多题目都是有套路的。 所以并不是你笨,而是你基础不扎实或者你见识的太少。总而言之,你的学习路线不够平缓。那什么样才是正确的学习路线呢。
首先掌握基础知识,其次再刷题。具体步骤如下(本文针对的是刷题小白或者抗拒刷题的人,大神请自动略过)。
基础知识
首先必须掌握基础知识,因为基础都不知道,刷题寸步难行,就好像不了解多线程让你写并发一样困难。当然你是可以通过刷题,来学习基础,但是这就本末倒置了,刷题可以是用来练习思维的,对基础知识只是查缺补漏的程度,当作主要学习手段是很蠢的。
具体操作是首先选一本书或者一门课去复习这些知识,这里推荐本科的教科书,因为毕竟上过一遍是有印象的。如果不是科班或者本科全部水过去的,我推荐《算法(第4版)》,经典不解释,英语水平不过关的可以去搜中文版。更深入的当然力推《算法导论》。视频教程的话中国大学Mooc上浙大的课程不错,牛客网上的左程云讲的也很不错,不过是付费的,这里就不贴链接了。
至于学习方法,首先把基础知识弄明白,这个难度应该不大,可能个别地方比如红黑树,KMP之类的比较难理解,不会的可以去这里看看 :算法可视化。其次一定一定一定要练一遍,经典算法的练习你当然可以自己IDE里面写,可以有测试用例检测就更好了,这里就式很合适的地方:经典算法练习。或者参考下github上别人的实现:经典算法Java实现,也学习学习好的代码习惯。明白了和掌握了之间是需要动手训练的。最后要自己做个总结。
下面是一些简单的梳理
- 数据结构
- 顺序表
- 顺序表的表示
- 顺序表的增删改查
- 常见排序算法(冒泡,选择,插入,希尔,通,归并,快排,堆排序,桶排序,基数排序)
- 队列
- 栈
- 链表
- 单链表
- 单链表的增删改查
- 双链表
- 链式栈,链式队列
- 环形队列
- 块状表
- 树
- 二叉树
- 二叉树的链式存储
- 二叉树的顺序存储
- 二叉树的建立
- 哈夫曼树
- 二叉树的遍历(先序,中序,后序,层次)
- 二叉排序树(二叉搜索树)
- 二叉排序树的建立
- 完全二叉树
- 堆
- 大顶堆,小顶堆
- 堆排序
- 平衡二叉树
- 二叉树的旋转
- 多叉树
- B+树
- 二叉树
- 图
- 有向图与无向图、强连通图与弱连通图
- 图中的环
- 图的线性存储与矩阵存储
- 边集与顶点集以及邻接表
- 矩阵及稀疏矩阵的链式存储
- 十字链表与邻接多重表
- 图的遍历
- DFS(栈)
- BFS(队列)
- 图的最小生成树
- 克鲁斯卡尔算法
- 普里姆算法
- 最短路径
- 迪杰斯特拉算法
- AOV网
- 拓扑排序
- AOE网
- 关键路径
- 顺序表
- 算法
- 分治
- 主定理
- 二分搜索,归并,快排,汉诺塔,选最大最小,最大字段和,Strassen矩阵乘法,循环赛日程,FFT,凸包
- dp
- 背包问题,矩阵链相乘,LCS,投资问题,最大子段和,
- 贪心
- 活动选择,背包,多机调度,哈夫曼树,前缀码,迪杰斯特拉算法,最小生成树
- 回溯
- n皇后,货郎问题,图的着色
- 分治
- 补充
- 数据结构
- 线段树,树状数组,并查集,字典树
- 算法
- 扫描线,拓扑排序,滑动窗口,蓄水池,flood fill
- 其他
- 位运算,设计思想,数学知识,语言中的数据结构(比如C++的STL,Java,C#的Collection)
- 数据结构
刷题
基础算法掌握后,开始刷题吧。这里介绍一下路线。可以先刷一些难度较小,题目比较典型的,这里推荐结合《剑指Offer》第二版书籍,刷牛客网的剑指Offer的OJ. 接下来就去Leetcode刷题吧,刷题要有个顺序,有人按照题型刷,有人按照AC比例刷,这个因人而异,我推荐看下这个分析,按照花花酱的推荐去刷我感觉挺好的。
另外介绍一下两种刷题方式,一种是龟式刷题法,一种是兔式刷题法。龟式刷题法就是做题的时候不看提示,不看答案,自己思考,速度自然很慢,但是做出来成就感很大,对思维的训练也很大,但是耗费时间,适合基础扎实,刷题经验丰富或者想挑战自己的人。兔式刷题法则是看完题目,大概5分钟内没有思路,立刻看答案,选择最好的思路自己实现,这样刷的很快,但是印象可能不是很深刻,优点是腾出时间多刷几遍,而且刷题的广度很快就上去了。适合没刷多少题目,基础掌握的还不是很牢固的新手。建议刷题广度上去(标准是你自我感觉大部分类型的题目都见过了)之前兔式,之后龟式。
算法学习道路任重而道远,与诸君共勉。