算法题到底咋做很多题根本找不到思路,每个题做完弄懂之后,下一次还是重写不出来,不知道啥算懂( 五 )


整个人完全奔溃,不刷题了,不准备算法面试了,不准备跳槽了!
后来我不停的告诫自己:作为一名非科班的程序员,肯定比不上他们呀,如果随随便便的学了一点就能刷题顺利,那别人大学四年不白学了!
所以前期先接受自己的思考方式,暴力解法其实也是一种有效的解法。
2、没有合理的刷题我只是盲目的追求刷题的数量,即使刷了 200 道,脑中依旧一团浆糊。
后来才明白,吃透一道题目比乱刷十道题目更有价值。
经过不断的摸索与试验,形成了自己的一套刷题路径。
自己的解法网上好的解法自己的解法可以改进的地方不停的优化寻找相同的题型重复练习总结每一个题目都经过至少一遍这样的迭代,彻底吃透一道题进而掌握一种题型。
以一道极其简单的动态规划题为例 ,LeetCode 第 70 号问题:爬楼梯。
算法题到底咋做很多题根本找不到思路,每个题做完弄懂之后,下一次还是重写不出来,不知道啥算懂

当时的我根本不知道动态规划的相关概念,什么状态,什么转移方程,通通没听过。
没错,当时就那么菜!
二话不说,直接使用暴力解法。
class Solution { public int climbStairs(int n) { return calcWays(n); } private int calcWays( int n ){ if ( n == 1) return 1; if ( n == 2) return 2; return calcWays(n-1) + calcWays(n-2); }}很明显,无脑的递归暴力解法包含了大量的重复计算,提交上去直接标红提示超出时间限制。
后来看了网上高票答案的分析,知道了备忘录的概念,于是很容易写出优化后的代码。
//采用备忘录的方式来存子问题的解以避免大量的重复计算class Solution { int memo; ? public int climbStairs(int n) { ? memo = new int; ? return calcWays(n); ? } ? private int calcWays( int n ){ ? if ( n == 1) return 1; ? if ( n == 2) return 2; ? if (memo == 0) ? memo = calcWays(n-1) + calcWays(n-2); ? return memo; ? } }再后来,发现备忘录是自顶向下的方式,稍许变动,修改为自低向上的递推方式就是动态规划的形式。
class Solution { ? public int climbStairs(int n) { ? int memo = new int; ? memo = 1; ? memo = 1; ? for(int i = 2 ; i \u0026lt;= n; i++){ ? memo = memo + memo; ? } ? return memo; ? } }按照这样的刷题路径下来,发现对这类题型有了初步的思考途径,有了发力点,再也不会一筹莫展:看题懵逼半小时,Coding 只会按空格
彻底搞懂这题后,就需要找到类似的题型,然后不断的重复练习:最小路径和、整数拆分、完全平方数、解码方法、不同路径、不同路径 II。
通过这些练习,寻找题目中的共同点,为什么这类题型都可以这样思考呢?
慢慢的,知道了最优子结构、状态转移方程、重叠子问题的概念,不知不觉动态规划的知识点已经掌握了 80%。
再遇到更高难度的动态规划的题目时,心里也明白,一时半会没做成无法就是最优子结构、状态转移方程、重叠子问题没有理清楚。
这样长期坚持下来,接触新的题型时也可以从容不迫的思考。
作者:程序员吴师兄来源:https://zhuanlan.zhihu.com/p/137142974

■网友
以前我也对于算法题很苦恼,但是后来渐渐有些感觉了,后来完全没有疑惑了,因为不玩儿算法了。首先,把题目抽象成模型的能力是需要的。模型你可以理解为解决方案,抽象是人的主观意识里完成的,比如这道题,逆序数,我可以用归并排序,也可以用线段树前缀和。多涉猎一些常用或者好用的算法,如果题意符合这些算法的应用条件,比如,查找算法——想想看二分可不可以?直接用STL的set或者map可不可以?再比如大量插入和查询就马上联想到线段树和树状数组,观察题目给的数据量级,如果联想到的算法复杂度可以控制在时间复杂度之内,那自然是画个草图然后动手敲起来。然后是理解题意,为什么我会把理解题意放到抽象能力的下面,因为没有抽象能力和一定量的算法作为基础,是分析不出什么题意的……( ̄へ ̄)这两点真的是需要好好锻炼的,算法不是光敲代码这么简单的。好了,加油!


推荐阅读