代码随想录-2023/08/17

75 阅读2分钟

买卖股票问题

123.买卖股票的最佳时机III

解题思路:

  1. 本题最多可以买卖两次, 但是最多只能同时持有一个
  2. 定义四个状态: 第一次持有 | 第一次未持有 | 第二次持有 | 第二次未持有
  3. 根据定义的状态推导出递推公式

代码:

class Solution {
    // 最多买卖两次, 但是不能同时持有多个
    public int maxProfit(int[] prices) {
        // dp: 第一次持有股票的状态 | 第一次未持有的状态 | 第二次持有股票的状态 | 第二次未持有的状态
        int n = prices.length;
        int[][] dp = new int[n][4];
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = -prices[0];
        dp[0][3] = 0;
        for(int i=1; i<n; i++){
            // 第一次持有
            dp[i][0] = Math.max(0 - prices[i], dp[i-1][0]);
            // 第一次未持有
            dp[i][1] = Math.max(dp[i-1][0] + prices[i], dp[i-1][1]);
            // 第二次持有
            dp[i][2] = Math.max(dp[i-1][1] - prices[i], dp[i-1][2]);
            // 第二次未持有
            dp[i][3] = Math.max(dp[i-1][2] + prices[i], dp[i-1][3]);
        }

        return dp[n-1][3];

    }
}

188.买卖股票的最佳时机啊IV

解题思路:

  1. 动态规划 --- 和上题一样, 不过本题是至多交易k
  2. 定义dp数组: 有2*k个状态
  3. 注意需要初始化, 和递推的时候, 第一次买入的时候一定是Math.max(-prices[i], dp[i-1][0]);
  4. 根据dp数组定义推导出递推公式即可

代码:

class Solution {
    // 最多买卖k次, 但是同时最多只能持有一只股票
    public int maxProfit(int k, int[] prices) {
        int n = prices.length;
        int[][] dp = new int[n][2*k];
        // 初始化
        for(int i=0; i < 2*k; i++){
            dp[0][i] = i % 2 == 0?-prices[0]:0;
        }

        for(int i=1; i < n; i++){
            for(int j=0; j < 2*k; j++){
                if(j == 0) dp[i][j] = Math.max(-prices[i], dp[i-1][0]);
                else {
                    dp[i][j] = j % 2 == 0?Math.max(dp[i-1][j-1]-prices[i], dp[i-1][j]):Math.max(dp[i-1][j-1] + prices[i], dp[i-1][j]);
                }
            }
        }

        return dp[n-1][2*k-1];
    }
}