回溯算法:回溯算法实质上是一种暴力算法,不过可以根据情况进行剪枝,所以比一般的暴力还是要优一些。解题步骤基本都是利用递归建立一颗解题树,树的节点即为答案,并根据题目要求把把明显不满足要求的枝丫剪去。利用回溯算法主要能解决一下几类问题:
组合问题:N个数里面按一定规则找出k个数的集合。
排列问题:N个数按一定规则全排列,有几种排列方式。
切割问题:一个字符串按一定规则有几种切割方式。
子集问题:一个N个数的集合里有多少符合条件的子集。
棋盘问题:N皇后,解数独等等。
贪心算法:
贪心算法实际没有具体做题套路,基本是遵从内心想法,每次解题寻求最优。要说贪心中哪一类问题相对比较好归纳出一般规律,那就是区间问题了。比如无重叠区间等。
动态规划:
动态规划基础:初步体验动态规划五部曲的解题方法(1、确定dp数组含义。2、归纳出递推公式。3、初始化dp数组开头元素。4、确定遍历顺序。5、验证。),需要能够从题目中总结出随着数字变化的一般规律。
背包问题:在动态规划基础上丰富了数组含义,依旧是靠动态规划五步曲解题,不过在这一部分笔者认为需要重点搞清楚内外for循环各遍历什么,且遍历顺序是怎样的(大部分情况是外层遍历物品,内层遍历背包容量,且容量要倒序遍历,防止一个物品被放入数组多次)。
打家劫舍:这类问题dp数组的下表就不是代表容量了,而是代表最多处理到这个位置,前面的那些位置要怎样处理才能使结果最优要看题目的安排(让你要间隔一个处理啊等等)。
股票系列:股票系列题目和打家劫舍类似,下标也是代表遍历到的位置。遍历顺序和打家劫舍一样,也是顺序遍历。打家劫舍类题目更像一种状态转换,每次赋值给dp数组元素某个状态时,都要考虑它可以由什么状态转换而来。
子序列问题:子序列问题要注意锚定到背包问题上来,外层for循环是什么,内层for循环是什么,各代表什么含义,尤其注意dp[i]代表的是以数组i元素结尾的字符串的最长递增子序列(注意这个字序列是以i结尾,一定要包含i)。且如果是求连续的子序列,那么当比较两个字符不相等时需要给dp赋0;如果是求非连续的子序列,dp数组需要使用二维(不然没法表示比较到迄今为止前面的最长公共子序列)。并且这类问题需要一个中间结果,每次求出子序列都要做比较把最大的子序列长度复制给这个中间变量,最后输出中间变量。而背包问题、打家劫舍、股票系列等问题则不需要中间结果,直接求出dp数组,最后输出dp[size-1]即可。
编辑距离:这一类问题其实可以归纳到子序列问题中,笔者认为是dp系列问题中最难理解透彻的一类问题。要搞清楚在哪两个范围的子字符串中通过何种操作可以得到中间结果。
单调栈:
单调栈,顾名思义,以单调递增或者单调递减的顺序将数组的元素存入栈内。目的是在计算出每个元素对应的结果前将元素暂时保存在栈中,将来满足了要计算条件的时候,再将元素从栈中push出来。因为数组是从前往后遍历的,所以栈中元素的下标一定会遵从从小到大的顺序。