关键词:
动态规划,分治
121. Best Time to Buy and Sell Stock
题目地址
https://leetcode.com/problems/best-time-to-buy-and-sell-stock/
求最大的一次买卖
122. Best Time to Buy and Sell Stock II
题目地址:
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/
不限买卖次数的最大盈利额
采用动态规划做法,o(n^2)时间复杂度
dp[i]表示截止到第i天 可以获得的最大盈利
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if (len <= 1)
return 0;
vector<int> dp(len);
dp[0] = 0;
dp[1] = max(0, prices[1] - prices[0]);
int minVal = min(prices[0], prices[1]);
int maxP = max(dp[0], dp[1]);
for (int i = 2; i < len; i++)
{
if (prices[i] <= minVal)
{
dp[i] = dp[i - 1];
minVal = prices[i];
continue;
}
int p1 = dp[i - 1];
int p2 = prices[i] - prices[0];
dp[i] = max(p1, p2);
for (int j = 1; j < i; j++){
if (prices[i] <= prices[j])
continue;
int ptmp = dp[j - 1] + prices[i] - prices[j];
dp[i] = max(dp[i], ptmp);
}
if (dp[i] > maxP)
maxP = dp[i];
}
return maxP;
}
};
另外一种做法,说
应为不限制次数,因此,每一天都可以卖出,所以只要当前比昨天能够有收入,就可以卖出当天的
(一直递增的序列,其实算的是 最大减去最小的那个值,还是最大的)
最后的ac代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if (len <= 1)
return 0;
int result = 0;
for (int i = 1; i < len; ++i) {
if (prices[i] - prices[i - 1] > 0) {
result += prices[i] - prices[i - 1];
}
}
return result;
}
};
123. Best Time to Buy and Sell Stock III
题目地址
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/
最多可以进行2次交易的最大获利,可以2次或1次
有种分治的思想
ac代码如下
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if (len <= 1)
return 0;
if (len == 2)
{
return max(0, prices[1] - prices[0]);
}
int maxP = 0;
vector<int> left(len); // 包括 price[i] 在内的 左部分的最大一次交易
left[0] = 0;
int leftMin = prices[0];
for (int i = 1; i < len; i++)
{
left[i] = max(left[i-1], prices[i] - leftMin);
if (prices[i] < leftMin){
leftMin = prices[i];
}
if (left[i] > maxP)
maxP = left[i];
}
vector<int> right(len); // 包括 price[i]在内 右部分的最大一次交易
right[len - 1] = 0;
int rightMax = max(prices[len - 1], prices[len - 2]);
for (int i = len - 2; i >= 0; i--)
{
right[i] = max(right[i+1], rightMax - prices[i]);
if (prices[i] > rightMax)
rightMax = prices[i];
}
// 两次交易
for (int i = 1; i < len - 2; i++)
{
int two = left[i] + right[i + 1];
if (two > maxP)
maxP = two;
}
return maxP;
}
};
188. Best Time to Buy and Sell Stock IV
题目地址
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/
规定了最大交易次数,是上面几个题目的拓展
思路1
转载文章参考如下
http://www.07net01.com/2015/08/903505.html
基本思想
k次交易,我们需要大小为k的数组记录每一次交易的信息,又因为一次交易包含买和卖两次操作,所以我们需要两个数组。分别命名为hold【】和sell【】。hold[i]表示第i次持有后的盈亏,也就是第i次买入后的状态,sell[i]表示第i次卖出后的盈亏状态。比如上个例子1,3,7,2,1,5.如果我们在第一天买入,那么hold[1]应该是-1,这里可能会问,为什么会是负数?那是因为我们买入了股票,钱已经花出去了,但我们还没有卖出,所以当前你手上是没有现金的,只有股票。
算法核心就是两句:
cur = prices[i];
sell[j] = max(sell[j],hold[j] + cur); // sell 递推式
hold[j] = max(hold[j],sell[j-1] - cur); // hold递推式
在第i天第j次持有的盈亏最大是取两个的较大值,前一个表示继续持有,后一个表示在第j-1次卖出后,第i天又买入了。
在第i天第j次卖出的盈亏最大同上,也是比较两数取较大。
最后的ac代码如下:
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int len = prices.size();
if (len <= 1 || k <= 0)
return 0;
if (k > len / 2) // 不限制次数
{
int result = 0;
for (int i = 1; i < len; ++i) {
if (prices[i] - prices[i - 1] > 0) {
result += prices[i] - prices[i - 1];
}
}
return result;
}
int INF = 0x7fffffff;
int MIN = -1 - INF;
vector<int> hold(k + 1, MIN); // 第k次交易持有的亏损
vector<int> sell(k + 1,0); // 第k次交易卖出后的盈利情况
int cur;
for (int i = 0; i < len; i++)
{
cur = prices[i];
for (int j = 1; j <= k; j++)
{
sell[j] = max(sell[j], hold[j] + cur); // 当前卖出 + 上一次的买入
hold[j] = max(hold[j], sell[j - 1] - cur); // 当前买入 + 上一次的卖出
}
}
return sell[k];
}
};
思路二
转载:Code_Ganker
原文地址:
http://blog.csdn.net/linhuanmars/article/details/23236995