几乎所有顶级的互联网和软件公司都用算法和数据结构来考察软件工程师。不过,我不打算讨论算法的重要性以及它们对实际工作是否有用(我认为这是一个优秀程序员不可或缺的基本技能),也不讨论“Google-style”的有效性和合理性《算法面试》和《白板编程》,作为一名非《编程竞赛》背景的工程师,分享一些自己实践过的算法和数据结构学习过程,欢迎大家讨论批评。结合自己的学习心得和我作为“信息学竞赛”教练的教学实践,我通常认为学习算法最关键的有以下三点:1.首先练习“表达能力”有同学问,我“看懂”了课本上的所有算法,以及选择题或者手工推导过程中的题我都能做对,但是就是不会写“代码”或者“伪代码”,算法题上来就更加手足无措了。在我看来,首先是缺乏“表达能力”。除非你是经验丰富的程序员,否则我认为在学习一门编程语言的语法时,一开始最重要的是学习如何“表达”逻辑和流程。很多算法竞赛书上都有一种方法叫“模拟法”。说白了,这种方法就是把我们自然而然地处理问题的步骤“直截了当地”“程序化”了。比如“求最大数”的过程,“矩阵运算”的过程,“基数转换”或“求最大公约数”中使用的“反转除法”,模拟的“大整数加法”垂直操作等,我们可以直接通过程序“模拟”这个“过程”。大多数编程书籍在介绍语法的时候,都会提供类似这些问题的练习,帮助我们增强语言的表达能力。如果你使用Python作为你的主要语言,《LearnPythontheHardWay》有很多练习表达能力的问题。完成学习后,你一定会收获很多。“hackerrank”上有专门的“领域”,用来练习“程序表达”。阿三出的题,大部分都还不错。开发一些简单的应用“demo”也可以学习一些语言表达,但由于逻辑往往过于简单,不利于这种实践。2.先看书再写题。其实真正看完《算法导论》后做以上练习的人并不多。我经常把它当作参考书来查,也只是断断续续地读了一些章节。推荐没有很好算法基础的初学者选择RobertSedgewick的《算法》,这是一本比较简单易懂的书。了解算法的原理和执行过程,然后学习手动模拟过程,然后尝试自己实现,同时练习一些题目,不断加强对算法的理解。多练习书上的习题,通常比自己从“OJ”里找题要好,尤其是一些证明和分析题不允??许直接写代码,更能促进对算法本质的理解。比如“快速排序”的最坏情况和最好情况是如何产生的,使用随机和固定策略的优缺点分析,为什么这个排序算法“不稳定”。在此基础上开展“OJ”刷题训练,提高实现“Coding”的能力,加深对算法的理解。通过这样的训练,至少我们可以针对清晰算法的问题,正确的写出代码,然后用“debug”去解决细节问题。3.问题的归约和转换有时我明确告诉一些同学,你可以写一个“二叉树的层次遍历”,他也许能写出来。但是当我让他在一张“未经授权的图”上求“最短路径”时,他一头雾水。甚至有的时候,当“图”不是我们在《数据结构》中学过的“邻接矩阵”或“邻接表”表示的时候,我也不知道如何向“图”提出一个问题。他们不明白这里的“图”可以是看不见的图。我们需要找到某个“节点”的所有连接的“节点”。找出的过程可以是指针指向的“有形边缘”。”,也可以是经过一些数学运算或变换后得到的值。对于“八皇后”问题,我们在先深入遍历整个状态图的时候,不断检查从一种状态转移到另一种状态的合理性,从而求出正确的解。我们的计算机本质上就是一个“状态机”,动态规划或者说搜索就是从状态转移中寻找正确的解。对于每一个具体的算法,比如动态规划、贪心、递归的含义,都有“quora”和“知乎”上有很多高质量的答案解析,在学习的过程中阅读也可以帮助我们解惑,问题的还原和转化需要不断的实践。所以除了前面说的《算法》,找一本和习题相匹配的书也是非常有必要的,在我自己的学习过程中,我使用了秋叶拓哉的《挑战程序设计竞赛》和刘茹嘉翻译的《挑战编程:程序设计竞赛训练手册》,基础差的同学可以选择刘茹嘉的《算法竞赛入门经典(第2版)》.我们的目的是学习算法,而不是刷题,培养成为“编程竞技高手”,所以我觉得只需要选择经典题来练习即可。我自己不是“编程竞技高手”,但通过学习和实践,除非有特别“刁钻”的题,否则“Leetcode”或者“CC150”或者考研都能轻松搞定。当然,我们学习算法的目的肯定不是为了面试。这对我们的工作也有很大的帮助,这里就不展开讨论了。当你信心满满的时候,你可以尝试解决“Leetcode”上的经典面试问题。美帝大厂的面试题都是一遍又一遍的这些题,真是没创意。或者你可以去“hackerrank”参加公司的“招聘目的”竞赛,说不定还能翻墙去美国。
