本以为是一本高屋建瓴的书,没想到是一本讲算法的书。本以为是本讲刷题的书,没想到是一本顶层思维的书。
吴军老师用朗道的方法,讲计算机工程师分为7级
- 七级:本科毕业自水平不错的大学的计算机专业,但没有参加过6个月以上实习的学生。
- 六级:能在他人指导下完成计算机工程师的工作。
- 五级:能够独立解决问题,完成工程工作。
- 四级:能够用已知的最优方法解决问题,并指导和带领其他人一同完成更有影响力的工作。
- 三级:能够解决前人未解决的问题,并且能独立设计和实现产品,在市场上获得成果。
- 二级:能够提出重要的计算机理论和实践中的新问题,并解决他们,还能设计和实现别人做不出的产品。
- 一级:能够开创一个产业,或者奠定一个学科的基础。
这7级按照国内的码农评级水平应该是这样:
- 七级:211、985计算机专业在校生
- 六级:阿里P5
- 五级:阿里P6~p7
- 四级:阿里p7~p9
- 三级:阿里p10~
- 二级:无
- 一级:无
化繁为简-分治思想及应用
- 分治总共分三步:
- 分 divide
- 解决每个子问题 conquer
- 合并 combine
- 归并排序和快排都属于分治。他们的区别在于:
- 分割的时候
- 归并排序,取中间节点,将前后两个相同个数的子块各自排序好,再合并排序;
- 快排,随机取一个点A,以A为中心,将所有数分为大于A和小于A两部分,再排序。
- 合并的时候
- 归并排序,合并两个子块的时候,还要将两个子块边排序边合并;
- 快排,分割的时候排序,合并的时候顺序已经排好,直接合并。
- 分割的时候
- 取最大的k个数
- 不一定要用最大/小堆排序
- 使用快排的partition算法,将最大的k-1个数排在第k个数前面即可,这些数不一定是排好序的。
partition(A, start, end) {
pivot = A[start];
left_pos = start - 1;
right_pos = end + 1;
while(left_pos<right_pos) {
// 从后往前找到序列右边第一个小于pivot的元素
while(left_pos<right_pos && A[right_pos] >= pivot) {
right_pos -= 1;
}
// 从前往后找到序列左边第一个大于pivot的元素
while(left_pos<right_pos && A[left_pos] <= pivot) {
left_pos += 1;
}
if(left_pos < right_pos) {
swap(A[left_pos], A[right_pos]);
}else {
swap(A[start], A[right_pos]);//这一步不要忘了
return right_pos; // 序列比较完了,返回枢值所在位置
}
}
}
- 给定一个非常巨大的数,如何找到他的中值 (使用O(N)时间复杂度)
权衡时空-理解存储
- 给定一个二进制数,如何有效数出其中1的数量
吴军老师在书中说到:
x & (x-1)算法,只能保证平均运行时间的减少,并不能保证最坏情况比顺序数1的个数方法更好,因此我们就不推荐这种方法了。
而在《剑指offer》一书中,该算法被称为“能给面试官带来惊喜的解法” 二者的计算机高度差距,一目了然。
关于面试
根据我的经验,一道面试题,如果20%的人能够回答的很圆满,一半的人经过一些提示和讨论能够找到正确答案,剩下的人做不出来,这样最能区分面试者的水平,太难或太容易都不利于筛选面试者。
- 最长回文问题
对于这个问题,最有效的方法是马拉车(Manacher)算法。这个问题除了靠算法、考查一个人对递归的理解,我想不出任何实际的意义,因此这个问题算不得好的面试题。我曾经和一些将Manacher算法背下来的面试者交流过,让他们给我讲讲原理,几乎没有人讲的清楚,更没有人能够分析清楚他的算法复杂度。
读后总结
吴军老师这本书高屋建瓴的讲解算法思维在计算机中的应用,而不是单纯应试的刷leetcode。更宏观的从思维方式出发,理解计算机思维不仅仅有助于工作,也可以应用于生活。也更微观的从计算机最底层原理的存储、处理器工作的角度讲解为什么要这样。 读完感觉,要想达到3级工程师水平,要把数学基础、计算机基础要研究的很扎实才行。 书是没太看懂,以后常看常新,希望有完全看懂的一天。