開始做動態規劃部分的內容了,這部分有四個題,所以就對半開吧。
做這些題目的時候,有那麼一些感覺像是回到了小時候做奧數的感覺,反正都是難。
第一題:(爬樓梯)
假設你正在爬樓梯。需要 n 階你才能到達樓頂。
每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?
注意:給定 n 是一個正整數。
示例 1:
輸入: 2
輸出: 2
解釋: 有兩種方法可以爬到樓頂。
1. 1 階 + 1 階
2. 2 階
示例 2:
輸入: 3
輸出: 3
解釋: 有三種方法可以爬到樓頂。
1. 1 階 + 1 階 + 1 階
2. 1 階 + 2 階
3. 2 階 + 1 階
> 來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/climbing-stairs
> 著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
第二題:買賣股票的最佳時機
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
如果你最多隻允許完成一筆交易(即買入和賣出一支股票一次),設計一個算法來計算你所能獲取的最大利潤。
注意:你不能在買入股票前賣出股票。
示例 1:
輸入: [7,1,5,3,6,4]
輸出: 5
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣出,最大利潤 = 6-1 = 5 。
注意利潤不能是 7-1 = 6, 因爲賣出價格需要大於買入價格;同時,你不能在買入前賣出股票。
示例 2:
輸入: [7,6,4,3,1]
輸出: 0
解釋: 在這種情況下, 沒有交易完成, 所以最大利潤爲 0。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
我的題解(1)
這題居然判定爲簡單題,看來是我太菜了。
我倒也不是做不出來,只是我的算法無法處理過大的數據,哎。
我是這樣想的:既然有n個臺階,假設兩步走的次數爲k,則一步走的次數就是n-2k,那麼將這些兩步走的次數穿插在一步走的情況當中,就是一個排列組合問題。
那就將排列組合整理成一個函數,對k進行遞歸併求和2,便是最後的結果。
於是代碼就出來了:
//二代版本
int twostep(int n,int two)
{
int temp = 1;
int i = n - two;
int del = 1;
for (; i > n - 2 * two; i--)
{
temp *= i;
while (temp % del == 0 && del <= two)
{
temp /= del;
del++;
}
}
while (del <= two)
{
temp /= del;
del++;
}
return temp;
}
int climbStairs(int n)
{
int step = n / 2;
int ret = 1;
while (step > 0)
{
ret += twostep(n, step);
step--;
}
return ret;
}
一代版本是全乘完再統一除。
然後發現當n到35的時候就扛不住了,換了二代版本。沒想到還是抗不過45。
其實如果將除數放在數組裏面做三代版本是可以的,但是那樣就太肥了。。。
最後,我接受了現實,人外有人,那就看看別人怎麼做的。
斐波那契數列。。。
斐波那契解法
int climbStairs(int n) {
if(n==1||n==2)
return n;
int n1=1,n2=2;
for(int i=3;i<=n;i++)
{
int temp=n1+n2;
n1=n2;
n2=temp;
}
return n2;
}
原來這是一個找規律的題目啊。。。
我的題解(2)
上次做的那題,可以多次買賣,這次只能單次,那波峯波谷法就不好用了。
因爲當天下降可能是“虛假下降”,接下來會有反彈。
其實虛假下降也好判斷。但是吧,困擾我的是:
“過度虛假下降”:就是後面會反彈,但是這個下降力度已經超過了之前積攢下來的盈利,出現這種情況,應該認爲之前的天數都不存在,從波谷重頭來過。
其實這個情況單獨處理也並不是什麼很難的事情,但是把這些單獨處理都沒什麼問題的糅雜在一起的時候,那就很麻煩了。
前面失敗了之後,我又想起了最初那個被掐斷的小火苗:乾脆遞歸傳入當前最小值,遍歷找利益最大處。然後,過了。
int maxProfit(vector<int>& prices) {
if (prices.size() < 1)
return 0;
int the_min= prices[0];
int ret = 0;
for (int i = 1; i < prices.size(); i++) {
ret = max(ret, prices[i] - the_min);
the_min = min(the_min, prices[i]);
}
return ret;
}
其實我只是嘗試一下,因爲一開始掐滅這個想法也不是沒有道理的。
因爲最後買入點可不一定會是波谷,賣出點是不是波峯倒是無所謂,關鍵就是那個買入點。
但是,當它奇蹟般的通過的時候,我突然想通了,ret和不止有the_min一個變量在控制,所以the_min是不是波谷對ret並沒有絕對的影響。
有點繞,沒繞出來打盤王者冷靜冷靜。一定是可以繞出來的。
官方題解(1)
方法三:動態規劃(斐波那契數列)
算法
不難發現,這個問題可以被分解爲一些包含最優子結構的子問題,即它的最優解可以從其子問題的最優解來有效地構建,我們可以使用動態規劃來解決這一問題。
第 ii 階可以由以下兩種方法得到:
在第 (i-1) 階後向上爬一階。
在第 (i−2) 階後向上爬 2 階。
所以到達第 ii 階的方法總數就是到第 (i-1)(i−1) 階和第 (i-2)(i−2) 階的方法數之和。
令 dp[i]dp[i] 表示能到達第 ii 階的方法總數:
dp[i]=dp[i-1]+dp[i-2]
dp[i]=dp[i−1]+dp[i−2]
作者:LeetCode
鏈接:https://leetcode-cn.com/problems/climbing-stairs/solution/pa-lou-ti-by-leetcode/
來源:力扣(LeetCode) 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
官方題解(2)
方法二:一次遍歷
算法
假設給定的數組爲:[7, 1, 5, 3, 6, 4]
如果我們在圖表上繪製給定數組中的數字,我們將會得到:
我們來假設自己來購買股票。隨着時間的推移,每天我們都可以選擇出售股票與否。那麼,假設在第 i 天,如果我們要在今天賣股票,那麼我們能賺多少錢呢?
顯然,如果我們真的在買賣股票,我們肯定會想:如果我是在歷史最低點買的股票就好了!太好了,在題目中,我們只要用一個變量記錄一個歷史最低價格 minprice,我們就可以假設自己的股票是在那天買的。那麼我們在第 i 天賣出股票能得到的利潤就是 prices[i] - minprice。
因此,我們只需要遍歷價格數組一遍,記錄歷史最低點,然後在每一天考慮這麼一個問題:如果我是在歷史最低點買進的,那麼我今天賣出能賺多少錢?當考慮完所有天數之時,我們就得到了最好的答案。
作者:LeetCode-Solution
鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/121-mai-mai-gu-piao-de-zui-jia-shi-ji-by-leetcode-/
來源:力扣(LeetCode) 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
public class Solution {
public int maxProfit(int prices[]) {
int minprice = Integer.MAX_VALUE;
int maxprofit = 0;
for (int i = 0; i < prices.length; i++) {
if (prices[i] < minprice)
minprice = prices[i];
else if (prices[i] - minprice > maxprofit)
maxprofit = prices[i] - minprice;
}
return maxprofit;
}
}
> 作者:LeetCode-Solution
> 鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/121-mai-mai-gu-piao-de-zui-jia-shi-ji-by-leetcode-/
> 來源:力扣(LeetCode) 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
總結
動手前,還是先想清楚吧。。。。。。
永遠不要節省整理思緒的時間,不然,在實現功能的時候都會讓你還。