股票买卖问题总结

总结股票买卖问题,所有case都化简为DP处理。

通解

i 代表 ith day
k 代表最大交易次数
0/1 代表手中是否持有股票

T【i】【k】【0】 代表 在ith day 最多k次交易,ith day结束后不持有股票的 profit
T【i】【k】【1】 代表 在ith day 最多k次交易,ith day结束后持有股票的 profit

那么base case
T【-1】【k】【0】 = 0 (1)
T【-1】【k】【1】 = -INF (2)
T【i】【0】【0】 = 0 (3)
T【i】【0】【1】= -INF (4)
递推关系
T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k-1】【0】- prices【i】)#买入

(只有买入操作消耗交易次数)

应用

K=1

T【i】【1】【0】=max(T【i-1】【1】【0】,T【i-1】【1】【1】+prices【i】)
T【i】【1】【1】=max(T【i-1】【1】【1】,T【i-1】【0】【0】-prices【i】)
因为(3)
所以
T【i】【1】【0】=max(T【i-1】【1】【0】,T【i-1】【1】【1】+prices【i】)
T【i】【1】【1】=max(T【i-1】【1】【1】,-prices【i】)

public int maxProfit(int[] prices) {
    int T_i10 = 0, T_i11 = Integer.MIN_VALUE;
        
    for (int price : prices) {
        T_i10 = Math.max(T_i10, T_i11 + price);
        T_i11 = Math.max(T_i11, -price);
    }
        
    return T_i10;
}

K=INF

K无穷大时候,K和K-1 没区别
T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k-1】【0】- prices【i】)#买入
变成
T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k】【0】- prices【i】)#买入

public int maxProfit(int[] prices) {
    int T_ik0 = 0, T_ik1 = Integer.MIN_VALUE;
    
    for (int price : prices) {
        int T_ik0_old = T_ik0;
        T_ik0 = Math.max(T_ik0, T_ik1 + price);
        T_ik1 = Math.max(T_ik1, T_ik0_old - price);
    }
    
    return T_ik0;
}

K=2

T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k-1】【0】- prices【i】)#买入
变成
T【i】【2】【0】 = max(T【i-1】【2】【0】,T【i-1】【2】【1】+prices【i】)
T【i】【2】【1】 = max(T【i-1】【2】【1】,T【i-1】【1】【0】- prices【i】)
T【i】【1】【0】 = max(T【i-1】【1】【0】,T【i-1】【1】【1】+prices【i】)
T【i】【1】【1】 = max(T【i-1】【1】【1】,- prices【i】)

public int maxProfit(int[] prices) {
    int T_i10 = 0, T_i11 = Integer.MIN_VALUE, T_i20 = 0, T_i21 = Integer.MIN_VALUE;
        
    for (int price : prices) {
        T_i20 = Math.max(T_i20, T_i21 + price);
        T_i21 = Math.max(T_i21, T_i10 - price);
        T_i10 = Math.max(T_i10, T_i11 + price);
        T_i11 = Math.max(T_i11, -price);
    }
        
    return T_i20;
}

K 是任何数

T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k-1】【0】- prices【i】)#买入

public int maxProfit(int k, int[] prices) {
    //如果K 大于等于Prices长度的一半,那么相当于K=INF的情况
    if (k >= prices.length >>> 1) {
        int T_ik0 = 0, T_ik1 = Integer.MIN_VALUE;
    
        for (int price : prices) {
            int T_ik0_old = T_ik0;
            T_ik0 = Math.max(T_ik0, T_ik1 + price);
            T_ik1 = Math.max(T_ik1, T_ik0_old - price);
        }
    
        return T_ik0;
    }
        
    int[] T_ik0 = new int[k + 1];
    int[] T_ik1 = new int[k + 1];
    Arrays.fill(T_ik1, Integer.MIN_VALUE);
        
    for (int price : prices) {
        for (int j = k; j > 0; j--) {
            T_ik0[j] = Math.max(T_ik0[j], T_ik1[j] + price);
            T_ik1[j] = Math.max(T_ik1[j], T_ik0[j - 1] - price);
        }
    }
        
    return T_ik0[k];
}

K=INF with Cooldown

T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k-1】【0】- prices【i】)#买入
当K=INF变为
T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k】【0】- prices【i】)#买入
但是有cooldown时候,变为
T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-2】【k】【0】- prices【i】)#买入
因为不能在i天买入如果股票是在i-1天卖出的,所以只能用T【i-2】【k】【0】

public int maxProfit(int[] prices) {
    int T_ik0_pre = 0, T_ik0 = 0, T_ik1 = Integer.MIN_VALUE;
    
    for (int price : prices) {
        int T_ik0_old = T_ik0;
        T_ik0 = Math.max(T_ik0, T_ik1 + price);
        T_ik1 = Math.max(T_ik1, T_ik0_pre - price);
        T_ik0_pre = T_ik0_old;
    }
    
    return T_ik0;
}

K=INF with Transaction Fee

T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k-1】【0】- prices【i】)#买入
当K=INF变为
T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k】【0】- prices【i】)#买入
但是有Fee时候,变为因为fee只在卖出时候付清
T【i】【k】【0】 = max(T【i-1】【k】【0】,T【i-1】【k】【1】+prices【i】-fee) #卖出
T【i】【k】【1】 = max(T【i-1】【k】【1】,T【i-1】【k】【0】- prices【i】)#买入

public int maxProfit(int[] prices, int fee) {
    long T_ik0 = 0, T_ik1 = Integer.MIN_VALUE;
    
    for (int price : prices) {
        long T_ik0_old = T_ik0;
        T_ik0 = Math.max(T_ik0, T_ik1 + price - fee);
        T_ik1 = Math.max(T_ik1, T_ik0_old - price);
    }
        
    return (int)T_ik0;
}