原题链接: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/
Buy and Sell Stock专题相关题目
121. Best Time to Buy and Sell Stock
122. Best Time to Buy and Sell Stock II
123. Best Time to Buy and Sell Stock III
188. Best Time to Buy and Sell Stock IV
309. Best Time to Buy and Sell Stock with Cooldown
714. Best Time to Buy and Sell Stock with Transaction Fee
1. 题目介绍
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most k transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
输入一个数组,数组中第 i 个数代表着某只股票在第 i 天的价格,最多交易为k次,求可获得的最大利润。必须先买后卖,并且同一天只能买一次或者卖一次二选一,不能在同一天买卖。
Example 1:
Input: [2,4,1], k = 2
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2
(price = 4), profit = 4-2 = 2.
Example 2:
Input: [3,2,6,5,0,3], k = 2
Output: 7
Explanation:
Buy on day 2 (price = 2) and sell on day 3 (price = 6),
profit = 6-2 = 4.
Then buy on day 5 (price = 0) and sell on day 6 (price = 3),
profit = 3-0 = 3.
2. 解题思路
动态规划法
这个题是上一道题 123. Best Time to Buy and Sell Stock III的改进版,在III中,只允许最多交易2次,而在IV中就不限次数了,可以不限次数交易。
根据 123. Best Time to Buy and Sell Stock III的解题方法,我们把那一题的代码稍作更改,加入了k次这个变量。
class Solution {
public int maxProfit(int k, int[] prices) {
int length = prices.length;
if(prices==null || length==0)
return 0;
int[] local = new int[k+1];
int[] global = new int[k+1];
for(int i = 1; i<length ; i++)
{
int diff = prices[i]-prices[i-1];
for(int j=k;j>=1;j--)
{
local[j] = Math.max(global[j-1]+(diff>0?diff:0) , local[j]+diff);
global[j] = Math.max( local[j] , global[j] );
}
}
return global[k];
}
}
提交的结果如何呢?Memory Limit Exceeded !
这个样例中,k和数组都很大,该怎么解决呢?
优化方法1
首先看k,在这个样例中,k很大,这就会导致上述代码中的
for(int j=k;j>=1;j--)
{
local[j] = Math.max(global[j-1]+(diff>0?diff:0) , local[j]+diff);
global[j] = Math.max( local[j] , global[j] );
}
执行非常漫长。因此,我们需要做出第一个优化,当k的值超过最大交易次数时,我们就要把k换成最大交易次数,提高效率。数组中共有 n 个数,每个数只能买,或者卖,二选一。买卖一次算是交易,因此最大的交易次数是 n/2
当k > n/2时,我们就把n/2赋值给k,改进后的提交就成功了。
实现代码
class Solution {
public int maxProfit(int k, int[] prices) {
int length = prices.length;
if(prices==null || length==0)
return 0;
if(k > length/2) {
k = length/2;
}
int[] local = new int[k+1];
int[] global = new int[k+1];
for(int i = 1; i<length ; i++)
{
int diff = prices[i]-prices[i-1];
for(int j=k;j>=1;j--)
{
local[j] = Math.max(global[j-1]+(diff>0?diff:0) , local[j]+diff);
global[j] = Math.max( local[j] , global[j] );
}
}
return global[k];
}
}
耗时95ms
优化方法2
当k的值超过最大交易次数时,同时意味着,可以无限次交易了。那样就可以使用贪心的方法,从头遍历数组,每当遇到prices[ i ] > prices[i-1]时,就可以将差价算为收入。
这样的改进方法最后也成功了,而且执行时间非常短。
实现代码
class Solution {
public int maxProfit(int k, int[] prices) {
int length = prices.length;
if(prices==null || length==0)
return 0;
if(k > length/2) {
int ans = 0;
for(int i = 1;i<length;i++) {
if(prices[i] > prices[i-1]) {
ans += prices[i] - prices[i-1];
}
}
return ans;
}
int[] local = new int[k+1];
int[] global = new int[k+1];
for(int i = 1; i<length ; i++)
{
int diff = prices[i]-prices[i-1];
for(int j=k;j>=1;j--)
{
local[j] = Math.max(global[j-1]+(diff>0?diff:0) , local[j]+diff);
global[j] = Math.max( local[j] , global[j] );
}
}
return global[k];
}
}
执行时间只需3ms