买卖股票

Best Time to Buy and Sell Stock II

先说买卖股票II,这题没有交易次数的限制条件
我们定义两个dp数组, hold[n]unhold[n]

  • hold[i] - the maximum profit I can have ends at ith day
  • unhold[i] - maximum profit I can have ends at ith day

初始化

  • hold[0] = -prices[0] - 第一天买入profit是-prices[0]
  • unhold[0] = 0 - 第一天不买,profit是0

结果 - unhold[n - 1] - unhold[n - 1]一定大于hold[n - 1]

class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        int n = prices.length;
        int[] hold = new int[n];
        int[] unhold = new int[n];
        hold[0] = -prices[0];
        unhold[0] = 0;
        for (int i = 1; i < n; i++) {
            hold[i] = Math.max(hold[i - 1], unhold[i - 1] - prices[i]);
            unhold[i] = Math.max(unhold[i - 1], hold[i - 1] + prices[i]);
        }
        return unhold[n - 1];
    }
}

Best Time to Buy and Sell Stock

买卖股票I是在买卖股票二上加入了限制条件,即最多只能有一次交易
我们稍微的对hold[n]的转移方程做出修改即可 - hold[i] - Math.max(unhold[i - 1], -prices[i])
因为只能买一次,所以如果一定要在第ith day买入,那这种情况下unhold[i]就是-prices[i]

class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        int n = prices.length;
        int[] hold = new int[n];
        int[] unhold = new int[n];
        hold[0] = -prices[0];
        unhold[0] = 0;
        for (int i = 1; i < n; i++) {
            hold[i] = Math.max(hold[i - 1], -prices[i]);
            unhold[i] = Math.max(unhold[i - 1], hold[i - 1] + prices[i]);
        }
        return unhold[n - 1];
    }
}

Best Time to Buy and Sell Stock IV

买卖股票IV限制了最多k次的交易次数
我们的dp数字要加上第二个维度,即交易次数

  • 定义hold[n][k + 1] - hold[i][j] - the maximum profit I can have when I hold the stock at ith day with at most j times transaction
  • 定义unhold[n][k + 1] - unhold[i][j] - the maximum profit I can have when I unhold the stock at ith day with at most j times transaction

初始化
unhold[0][1...k] = 0 - 对于第1天(index = 0),我不持有股票,我的maximum profit是0
unhold[0][1...k] = -prices[0] - 对于第1天(index = 0),我持有股票,我的maximum profit是-prices[0]

结果
unhold[n - 1][k]

最后我们额外的处理一种特出情况,就是当k的值大于prices.length / 2时,这题就被转换到了买卖股票II的问题

class Solution {
    public int maxProfit(int k, int[] prices) {
        if (prices == null || prices.length <= 1) {
            return 0;
        }
        
        if (k > prices.length / 2) {
            int profit = 0;
            for (int i = 1; i < prices.length; i++) {
                profit += Math.max(0, prices[i] - prices[i - 1]);
            }
            return profit;
        }
        
        int n = prices.length;
        int[][] hold = new int[n][k + 1]; // hold[i][j] - the maximum profit i can make when i make at most j times of transactions at ith day with stock in hand
        int[][] unhold = new int[n][k + 1]; // unhold[i][j] - hold[i][j] - the maximum profit i can make when i make at most j times of transactions at ith day without stock in hand
        
        for (int j = 1; j <= k; j++) {
            hold[0][j] = -prices[0];
            unhold[0][j] = 0;
            for (int i = 1; i < n; i++) {
                hold[i][j] = Math.max(hold[i - 1][j], unhold[i - 1][j - 1] - prices[i]);
                unhold[i][j] = Math.max(unhold[i - 1][j], hold[i - 1][j] + prices[i]);
            }
        }
        return unhold[n - 1][k];
    }
}

Best Time to Buy and Sell Stock III

买卖股票III问的是最多的交易次数是2的时候,最大profit是多少。把买卖股票IV里的k替换成2即可。

class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length <= 1) {
            return 0;
        }
        int n = prices.length;
        int[][] hold = new int[n][3];
        int[][] unhold = new int[n][3];
        
        for (int j = 1; j <= 2; j++) {
            hold[0][j] = -prices[0];
            unhold[0][j] = 0;
            for (int i = 1; i < n; i++) {
                hold[i][j] = Math.max(hold[i - 1][j], unhold[i - 1][j - 1] - prices[i]);
                unhold[i][j] = Math.max(unhold[i - 1][j], hold[i - 1][j] + prices[i]);
            }
        }
        
        return unhold[n - 1][2];
    }
}

Best Time to Buy and Sell Stock with Transaction Fee

这题是买卖股票且每次交易要收手续费,但不限制交易次数。把买卖股票II的转移方程稍作修改
在买卖股票II中,hold[n]的
转移方程是 - hold[i] = Math.max(hold[i - 1], unhold[i - 1] - prices[i])
初始化是 - hold[0] = -prices[0]

而这题hold[n]
转移方程是 - hold[i] = Math.max(hold[i - 1], unhold[i - 1] - prices[i] - fee);
初始化是 - hold[0] = -prices[0] - fee

class Solution {
    public int maxProfit(int[] prices, int fee) {
        if (prices == null || prices.length <= 1) {
            return 0;
        }
        int n = prices.length;
        int[] hold = new int[n];
        int[] unhold = new int[n];
        hold[0] = -prices[0] - fee;
        unhold[0] = 0;
        
        for (int i = 1; i < n; i++) {
            hold[i] = Math.max(hold[i - 1], unhold[i - 1] - prices[i] - fee);
            unhold[i] = Math.max(unhold[i - 1], hold[i - 1] + prices[i]);
        }
        return unhold[n - 1];
    }
}

Best Time to Buy and Sell Stock with Cooldown

这题要求如果你卖出了股票,那卖出股票的后一天,你不能进行买入操作,你只能休息一天。
这题我们定义三种状态

  • buy[i] - before or at ith day, the maximum profit I can have if the last action is buy
  • sell[i] - before or at ith day, the maximum profit I can have if the last action is sell
  • rest[i] - before or at ith day, the maximum profit I can have if the last action is rest

转移方程
buy[i] = max(buy[i - 1], rest[i - 1] - prices[i])
sell[i] = max(sell[i - 1], buy[i - 1] + prices[i])
rest[i] = max(rest[i - 1], buy[i - 1], sell[i - 1])

初始化

  • buy[0] = -prices[0]
  • sell[0] = Integer.MIN_VALUE // 这种情况不可能发生,第1天(index 0)上,不能发生sell action,用Integer.MIN_VALUE来表示这种状态
  • rest[0] = 0

结果
max(rest[n - 1], sell[n - 1])

class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length <= 1) {
            return 0;
        }
        int n = prices.length;
        int[] buy = new int[n]; // buy[i] - before or at ith day, the maximum profit you can have when the last action is buy
        int[] sell = new int[n]; // hold[i] - before or at ith day, the maximum profit you can have when the last action is sell
        int[] rest = new int[n]; // rest[i] - before or at ith day, the maximum profit you can have when the last action is rest
        buy[0] = -prices[0];
        sell[0] = Integer.MIN_VALUE;
        rest[0] = 0;    
        
        for (int i = 1; i < n; i++) {
            buy[i] = Math.max(buy[i - 1], rest[i - 1] - prices[i]);
            sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]);
            rest[i] = Math.max(rest[i - 1], Math.max(buy[i - 1], sell[i - 1]));
        }
        return Math.max(rest[n - 1], sell[n - 1]);
    }
}

你可能感兴趣的:(买卖股票)