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).
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.
这道题我一开始想用动态规划去做,转移方程是
dp[[j][m] = max(dp[k][m-1] + maxp[k+1][j]):dp[j][m]指的是前j天m次交易的最大收益,1<=j<n;2<=m<=k;1<=k<=j;时间复杂度是O(n^3),空间复杂度是O(n^2);很明显两者都太高了,有些case超出内存限制了;之前做Best Time to Buy and Sell StockⅢ的时候有尝试过找成对的波峰波谷,将差值放到大顶堆中,然后取前k个值。但是因为不知道如何处理v1<v2&&p1<p2的情况,有些case没法通过;但是我看了别人的做法,非常巧妙。当v1<v2&&p1<p2时,可以将(v1,p2),(v2,p1)代替(v1,p1),(v2,p2),这就完美解决了我上面的问题。唉,为什么我当初没有细想下去呢。。。。时间复杂度为O(n),空间复杂度也为O(n)。
下面附上第一第二次的代码
class Solution {
public:
int maxProfit(int k, vector<int>& prices)
{
int n = prices.size();
//cout<<n<<endl;
if(n<2||k==0) return 0;
vector<vector<int> > maxp_1 = maxp(prices);
vector<vector<int> > dp(n,vector<int>(k+1,0));
for(int i=1;i<n;i++)
{
dp[i][1] = maxp_1[0][i];
cout<<i<<" "<<1<<" "<<dp[i][1]<<endl;
}
if(k==1) return dp[n-1][1];
for(int j=1;j<n;j++)
{
for(int m=2;m<=k;m++)
for(int i=1;i<=j;i++)
{
dp[j][m] = max(dp[j][m],dp[i][m-1]+maxp_1[i+1][j]);
//cout<<i<<' '<<m<<" "<dp[i][m];
}
}
return dp[n-1][k];
}
vector<vector<int> > maxp(vector<int>& price)
{
int n = price.size();
vector<vector<int> > maxpv(n+1,vector<int>(n+1,0));
for(int i=0;i<n;i++)
{
int minele = price[i];
for(int j=i+1;j<n;j++)
{
maxpv[i][j] = max(maxpv[i][j-1],price[j]-minele);
if(price[j]<minele) minele = price[j];
}
}
return maxpv;
}
};
class Solution {
public:
int maxProfit(int k, vector<int>& prices)
{
stack<pair<int,int>> vp_pairs;
priority_queue<int> profit;
int n=prices.size();
int v,p=0;
int ans=0;
while(p<n)
{
for(v=p;v<n-1&&prices[v]>=prices[v+1];v++);
for(p=v+1;p<n&&prices[p]>=prices[p-1];p++);
while(!vp_pairs.empty()&&prices[v]<=prices[vp_pairs.top().first])
{
profit.push(prices[vp_pairs.top().second-1]-prices[vp_pairs.top().first]);
vp_pairs.pop();
}
while(!vp_pairs.empty()&&prices[p-1]>prices[vp_pairs.top().second-1])
{
profit.push(prices[vp_pairs.top().second-1]-prices[v]);
v = vp_pairs.top().first;
vp_pairs.pop();
}
vp_pairs.push({v,p});
}
while(!vp_pairs.empty())
{
profit.push(prices[vp_pairs.top().second-1]-prices[vp_pairs.top().first]);
vp_pairs.pop();
}
for(int i=0;i<k&&!profit.empty();i++)
{
ans += profit.top();
profit.pop();
}
return ans;
}
};
ps:我老是会犯堆溢出的问题,在访问向量中元素的时候经常忘记做下标判断。