LeetCode 第 122 题:买卖股票的最佳时机 II(动态规划、贪心算法)

地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
我写的题解地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/tan-xin-suan-fa-by-liweiwei1419-2/

方法一:动态规划

定义状态: dp[i][j]

说明:第一维 i 表示区间 [0, i](具有前缀性质,即考虑了之前天数的收益)能获得的最大利润;

第二维 j 表示索引位置为 i 的那一天我是持有股票,还是持有现金,这里 0 表示持有现金(cash),1 表示持有股票(stock)。

  • 状态转移方程:

状态从持有现金(cash)开始,到最后一天我们关心的状态也是持有现金(cash),因为股价是正数,最后一天买进一支股票,手上的现金肯定少了;
每一天状态可以转移,也可以不动。 可以用下图表示:

在这里插入图片描述
因此状态转移方程是:

dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
  • 初始化:起始的时候,不持有股票。如果什么都不做,dp[0][0] = 0,如果买入股票,当前收益是负数,即 dp[0][1] = -prices[i];

  • 输出: dp[len - 1][0]。因为不限制交易次数,也没有冷冻期,因此最后一天一定得把手上持有的股票卖掉,即一定有 dp[len - 1][0] > dp[len - 1][1]

Java 代码:

public class Solution {
    // 0:持有现金
    // 1:持有股票

    public int maxProfit(int[] prices) {
        int len = prices.length;
        if (len < 2) {
            return 0;
        }

        // 状态数组
        // 状态转移:cash → hold → cash → hold → cash → hold → cash
        // 状态转移:0 → 1 → 0 → 1 → 0 → 1 → 0
        int[][] dp = new int[len][2];

        dp[0][0] = 0;
        dp[0][1] = -prices[0];

        for (int i = 1; i < len; i++) {
            // 说明这两行调换顺序也是可以的
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
        }
        return dp[len - 1][0];
    }
}

还可以这样写:

Java 代码:

public class Solution {

    // cash:持有现金
    // hold:持有股票

    public int maxProfit(int[] prices) {
        int len = prices.length;
        if (len < 2) {
            return 0;
        }

        // 状态数组
        // 状态转移:cash → hold → cash → hold → cash → hold → cash
        int[] cash = new int[len];
        int[] hold = new int[len];

        cash[0] = 0;
        hold[0] = -prices[0];

        for (int i = 1; i < len; i++) {
            // 说明这两行调换顺序也是可以的
            cash[i] = Math.max(cash[i - 1], hold[i - 1] + prices[i]);
            hold[i] = Math.max(hold[i - 1], cash[i - 1] - prices[i]);
        }
        return cash[len - 1];
    }
}

状态压缩(如果是刚开始接触,可以跳过,我个人觉得不是很重要,重点理解状态转移)

Java 代码:

public class Solution {

    // cash:持有现金
    // hold:持有股票

    public int maxProfit(int[] prices) {
        int len = prices.length;
        if (len < 2) {
            return 0;
        }

        // 状态数组
        // 状态转移:cash → hold → cash → hold → cash → hold → cash

        int cash = 0;
        int hold = -prices[0];

        int preCash = cash;
        int preHold = hold;
        for (int i = 1; i < len; i++) {
            cash = Math.max(preCash, preHold + prices[i]);
            hold = Math.max(preHold, preCash - prices[i]);

            preCash = cash;
            preHold = hold;

        }
        return cash;
    }
}

方法二:贪心算法

贪心算法的证明见本文开始贴出的我的题解地址。

Java 代码:

public class Solution {

    public int maxProfit(int[] prices) {
        int res = 0;
        int len = prices.length;
        for (int i = 0; i < len - 1; i++) {
            int diff = prices[i + 1] - prices[i];
            if (diff > 0) {
                res += diff;
            }
        }
        return res;
    }
}
发布了442 篇原创文章 · 获赞 330 · 访问量 123万+

猜你喜欢

转载自blog.csdn.net/lw_power/article/details/103773246