力扣 买卖股票的最佳时机II
题目描述
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
1 <= prices.length <= 3 * 10 ^ 4
0 <= prices[i] <= 10 ^ 4
思路分析
方法一: 模拟
用两个指针pre和last, 遍历数组, 在上升的时候更新last, 在下降的时候更新ans的值,并将pre和last指向当前值,需要注意的是如果最后一个还是上升的话最后一次的更新是没有计算的,需要单独加上
AC代码:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int pre=prices[0],last=prices[0];
int ans=0;
if(prices.size()==1)return 0;
for(int i=1;i<prices.size();i++)
{
if(prices[i]>=prices[i-1]) last=prices[i];
else
{
ans+=last-pre;
if(i+1>=prices.size())break;
else
{
pre=prices[i];
last=prices[i];
}
}
}
if(prices[prices.size()-1]>=prices[prices.size()-2])ans+=last-pre;//易错
return ans;
}
};
方法二:贪心
由于股票的购买没有限制,因此整个问题等价于寻找 xx 个不相交的区间 (li,ri]使得如下的等式最大化
∑
i
=
1
x
a
[
r
i
]
−
a
[
l
i
]
i
\sum_{i=1}^{x} a[r_i]-a[l_i] i
i=1∑xa[ri]−a[li]i
其中 li表示在第 li天买入,ri表示在第 ri天卖出。同时我们注意到对于 (li,ri]这一个区间贡献的价值 a[ri]-a[li]其实等价于若干个区间长度为 1 的区间的价值和,即
a
[
r
i
]
−
a
[
l
i
]
=
(
a
[
r
i
]
−
a
[
r
i
−
1
]
)
+
(
a
[
r
i
−
1
]
−
a
[
r
i
−
2
]
)
+
…
+
(
a
[
l
i
+
1
]
−
a
[
l
i
]
)
a
[
r
i
]
−
a
[
l
i
]
a[r_i]-a[l_i]=(a[r_i]-a[r_i-1])+(a[r_i-1]-a[r_i-2])+\ldots+(a[l_i+1]-a[l_i]) a[r i]−a[l i]
a[ri]−a[li]=(a[ri]−a[ri−1])+(a[ri−1]−a[ri−2])+…+(a[li+1]−a[li])a[ri]−a[li]
因此问题可以简化为找 x 个长度为 1 的区间 (li,li+1] 使得 价值最大化。
贪心的角度考虑我们每次选择贡献大于 00 的区间即能使得答案最大化,因此最后答案为
a n s = ∑ m a x ( 0 , a [ i ] − a [ i − 1 ] ) ans= ∑ max( 0,a[i]−a[i−1] ) ans=∑max(0,a[i]−a[i−1])
需要说明的是,贪心算法只能用于计算最大利润,计算的过程并不是实际的交易过程。
考虑题目中的例子 [ 1,2,3,4,5],数组的长度 n=5,由于对所有的 1≤i<n 都有 a[i]>a[i-1],因此答案为
a
n
s
=
∑
a
[
i
]
−
a
[
i
−
1
]
=
4
ans=∑ a[i]−a[i−1]=4
ans=∑a[i]−a[i−1]=4
但是实际的交易过程并不是进行 4次买入和 4次卖出,而是在第 1天买入,第 5天卖出。
AC代码:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ans = 0;
int n = prices.size();
for (int i = 1; i < n; ++i) {
ans += max(0, prices[i] - prices[i - 1]);
}
return ans;
}
};