【leetCode-DP】买卖股票的最佳时机(1-4)

参考:传送门

定义通用状态dp[i][j][k] 数组,含义dp[第一天...第N天的股票价格 ][限制交易次数][ 0未持有股票;1持有股票 ]

通用状态转移方程:

dp[i][j][0] = Math.max(dp[i - 1][ j ][0], dp[i - 1][ j ][1] + prices[i] );
dp[i][j][1] = Math.max(dp[i - 1][ j ][1], dp[i - 1][ j-1 ][0] - prices[i] );

初始化:根据不同题目进行调整

 

买股票最佳时机I(点击题目进入原题)

此题目没有交易次数的限制

    public int maxProfit(int[] prices) {
        int len = prices.length;
        if(len ==0 || len == 1) {
            return 0;
        }
        int[][] dp = new int[ len + 2 ][4]; //dp[i][j] 表示第i天股票状态为( 1持有股票、0 没有股票 )的尽量多次数
        for (int i = 0; i < len; i++) {
            if (i == 0) {
                dp[i][0] = 0;
                dp[i][1] = - prices[i];
                continue;
            }else if(i == 1){
                dp[1][0] = Math.max(dp[0][0],dp[0][1]+prices[i]);
                dp[1][1] = Math.max(dp[0][1], - prices[i]);
                continue;
            }

            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 - 2][0] - prices[i]);
        }
        return dp[len-1][0];
    }

买卖股票的最佳时机含手续费(点击题目进入原题)

    public int maxProfit(int[] prices, int fee) {
        int len = prices.length;
        if(len ==0 ) {
            return 0;
        }
        int[][] dp = new int[ len + 2 ][4]; //dp[i][j] 表示第i天股票状态为( 1持有股票、0 没有股票 )的最大利润
        for (int i = 0; i < len; i++) {
            if (i == 0) {
                dp[i][0] = 0;
                dp[i][1] = - prices[i] ;
                continue;
            }
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee);
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
        }
        return dp[len-1][0];
    }

买卖股票的最佳时机 III(点击题目进入原题)

public int maxProfit(int[] prices) {
        int len = prices.length;
        if(len == 0 ) {
            return 0;
        }
        int[][][] dp = new int[ len + 2 ][4][2]; // dp[i][j][k] 表示第i天股票进行j笔交易(最多两笔)并且状态为k(0无持有 1持有)的最大利润

        for (int i = 0; i < len; i++) {
            for (int j = 1; j <= 2; j++) {
                if(i == 0 && j == 1) {
                    dp[i][j][0] = 0;
                    dp[i][j][1] = -prices[i];
                    continue;
                }else if(i == 0 && j == 2) {
                    dp[i][j][0] = 0;
                    dp[i][j][1] = -999999;
                    continue;
                }
                dp[i][j][0] = Math.max(dp[i - 1][ j ][0], dp[i - 1][ j ][1] + prices[i] );
                dp[i][j][1] = Math.max(dp[i - 1][ j ][1], dp[i - 1][ j-1 ][0] - prices[i] );
            }
        }
        return Math.max(dp[len-1][1][0],dp[len-1][2][0]);
    }

买卖股票的最佳时机 IV(点击题目进入原题)

一开始提交下面代码的时候,报超出内存的错误

public int maxProfit(int k, int[] prices) {
        int len = prices.length;
        if(len == 0 ) {
            return 0;
        }
        int[][][] dp = new int[ len + 2 ][k+2][2]; // dp[i][j] 表示第i天股票进行j笔交易(最多两笔)并且状态为(0无持有 1持有)的最大利润
        for (int i = 0; i < len; i++) {
            for (int j = 1; j <= k; j++) {
                if(i == 0 && j == 1) {
                    dp[i][j][0] = 0;
                    dp[i][j][1] = -prices[i];
                    continue;
                }else if(i == 0 && j == 2) {
                    dp[i][j][0] = 0;
                    dp[i][j][1] = -999999;
                    continue;
                } else if(i == 0){
                    dp[i][j][0] = 0;
                    dp[i][j][1] = -999999;
                    continue;
                }
                dp[i][j][0] = Math.max(dp[i - 1][ j ][0], dp[i - 1][ j ][1] + prices[i] );
                dp[i][j][1] = Math.max(dp[i - 1][ j ][1], dp[i - 1][ j-1 ][0] - prices[i] );
            }
        }
        int max = 0;
        for(int i = 1;i <= k;i++){
            max = Math.max(max,dp[len-1][i][0]);
        }
        return max;
    }

优化

滚动数组优化空间,变成二维

int[][] dp = new int[k+2][2]; // dp[i][j] 表示进行j笔交易(最多两笔)并且状态为k(0无持有 1持有)的最大利润
        for (int i = 0; i < len; i++) {
            for (int j = 1; j <= k; j++) {
                if(i == 0 && j == 1) {
                    dp[j][0] = 0;
                    dp[j][1] = -prices[i];
                    continue;
                }else if(i == 0 && j == 2) {
                    dp[j][0] = 0;
                    dp[j][1] = -999999;
                    continue;
                } else if(i == 0){
                    dp[j][0] = 0;
                    dp[j][1] = -999999;
                    continue;
                }
                dp[j][0] = Math.max(dp[ j ][0], dp[ j ][1] + prices[i] );
                dp[j][1] = Math.max(dp[ j ][1], dp[ j-1 ][0] - prices[i] );
            }
        }
        int max = 0;
        for(int i = 1;i <= k;i++ ){
            max = Math.max(dp[i][0],max);
        }
        return max;

 

结果还是超出内存空间。。。 

结果发现k和prices[]数组的长度有关系,加入如下的判断即可

    int n = prices.length;
    if (k >= n / 2) {   // 这种情况下该问题退化为普通的股票交易问题
        int maxProfit = 0;
        for (int i = 1; i < n; i++) {
            if (prices[i] > prices[i - 1]) {
                maxProfit += prices[i] - prices[i - 1];
            }
        }
        return maxProfit;
    }

 

你可能感兴趣的:(普通DP)