这篇page是针对leetcode上的188.买卖股票的最佳时机Ⅳ所写的。小尼先简单的说明一下这道题的意思,就是我们给定一个整数数组prices,它的第i个元素prices[i]是一支给的股票在第i天的价格。我们需要设计一个算法在我们完成k次交易的情况下我们可以赚到最大的利润。
其实这道题跟小尼上面的所写的只交易两次的题目非常的类似,只是说我们增加了交易的次数,意味着我们进行的操作没多一次交易我们将会进行的步骤就回增加两次,我们还是利用动态规划五部曲:
1.确定dp数组以及下标的含义
在动态规划:123.买卖股票的最佳时机III (opens new window)中,我是定义了一个二维dp数组,本题其实依然可以用一个二维dp数组。
使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]
j的状态表示为:
大家应该发现规律了吧 ,除了0以外,偶数就是卖出,奇数就是买入。
题目要求是至多有K笔交易,那么j的范围就定义为 2 * k + 1 就可以了。
2.确定递推公式
还要强调一下:dp[i][1],表示的是第i天,买入股票的状态,并不是说一定要第i天买入股票,这是很多同学容易陷入的误区。
达到dp[i][1]状态,有两个具体操作:
选最大的,所以 dp[i][1] = max(dp[i - 1][0] - prices[i], dp[i - 1][1]);
同理dp[i][2]也有两个操作:
所以dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])
3.dp数组如何初始化
第0天没有操作,这个最容易想到,就是0,即:dp[0][0] = 0;
第0天做第一次买入的操作,dp[0][1] = -prices[0];
第0天做第一次卖出的操作,这个初始值应该是多少呢?
首先卖出的操作一定是收获利润,整个股票买卖最差情况也就是没有盈利即全程无操作现金为0,
从递推公式中可以看出每次是取最大值,那么既然是收获利润如果比0还小了就没有必要收获这个利润了。
所以dp[0][2] = 0;
第0天第二次买入操作,初始值应该是多少呢?
不用管第几次,现在手头上没有现金,只要买入,现金就做相应的减少。
第二次买入操作,初始化为:dp[0][3] = -prices[0];
所以同理可以推出dp[0][j]当j为奇数的时候都初始化为 -prices[0],在初始化的地方同样要类比j为偶数是卖、奇数是买的状态。
4.确定遍历顺序
从递归公式其实已经可以看出,一定是从前向后遍历,因为dp[i],依靠dp[i - 1]的数值。
5.导出递推公式
小尼接下来拉一下这道题的解题代码:
- class Solution {
- public int maxProfit(int k, int[] prices) {
- if(prices.length == 0) return 0;
-
- int len = prices.length;
- int[][] dp = new int[len][k*2 + 1];
-
- for(int i = 1;i < k*2; i += 2){
- dp[0][i] = -prices[0];
- }
-
- for(int i = 1;i < len ; i++){
- for(int j = 0; j < k*2 - 1; j += 2){
- dp[i][j + 1] = Math.max(dp[i - 1][j + 1], dp[i - 1][j] - prices[i]);
- dp[i][j + 2] = Math.max(dp[i - 1][j + 2], dp[i - 1][j + 1] + prices[i]);
- }
- }
- return dp[len - 1][k*2];
- }
- }
小尼简单的说明一下这道题的解题的思路,其实还是比较简单的,其实就是我们在两层递归中我们一共是进行两部操作,我们只是再将步数进行不断的重复,我们进行的第一步就是买入,这里就是对应我们的j+1的操作,我们第二步就是做卖出的操作,这里对应的步骤就是j+2的操作。我们第一层递归的是我们的物品数,我们的第二层递归的是我们的k的层数,因为每当我们增加一次交易的机会,我们的步骤就会增加两个,所以我们再循环中所设的限制就是j < k*2 - 1.
希望上面的代码可以帮助到小伙伴们~~~