一、股票问题(*)
188.
买卖股票的最佳时机 IV
给定一个整数数组 prices ,它的第 i 个元素 prices[i]
是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
labuladong算法秘籍中使用了【三个状态】(三维dp数组)
- 第几天
- 手中是否持有股票
- 最大交易限制(最大交易限制只在买入股票时减一)
状态转移方程
1 2 3 4 5 6 7 8
| dp[i][0][k] = Math.max( dp[i-1][0][k], dp[i-1][1][k]+prices[i-1] ); dp[i][1][k] = Math.max( dp[i-1][1][k], dp[i-1][0][k-1]-prices[i-1] );
|
base case
1 2
| dp[0][0][...] = 0; dp[0][1][...] = Integer.MIN_VALUE; dp[...][0][0] = 0; dp[...][1][0] = Integer.MIN_VALUE;
|
二、打劫家舍问题
198.打劫家舍
213. 打家劫舍
II
337.
打家劫舍 III
1、打劫家舍
【状态】是 抢劫第i家时能获得的最大金额
1 2
| dp[i] = Math.max(dp[i-2], dp[i-3]) + nums[i];
|
2、打劫家舍Ⅱ
特别之处在于 nums 换成了环形数组
应对策略也十分巧妙
\(f([x_{1}, x_{2}, ... , x_{n}]) = max(
f([x_{1}, x_{2}, ..., x_{n-1}]), f([x_{2}, ..., x_{n}]) )\)
既然首尾相连了,那么肯定最多只能抢劫一家,把另外一家除去,就把环形数组又变成了普通数组了。
3、打劫家舍Ⅲ
把家舍的形状变成了二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public int rob(TreeNode root) { int[] res = dp(root); return Math.max(res[0], res[1]); }
private int[] dp(TreeNode root){ if(root == null) return new int[]{0, 0}; int[] left = dp(root.left); int[] right = dp(root.right); int x = left[1] + right[1] + root.val; int y = Math.max(left[1], left[0]) + Math.max(right[1], right[0]); return new int[]{x, y}; } }
|
三、博弈问题
486.
预测赢家
最核心最关键的还是在【找状态】,理解!!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
dp[i][j][0] = Math.max(nums[i]+dp[i+1][j][1], nums[j]+dp[i][j-1][1]);
if 先手选择了i: dp[i][j][1] = dp[i+1][j][0]; if 先手选择了j: dp[i][j][1] = dp[i][j-1][0];
dp[i][j] = Math.max(nums[i] - dp[i+1][j], nums[j] - dp[i][j-1]);
|
四、扔鸡蛋(***)
887.鸡蛋掉落
这道题理解上难度很高...
image-20221104212852347
这里讲一个逆向思维。
1
| dp[i][j] 表示有j个鸡蛋,可以操作i次,可以在最高dp[i][j]的建筑里保证找到f
|
比如dp[2][1]=2
,表示有1个鸡蛋,可以操作2次,可以在最高2楼的建筑里保证找到f
。意思就是如果楼>=
3,就不能保证在1个鸡蛋2次操作的情况下找到f。这里的保证是指不管在什么情况下都可以成功找到f,而不是说有一定概率可以找到。很好理解,不管多高的楼层,即使给1个鸡蛋1次操作,也有一定概率可以找到f(第1层就碎了,所以f=0
)
理解完状态之后,就需要找到状态转移方程。先给出来
1
| dp[i][j] = 1 + dp[i-1][j-1] + dp[i][j-1];
|
这里应该是这道题最难理解的地方。