Vue-Croppa插件开发:如何扩展自定义裁剪功能
2026/7/5 18:01:56
不涉及题目讲解,只介绍题目中容易踩的坑!!!dp[j][0]和dp[j][1]的更新顺序为什么没要求?最多 k 次交易的股票 DP 不需要对 k倒序遍历?代码中 DP 的含义是:
dp[j][0]:在「最多 j 次交易」的限制下,不持股的最大利润 dp[j][1]:在「最多 j 次交易」的限制下,持股的最大利润⚠️ 关键在于这四个字:
最多 j 次交易
而不是「已经完成 j 次交易」。
这是后面所有结论的根源。
每天价格为price,转移方程是:
dp[j][1]=max(dp[j-1][0]-price,# 今天买入dp[j][1]# 之前就持有)dp[j][0]=max(dp[j][1]+price,# 今天卖出dp[j][0]# 之前就不持有)这里有两个看起来“危险”的点:
dp[j][1]用到了dp[j-1][0]dp[j][0]又用到了本轮更新后的dp[j][1]按很多 DP 的经验,这似乎会导致状态污染。
但实际上不会。
dp[j][1]被dp[j][0]使用,安全吗?假设dp[j][1]是刚更新的:
dp[j][1]=dp[j-1][0]-price那么dp[j][0]中的这一项就是:
dp[j][1]+price=(dp[j-1][0]-price)+price=dp[j-1][0]这意味着什么?
👉同一天买入 + 同一天卖出 = 什么都没做
所以即便用了本轮的dp[j][1],也只是一个无效操作,不会破坏结果。
这是最重要的一点。
那么:
dp[j]一定严格依赖dp[j-1]这就和 0/1 背包是完全一致的。
这意味着:
dp[j] ≥ dp[j-1]👉 不存在“交易次数被重复消费”的问题。
假设我们正序遍历:
j = 1 → 2 → 3当我们计算dp[2]时:
用到的dp[1]表示的是:
用这个状态再买一次:
而不是:
如果我们把定义改成:
dp[j][0]:已经完成 j 次交易,不持股 dp[j][1]:已经完成 j 次交易,持股那么转移会变成:
dp[j][1]=max(dp[j][1],dp[j][0]-price)dp[j][0]=max(dp[j][0],dp[j][1]+price)此时:
dp[j]依赖dp[j]👉 是否倒序,完全取决于 j 的语义,而不是题目是不是“股票”。
是否需要对 k 倒序遍历,关键不在于 DP 的形式,
而在于 j 表示什么。
| j 的含义 | 是否需要倒序 |
|---|---|
| 已经用掉 j 次交易 | ✅ 必须倒序 |
| 最多允许 j 次交易 | ❌ 可以正序 |
再补一句非常重要的经验:
在「最多 k 次交易」的股票 DP 中,
即便同一天发生“买入 → 卖出”,
也只会产生 0 利润,不会破坏状态。