class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
if(n<1) return 0;
int dp[n];
dp[0]=0;
for(int i=1;i<n;i++){
for(int j = 0;j<i;j++){
dp[i]= max(dp[i-1],prices[i]-prices[j]+dp[j]);
}
}
return dp[n-1];
}
};
第一次看到这个题目,想着是用dp来写的,算法时间复杂度是O(n²)。
状态转移方程
dp[i]= max(dp[i-1],prices[i]-prices[j]+dp[j]);
后来发现其实这个写法其实并不算是dp,只是单纯的暴力算法。
这个题用贪心的话其实就可以写出来了
int maxProfit(vector<int>& prices) {
int ans = 0;
int n=prices.size();
for(int i=1;i<n;i++){
if(prices[i]>prices[i-1])
ans+=prices[i]-prices[i-1];
}
return ans;
思路就是我们每一天都可以进行买卖,那么我们只需要一直买上涨的股票,就能一直赚,并得到最大利益,因为一天内我们既可以买入又可以卖出,是没有利益损失的。
举个例子【7,1,5,3,4,6】
- 股价为1的那天,我们可以看到对比昨天股价7是跌的,所以我们不在股价为7的那天买入股票
- 股价为5的那天,我们可以看到对比昨天股价1是涨的,所以我们要买股价为1的那天的股票并且在股价为5的时候卖出,获得收益 5-1 = 4
- 股价为3的那天,我们可以看到对比昨天股价5是跌的,所以我们不在股价为5的那天买入股票
- 股价为4的那天,我们可以看到对比昨天股价3是涨的,所以我们要买股价为3的那天的股票并且在股价为4的时候卖出,获取收益 4-3 = 1
- 股价为6的那天,我们可以看到对比昨天股价4是涨的,所以我们要买股价为4的那天的股票并且在股价为6的时候卖出,获取收益 6-4 = 2
这时候就可以发现,其实步骤3到步骤5这一步,跟我在股价为3的时候买入,股价为6的时候卖出的收益是一样的,因为我们在股价为4的时候卖出了这只股票,然后我们通过开天眼(现实当然不可能),预测到这只股票还会继续涨,所以我们在股价为4的时候卖出又买回了这只股票,这时候我们是没有收益损失的
所以我们只要一直买上涨的股票,就能获得最大收益,也就是这个贪心算法的核心思想。
后来看了下别人的题解,感觉其实这个跟小偷问题有点像,又重新了写了一遍dp的写法
int maxProfit(vector<int>& prices) {
int n = prices.size();
int temp = INT_MAX;
if(n<1) return 0;
int dp[n][2];
// dp[i][0] 表示第i天不持有股票的收益,dp[i][1] 表示第i天持有股票的收益
//(注意,是持有股票,不一定是持有当前的股票,也可能是持有昨天所持有的股票!)
dp[0][0]=0;
dp[0][1]=-prices[0];
for(int i=1;i<n;i++){
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
}
return dp[n-1][0];
}
对于某一天来说,有四种状态
- 前一天持有股票,今天卖出
dp[i][0]=dp[i-1][1]+prices[i]
2. 前一天持有股票,今天不操作
dp[i][1]=dp[i-1][1]
3. 前一天不持有股票,今天买入
dp[i][1]=dp[i-1][0]-prices[i]
4. 前一天不持有股票,今天不操作
dp[i][0]=dp[i-1][0]
把这四种状态捋清,思路就很明确了。
End:突然想起写博客只是为了记录下自己学习的过程,笔者是算法小白,正在努力学习算法,希望各位大佬看到了能轻点喷。