連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/python
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。算法
若是你最多隻容許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。數組
限制只能買入賣出一次spa
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
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
連接: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 };
連接: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數組,只須要一個變量記錄上一次的狀態就行,但我懶,就不寫了,反正內存大任性
連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/
給定一個數組,它的第 i 個元素是一支給定的股票在第 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 };
連接: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