从最开始找不到如何做算法题的门路,面对算法题一筹莫展,到现在二刷完结看题基本都知道怎么回事有思路了,感谢卡哥带我入门,学一样东西往往入门是颇具难度的,入门之后才是个人努力闪光的时候。
之后我打算刷一下卡哥新更新的图论,然后做一做hot100在不知道题目类型的情况下练习。
1、维持好循环不变量。
2、搜索结果如果是单点,结果由mid=target得出;搜索结果如果是区间范围或者是单区间(如求平方根只要整数向下取整即为单区间)这种要一个区间边界一个搜索,分开搜索,写到一块容易出错误。
双指法的使用比较灵活,有单向的快慢双指针,也有双向指针法,也有两个指针指向相邻元素,此外还有灵活的使用全局变量记录要移动的位置。
滑动窗口即为,不断移动窗口的起始位置和结束位置,直到得到我们想要的结果。
最典型的就是两层for循环,外层控制起始位置,内层控制结束位置。只不过滑动窗口是一层for循环控制结束位置,满足目标条件后,再移动起始位置,直至不再满足条件,然后再移动借宿位置。
注意使用虚拟头结点。对于判断有环无环,可以用快慢指针,一个走两步一个走一步,能相交即为有环,然后一个从头结点出发一个从相交点出发,再次相交时即为环的入口。
什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。数组、set (集合)、map(映射)
两数之和、三数之和、四数之和,主要set、map、双指针的使用,三数之和、四数之和的去重、剪枝。
注意翻转、双指针、KMP。
栈: 栈在系统中的应用、括号匹配问题、字符串去重问题、逆波兰表达式问题
队列:滑动窗口最大值问题、求前 K 个高频元素
卡哥总结、注意大顶堆和小顶堆,优先级队列java中是PriorityQueue。
求普通二叉树的最近公共祖先用后序遍历,求二叉搜索树的最近公共祖先直接从上向下搜索,搜索两个节点构成的区间,第一个在区间内的节点即为最近公共祖先。
递归何时需要返回值:
再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
组合、分割、子集、排列、棋盘、其他
组合问题:
元素可以重复使用index无需加1,元素不可以重复使用需要从下一个位置开始index+1。
如果组合数是固定个数的可以剪枝,for循环的次数小于n了就停止。
对于数组中有重复数字,但是要求结果集不能重复,需要树层去重。
分割问题:注意操作字符串的边界问题。
子集问题:
如果收集所有节点,即叶子结点和非叶子节点。
求递增子序列,如3,7,6,7 。由于不能排序树层去重,就无法使用used数组或者i > index && nums[i]== nums[i-1],因为相同的数并不挨着。又得解决树层中相同的数不能重复使用,就可以在树层间使用set数组,每递归进入下一层就是一个新数组。
求全排列,由于排列讲究顺序,如1,2,3排列结果会有2,1,3。这样就不能指定for循环的开始位置为当前数的下一个,而是固定从0开始,但是需要使用一个数组记录下来哪些使用过滤哪些没有使用,要纵向记录,因为纵向不能重复使用数字,递归标记,回溯后就没有标记,只影响纵向收集。
对于有重复数字的全排列,纵向横向都要去重,for从0开始,避免纵向重复使用used数组记录,为true为使用过,为false为没使用过,即used[i]=true跳过,横向去重需要数组排序,当nums[i]=nums[i-1]时,used[i-1]=false是回溯完的,需要树层去重。
注意区间问题。
分为:背包问题、打家劫舍、股票问题、子序列问题
背包问题:一维数组,dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i])。
01背包遍历顺序:先物品后背包,物品正序,背包逆序。
如若背包正序则会出现同一个物品重复放入,如物品1重量为1,背包空间为1时放入了,背包空间为2时又放入了。
如果先背包后物品,为了避免重复放入背包依然是逆序,背包容量固定时,每种背包容量只能放入一个物品,即为最大的物品,小的物品都放不进来或者被覆盖了。
求组合数排列数:dp[j] += dp[j - nums[i]]
完全背包遍历顺序:物品背包没有先后顺序,物品背包都是正序。因为同一个物品不限量可以放入多次,在背包采用正序中。
完全背包求组合数,物品在外,背包在内。求排列数,背包在外,物品在内。
股票问题:每天是有两种状态的,持有或者不持有。
定义时都要这么定义,也可以简化为dp[0],dp[1]。
定义dp[i][0]表示第i天持有股票手中金额的最大值,dp[i][1]表示第i天不持有股票手中金额的最大值。
注意,这里的持有可以是之前持有的,也可以是当天才持有的,不持有可以是之前就没持有过,也可以说当前才卖出变成了没持有。
下面是一个每天都可以买卖的例子。
dp[0] = Math.max(dp[0], dp[1] - prices[i]);
dp[1] = Math.max(dp[1], dp[0] + prices[i]);
最后就是子序列问题,最长递增子序列、最长连续递增子序列,最长连续子数组,最长重复子序列
一般是求左边或者右边第一个最大的元素时使用。
有两个经典的问题:接雨水和矩阵面积。解题思路(2,1,3)和(1,2,3)