买卖股票 | House Robber

Best Time to buy and sell stocks

参考labladong大神的帖子

买卖股票是一个系列问题,「状态」有三个,第一个是天数,第二个是允许交易的最大次数,第三个是当前的持有状态(即之前说的 rest 的状态,我们不妨用 1 表示持有,0 表示没有持有)。然后我们用一个三维数组就可以装下这几种状态的全部组合:

dp[i][k][0 or 1]
0 <= i <= n-1, 1 <= k <= K
n 为天数,大 K 为最多交易数
此问题共 n × K × 2 种状态,全部穷举就能搞定。

for 0 <= i < n:
    for 1 <= k <= K:
        for s in {0, 1}:
            dp[i][k][s] = max(buy, sell, rest)
  • dp[3][2][1] 的含义就是:今天是第三天,我现在手上持有着股票,至今最多进行 2 次交易。

  • dp[2][3][0] 的含义:今天是第二天,我现在手上没有持有股票,至今最多进行 3 次交易。

我们想求的最终答案是 dp[n - 1][K][0],即最后一天,最多允许 K 次交易,最多获得多少利润。读者可能问为什么不是 dp[n - 1][K][1]?因为 [1] 代表手上还持有股票,[0] 表示手上的股票已经卖出去了,很显然后者得到的利润一定大于前者。

二、状态转移框架

现在,我们完成了「状态」的穷举,我们开始思考每种「状态」有哪些「选择」,应该如何更新「状态」。只看「持有状态」,可以画个状态转移图。

Best Time to Buy and Sell Stock IV

  • at most K transaction

  • 最general的股票买卖题目

  • f[i][k][0 or 1] represents max profit after day i and making at most K transaction with state j, j can be 0 or 1, 1 means hold

Best Time to Buy and Sell Stock III

  • K=2的情况,套用IV模板就好

Best Time to Buy and Sell Stock I

  • At most one transaction, 即K = 1的情况

  • f[i][0] = max(f[i-1][0], f[i-1][1] + prices[i])

  • f[i][1] = max(f[i-1][1], - prices[i]) //注意,不是max(f[i-1][1], f[i-1][0] - prices[i])

Best Time to Buy and Sell Stock II

  • K= infinite的情况

  • 这题可以用Greedy贪心来做

  • whenever prices[i] - prices[i - 1] >0, then add to profit

  • 带冷却时间的情况

  • K = Infinite

  • 带交易费的情况

  • K = Infinite

House Robber

  • 相邻两家不能同时抢

House Robber II

  • 收尾相连

  • 所以针对收尾的两个房子有3种情况

    • both nums[0] and nums[n - 1] not rob

    • rob nums[0] only, not nums[n - 1]

    • rob nums[n - 1] only, not nums[0]

  • 不用考虑第1种情况,因为结果可以被2,3 cover

  • 可以转化为区间型 DP -> rob(int[] nums, int begin, int end)

House Robber III

  • 抢劫的路径改为binary tree

  • 这个反而更简单了,divide & conquer返回resultType

  • Tree DFS traverse不需要memo, 因为没有重复计算可以优化

Last updated

Was this helpful?