力扣-dp基础问题思维构建
1.198. 打家劫舍,很经典了。
2.213. 打家劫舍 II,可转化为198题。
3.典型连续子数组问题:(之后单独拎出来?区别于子序列问题)
3.1 53. 最大子序和,dp[i]表示以nums[i]为结尾的连续子数组的最大和,可用滚动数组优化。
4.72. 编辑距离,非常经典了,其实就是[i-1][j] [i][j-1] [i-1][j-1],其中-1地都表示原来的i或j被匹配上了。
5.背包问题专题
5.1 416. 分割等和子集,转换为0-1背包问题,dp[i][j]表示前i个物品能否组和为和刚好为j的子集,如果可以就为true;那么在选择时如果nums[i]比背包重量j大的话,就不能放进来,如果小的话,就可以选择放或者不放。
5.2 474. 一和零,给定m个0和n个1,求最多包含的字符串数目,相当于两个背包,状态算上物品共是三维,经过空间优化,转换为两个背包的二维状态,但由于是0-1背包问题需要从大到小更新。
5.3 494. 目标和,可以用dfs+记忆数组来做,也可用0-1背包来做,选择有两种+或-,这里有一点特殊的是,和可能为负值,但是数组下标不能为负,所以就+和的长度来平移一下下标,学到了。挺难的还。
5.4 322. 零钱兑换,完全背包问题,状态中不考虑物品了,只考虑重量,dp[i]=min(dp[i],dp[i-coins[j]]),一般都是当前背包重量减去物品重量求个最小值。挺难的。
5.5 518. 零钱兑换 II,完全背包问题,求解组合数,需要先遍历物品,dp[i][j] = dp[i - 1][j] + (j >= coins[i - 1] ? dp[i][j - coins[i - 1]] : 0),i是枚举硬币,到当前容量j的时候,结果包括:不包含当前硬币时组成j的数目+包含当前硬币i时组成j的数目,可以优化为一维的dp[j]+=dp[j-c]。
5.6 70. 爬楼梯,完全背包问题,求解排列数,需要遍历容量,考虑物品的排列,所有结果,不是固定的,也就是排列数。
5.7 377. 组合总和 Ⅳ,完全背包问题,求组合数,结果可以重复,所以是对物品的排列,需要先遍历容量,再遍历物品。
6.279. 完全平方数,状态转移方程为dp[i]=1+min(dp[i-j^2]),其中j*j<=i,很牛的状态转移方程。
7.剑指 Offer 60. n个骰子的点数,dp[i]表示和为i的结果次数, 遍历每个骰子,遍历容量,状态转移方程:针对第j个骰子,dp[i]=Σk1-6 dp[i-k]。
回文子序列:
516. 最长回文子序列,dp[i,j]表示s[i:j]之间(闭区间)的最长回文子序列长度,从中间向外扩展。
字符串:
1. 139. 单词拆分,拆分为子问题,部分串是否能由字典组成,dp[i]表示前i个字符能否由字典组成,计算时又将前i个按j的位置拆分,dp[0]表示空串可以组成。
记忆化搜索:
2.140. 单词拆分 II,用哈希表存储从当前index拆分的所有结果,再遍历时如果有已处理过的,就返回。自顶向下处理,然后回溯。挺难的。
3. 上述139题也可用记忆化搜索完成,dp是将大问题拆分为子问题,最终返回的结果是dp[n],前n个字符是否能按字典拆分,自底向上;记忆化搜索memo[i]记录下标,表示是否拆分过,如果拆分过保存结果之后访问直接返回,做剪枝操作,最后返回memo[0],自顶向下。