Leetcode面试经典150题-123.买卖股票的最佳时机III

  解法都在代码里,不懂就留言或者私信

建议看这个之前先看股票系列的其他问题123.买卖股票的最佳时机III

Leetcode面试经典150题-121.买卖股票的最佳时机-CSDN博客

Leetcode面试经典150题-122.买卖股票的最佳时机II-CSDN博客

Leetcode面试经典150题-188.买卖股票的最佳时机IV-CSDN博客

尤其是122和188题,这个题的解题其实就是一个简单的加工

class Solution {
    public static int maxProfit(int[] prices) {
        return maxProfit(2, prices);
    }

    /**
     * 本题比股票问题2多了一个限制:最多交易k次,也就是可能不能像我们之前的那种每次波谷都买,每次波峰都卖的方式
     * 除非k是大于等于prices.length/2的
     * @param k 这里的k是交易的对数,也就是买一次卖一次
     * @param prices
     * @return
     */
    public static int maxProfit(int k, int[] prices) {
        if(prices == null || prices.length < 2 || k < 1) {
            return 0;
        }
        int ans = 0;
        //如果交易数限制大于prices.length/2,那我们还是可以认为这就是无限次的交易
        //套用股票问题2的解法
        if(k >= prices.length / 2) {
            for(int i = 1; i < prices.length; i++) {
                int curProfit = Math.max(0,prices[i] - prices[i - 1]);
                ans += curProfit;
            }
            return ans;
        } else {
            int N = prices.length;
            //如果小于这个次数的话就需要好好分析一下了,这里我们使用动态规划的从左往右的尝试模型+业务限制进行解题
            //先定义一个动态规划表,表中dp[i][j]代表从0~i做不超过j次交易可以获得的最大的利润,所以i的变化范围0~N-1,j的变化范围从0到k
            int[][] dp = new int[N][k+1];
            //第一行表示从0~0做0~k次交易,都是0,int默认是0,这里忽略初始化
            //第一列表示从0~0,0~1...0~N分别做0次交易,你都没有做交易,你有啥利润,也都是0,同样忽略初始化过程
            //从dp[1][1]开始初始化,如果按照一般的方式进行初始化则dp[8][2] 有几种可能性(1)8位置不交易,那这种可能是dp[7][2]
            //(2)8位置参与交易,那8位置只能卖(因为我们限制0~8进行2次交易,如果你8位置是买的话利润就无法计算到dp[8][2]里了)
            //那我们可以分别在0~8进行买入,分别是dp[8][1] + prices[8] - prices[8](8位置买入,8位置卖出)
            //dp[7][1] + prices[8] - prices[7](7位置买入,8位置卖出)....dp[0][1] + prices[8] - prices[1]
            //也是就说在O(N*k)的基础上我们又加上了枚举行为,时间复杂度变成了O(N^2*k)这个对于leetCode给的数据量来说,不一定能过
            //这里我们尝试进行斜率优化,斜率优化分析过程参考:https://www.xiaohuazhuo.com/board/658accf232120d0c5d74f794
            //这里简单描述一下,其实我们dp[8][2]求解过程中可能性2的每一项都加上了price[8]这个数,也就是说比较过程我们可以不计算这个数
            //在dp[8][1] - [8] dp[7][1] - [7]....dp[0][1] - [0]中取最大值max,然后+[8]就是当前可能性2的最大值
            //为什么要求这样的最大值呢,因为我们之后的计算过程用的上,现在举一个dp[9][2]的求解过程,可能性1:9位置不交易 =dp[8][2]
            //9位置交易,那0~9都可以买入,分别是dp[9][1] + [9] - [9](9位置买入,9位置卖出) dp[8][1] + [9] - [8](8位置买入,9位置卖出)
            // dp[7][1] + prices[9] - prices[7](7位置买入,9位置卖出)....dp[0][1] + prices[9] - prices[1]
            //这些项里我们又看到了加上了一样的prices[9], 所以比较的时候只需要拿dp[9][1] - [9] dp[8][1] - [8] dp[7][1] - [7]....dp[0][1] - [0]
            //这些取最大值就可以了,但是这些出了第一项之外,不就是dp[8][2]的时候求的max吗?所以复用dp[9][2]时候的max=Math.max(max, dp[9][1] - [9])
            //也就是说对于同一列的后面的行只需要多计算一个数(dp[i][j-1] - prices[i]),然后根据前面的max计算就可以了
            for(int j = 1; j <= k; j++) {
                //对于同一列,后面的行依赖于前面的行,这里我们定义一下公共的依赖
                //这里要注意max的初始值不是0,而是dp[0][j] + prices[0]-prices[0] 的中间部分,也就是dp[0][j]-prices[0]
                int max = dp[0][j]-prices[0];
                int p1 = 0;
                for(int i = 1; i < N; i ++) {
                    p1 = dp[i - 1][j];//0
                    //max函数第一个参数就是当前位置要计算的数dp[i][j-1] - prices[i]
                    max = Math.max(dp[i][j - 1] - prices[i], max);//dp[1][0]-dp
                    dp[i][j] = Math.max(p1, max + prices[i]);
                    System.out.println(i+","+ j + "=" + dp[i][j]);
                }
            }
            ans = dp[N-1][k];
        }
        return ans;
    }
}

这个题解法回头我和股票问题4综合一下,其实两个题是一样的,面试肯定保过

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值