Leetocode所有5道買賣股票問題總結(121+122+123+188+309)

題目1----121. 買賣股票的最佳時機I:

連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/python

給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。算法

若是你最多隻容許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。數組

解答:

限制只能買入賣出一次spa

DP1:

buy[i]記錄截止到第i天是買入的狀態的最小花費(值爲負數)設計

 1 class Solution {
 2 public:
 3     int maxProfit(vector<int>& prices) {
 4         if(prices.size()<2){
 5             return 0;
 6         }
 7         int n=prices.size(),res=0;
 8         vector<int> buy(n,0);
 9         buy[0]=-prices[0];
10         for(int i=1;i<n;++i){
11             res=max(buy[i-1]+prices[i],res);
12             buy[i]=max(-prices[i],buy[i-1]);
13         }
14         return res;
15     }
16 };

嚴格來講這個不算dp,計算第i天的狀況時,只用到了buy[i-1]的數據。。因此前面保存的數據是沒有意義的。code

DP2:

dp[i]記錄第i天當天賣出的最大利潤,則最大利潤必定等於以前某天買今天賣。blog

i):首先能夠昨天買今天賣。索引

ii):還能夠以前某天買今天賣。dp[i-1]等於昨天以前買入,i-1天賣出的最大利潤,那麼i-1天不賣,改成第i天賣也能夠獲得一個利潤。內存

兩個利潤取最大。leetcode

 1 class Solution {
 2 public:
 3     int maxProfit(vector<int>& prices) {
 4         if(prices.size()<2){
 5             return 0;
 6         }
 7         int n=prices.size();
 8         vector<int> dp(n,0);
 9         dp[0]=0;
10         int res=0;
11         for(int i=1;i<n;++i){
12             dp[i]=max(0,prices[i]-prices[i-1]);
13             dp[i]=max(dp[i],dp[i-1]-prices[i-1]+prices[i]);
14             res=max(res,dp[i]);
15         }
16         return res;
17     }
18 };

 

遍歷:

和DP同樣都是O(N)時間,和第一種dp同樣想法,只是不用記錄dp數組了。畢竟考察i的時候,只須要buy[i-1]的數據。
思路:最高利潤出如今:買入爲價格最低時,賣出爲買入以後價格最高時。
故當更新最小值價格時,以前的最大價格要捨棄,從當前索引繼續考察。

 1 class Solution:
 2     def maxProfit(self, prices: List[int]) -> int:
 3         l=len(prices)
 4         if l<2:
 5             return 0
 6         _min,_max=0,0
 7         i=0
 8         res=0
 9         while i<l:
10             if prices[i]<prices[_min]:
11                 _min=i
12                 _max=i
13             if prices[i]>prices[_max]:
14                 _max=i
15             res=max(res,prices[_max]-prices[_min])
16             i+=1
17         return res

 

題目2----122. 買賣股票的最佳時機II:

連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/

給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。

設計一個算法來計算你所能獲取的最大利潤。你能夠儘量地完成更多的交易(屢次買賣一支股票)。

解答:

無限制次數的買入賣出

 1 class Solution {
 2 public:
 3     int maxProfit(vector<int>& prices) {
 4         int n=prices.size();
 5         if(n<2){return 0;}
 6         vector<int> buy(n,0),sell(n,0);
 7         buy[0]=-prices[0];
 8         for(int i=1;i<n;++i){
 9             sell[i]=max(sell[i-1],prices[i]+buy[i-1]);//以前賣今天不賣 or 以前買今天賣
10             buy[i]=max(buy[i-1],sell[i-1]-prices[i]);//以前買今天不買 or 以前賣了今天買
11         }
12         return sell[n-1];
13     }
14 };

 

題目3----123. 買賣股票的最佳時機III:

連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/

給定一個數組,它的第 i 個元素是一支給定的股票在第 i 天的價格。

設計一個算法來計算你所能獲取的最大利潤。你最多能夠完成 兩筆 交易。 

解答:

限制最多兩次買入賣出

定義了4個dp數組,分別是

buy1[i]:第i天是第一次買入的狀態

sell[i]:第i天是第一次賣出的狀態

buy二、sell2同理。

因爲一開始還不能第二次買和第二次賣,因此賦值爲負無窮。

 1 class Solution {
 2 public:
 3     #define inf INT_MIN
 4     int maxProfit(vector<int>& prices) {
 5        int n=prices.size();
 6        if(n<2){return 0;}
 7        vector<int> buy1(n,0),sell1(n,0),buy2(n,inf),sell2(n,inf);
 8        buy1[0]=-prices[0];
 9        for(int i=1;i<n;++i){
11            sell1[i]=max(prices[i]+buy1[i-1],sell1[i-1]);
12            buy1[i]=max(-prices[i],buy1[i-1]);
13            sell2[i]=max(buy2[i-1]+prices[i],sell2[i-1]);
14            buy2[i]=max(buy2[i-1],sell1[i-1]-prices[i]);
16        }
17        return max(0,max(sell2[n-1],sell1[n-1]));
18     }
19 };

方法2:先計算1次買賣最大的利潤sell1[i]。再計算從第i天開始再買賣一次最大的利潤sell2[i]。

第一次買賣是從前向後求(由於左側是固定的),第二次買賣是從後向前求(由於右側是固定的)

 1 class Solution {
 2 public:
 3     #define inf INT_MIN
 4     int maxProfit(vector<int>& prices) {
 5        int n=prices.size();
 6        if(n<2){return 0;}
 7        vector<int> sell1(n,0),sell2(n,0);
 8        int min_buy=-prices[0];
 9        for(int i=1;i<n;++i){
10            sell1[i]=max(sell1[i-1],prices[i]+min_buy);
11            min_buy=max(min_buy,-prices[i]);
12        }
13        int res=max(0,sell1[n-1]);
14        int max_sell=prices[n-1];
15        for(int i=n-2;i>=0;--i){
16            sell2[i]=max(sell2[i+1],max_sell-prices[i]);
17            max_sell=max(max_sell,prices[i]);
18            res=max(res,sell1[i]+sell2[i]);
19        }
20        return res;
21     }
22 };

以前寫過的python版本,以供參考:

 1 class Solution:
 2     def maxProfit(self, prices) -> int:
 3         l=len(prices)
 4         if l<2:
 5             return 0
 6         res=0
 7         #先算一個dp1數組
 8         #dp1[i]表示截止到第i-1天只進行一次買賣的最大利潤
 9         dp1=[0 for i in range(l)]
10         max_price,min_price=prices[0],prices[0]
11         for i in range(1,l):
12             dp1[i]=max(dp1[i-1],prices[i]-min_price)
13             #對於第i天來講,1.若是當天賣:最大利潤即當前賣出價格
14             #減去以前的最小買入價格,2若是不賣:最大利潤和前一天的
15             #最大利潤相同
16             min_price=min(min_price,prices[i])  #更新當前最小買入價格
17             max_price=max(max_price,prices[i])  #更新當前最大賣出價格
18         #對於任意k,dp1[k]表示k賣出的最大利潤,
19         #那麼須要求剩下k+1到n-1的最大利潤
20         #倒着求,由於右邊界不變始終爲l-1,左邊界在變化
21         #dp2[i]表示從i開始到最後只進行一次買賣的最大利潤
22         res=dp1[-1]
23         # print(res)
24         dp2=[0 for i in range(l)]
25         max_price=prices[-1]
26         for i in range(l-2,-1,-1):
27             dp2[i]=max(dp2[i+1],max_price-prices[i])
28             #對於第i天,1.若當天買,則最大利潤即以後的最大賣出價格減去
29             #當前買入價格,2.若當天不買,最大利潤和後一天的最大利潤相同
30             max_price=max(max_price,prices[i])  #更新當前最大賣出價格
31             res=max(res,dp1[i-1]+dp2[i]) if i>=1 else max(res,dp2[i])
32         # print(dp1)
33         # print(dp2)
34         return res

 

後來發現其實不須要存儲dp數組,只須要一個變量記錄上一次的狀態就行,但我懶,就不寫了,反正內存大任性

 

題目4----188. 買賣股票的最佳時機IV:

連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/

給定一個數組,它的第 i 個元素是一支給定的股票在第 天的價格。

設計一個算法來計算你所能獲取的最大利潤。你最多能夠完成 k 筆交易。

 

這道題限制買賣次數最大爲k,是一個變量。

 

設二維dp數組。dp[i][j]表示截止到i最多完成j筆交易的最大利潤。

截止第i天,最大利潤首先能夠是以前的最大利潤,即以前就完成了j筆交易,第i天不賣。

固然第i天也能夠賣,那麼本撥交易的買入最晚也得是i-1天,那麼i-2天以前(包含i-2天)就必需要完成j-1筆交易。

用一個max值表示截止到前一天完成j-1筆交易、而且是待賣出狀態的最大利潤。

遞推方程爲:dp[i][j]=max(dp[i-1][j],max+prices[i])

另外每次循環中要更新max的值。

 

另外有用例k給的無限大,那麼申請dp數組時會爆棧。須要判斷一下k和價格數量的關係,若是k太大,轉化爲上面第2題的無限次的買賣股票問題。

前面的問題1和問題3只是這道題的特殊狀況,代碼直接複製過去就能夠運行。

 1 class Solution {
 2 public:
 3     int maxProfit(int k, vector<int>& prices) {
 4         if(prices.empty()){
 5             return 0;
 6         }
 7         int n=prices.size();
 8         if(2*k<n){
 9             vector<vector<int>> dp(n,vector<int>(k+1,0));
10             //dp[i][j]表示截止第i天完成最多j次交易獲得的最大收益
11             for(int j=1;j<k+1;++j){
12                 int _max=-prices[0];
13                 for(int i=1;i<n;++i){
14                     dp[i][j]=max(dp[i-1][j],_max+prices[i]);
15                     _max=max(dp[i-1][j-1]-prices[i],_max);
16                 }
17             }
18             return dp.back().back();
19         }
20         else{//k太大,至關於能夠無限次交易
21             vector<int> dp(n,0);
22             //dp[i]表示截止第i+1天獲得的最大收益
23             int _max=-prices[0];
24             for(int i=1;i<n;++i){
25                 dp[i]=max(dp[i-1],_max+prices[i]);
26                 _max=max(_max,dp[i]-prices[i]);
27             }
28             return dp.back();
29         }
30         return 0;
31     }
32 };

 

題目5----309. 最佳買賣股票時機含冷凍期:

連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/

給定一個整數數組,其中第 i 個元素表明了第 i 天的股票價格 。​

設計一個算法計算出最大利潤。在知足如下約束條件下,你能夠儘量地完成更多的交易(屢次買賣一支股票):

 

這道題多了一個冷凍期的限制:賣出以後要至少休息一天才能買入

那麼理所固然的,多設立一個dp數組以表示冷凍期的狀態:

 1 class Solution {
 2 public:
 3     int maxProfit(vector<int>& prices) {
 4         if(prices.size()<2){
 5             return 0;
 6         }
 7         int n=prices.size();
 8         vector<int> buy(n,0),sell(n,0),freeze(n,0);
 9         //buy[i]、sell[i]、freeze[i]分別表示第i天
10         //買入、賣出、不買不賣的最大收益(包含買股票花的錢)
11         buy[0]=-prices[0];
12         int res=0;
13         for(int i=1;i<n;++i){
14             buy[i]=max(buy[i-1],freeze[i-1]-prices[i]);
15             sell[i]=max(sell[i-1],buy[i-1]+prices[i]);
16             freeze[i]=max(sell[i-1],freeze[i-1]);
17             res=max(sell[i],res);
18         }
19         return res;
20     }
21 };

也能夠仿照第四題的解法,用一個max值保存截止前一天待賣出狀態的最大利潤,不過更新max的時候,要注意冷凍期的要求。因此_max=max(_max,dp[i-2]-prices[i]),即截止i-2天賣出的最大利潤,休息一天,第i天買入。以前的題目是_max=max(_max,dp[i-1]-prices[i]),注意兩者的區別,雖然只是1和2的數字不一樣,但倒是整道題的關鍵

 1 class Solution {
 2 public:
 3     int maxProfit(vector<int>& prices) {
 4         int n=prices.size();
 5         if(n<2){return 0;}
 6         vector<int> sell(n,0);
 7         sell[1]=max(0,prices[1]-prices[0]);
 8         int _max=max(-prices[0],-prices[1]);
 9         for(int i=2;i<n;++i){
10             sell[i]=max(sell[i-1],_max+prices[i]);
11             _max=max(_max,sell[i-2]-prices[i]);
12         }
13         // for(int x:sell){cout<<x<<" ";};
14         return sell[n-1];
15     }
16 };

完結撒花👏👏

 

明天就要華爲機試了,壞運氣給👴爬

2020-02-19 02:01:09

相關文章
相關標籤/搜索