題目來自極客學院的視頻教程-動態規劃(一)
一句話解釋動態規劃:多階段最優化決策解決問題的過程
解題技巧:只關注狀態轉移(子問題之間的關係),不要考慮某個狀態是怎麼出現的
1.字符串解碼
一個只包含大寫字母的字符串加密後變成了只包含數字的字符串,加密的規則:
'A' -> 1
'B' -> 2
...
'Z' -> 26
現在給定一個只包含數字的加密過的字符串,求該字符串有多少種解密的方法。例如“12”->"AB", "12"->"L"
解:2位的在26以內的相鄰的數可以產生不同的解,字符串用str表示,用一維數組dp[i]來表示從0到i位解碼方法總數,dp[0]=1,想從dp[i]得到dp[i+1]:
1.str[i+1]是‘0’,那麼他不能單獨譯成一個字母,一定是和str[i]組合,dp[i+1] = dp[i-1]
2.str[i+1]不是‘0’:
1)str[i]和str[i+1]位不能組成一個字母,將str[i+1]解碼爲對應的字母,dp[i+1] = dp[i]
2)str[i]和str[i+1]可以組和譯成一個字母,則在這裏就可以出現2種解碼方法,如果單獨譯dp[i+1],有dp[i]種方法,如果組合起來,有dp[i-1]種方法,那麼dp[i+1] = dp[i]+dp[i-1]
代碼:
int Decode_num(string& str) {
int len = str.length();
int *dp = new int[len];
dp[0] = 1;
if (str[1] == '0') dp[1] = 1;
else if (str[0] == '1' || (str[0] == '2' && str[1] <= '6')) dp[1] = 2;
else dp[1] = 1;
for (int i = 1; i < len-1; i++) {
if (str[i+1] == '0') dp[i+1] = dp[i-1];
else if (str[i] == '1' || (str[i] == '2' && str[i+1] <= '6')) dp[i+1] = dp[i] + dp[i-1];
else dp[i+1] = dp[i];
}
return dp[len-1];
}
2.最大子數組乘積
給定一個整數數組,求乘積最大的子數組的乘積值
解:
1)首先明確數組中的數可能是負數
2)設數組是vec[],這裏我們在for循環中用一個max和min值分別記錄包含0~i中包含vec[i]的子數組的乘積的最大值和最小值,爲什麼一定是包含vec[i]呢,因爲只有在這個定義之下,我們才能由i計算到i+1
3)那麼包含vec[i]的子數組乘積的最大值就是vec[i],vec[i]*max,vec[i]*min中的最大值(當min和vec[i]同爲負,相乘得到最大值),更新max值
4)循環中同時更新min,min就是vec[i],vec[i]*max,vec[i]*min中的最小值
5)返回的結果max_product,是以0~size-1結尾的子數組乘積最大值的最大值
代碼:
int Max_product(vector<int>& vec) {
int size = vec.size();
int max_product = vec[0];
int _min = vec[0];
int _max = vec[0];
for (int i = 1; i < size; i++) {
int copy_max = _max;
_max = max(max(vec[i], vec[i]*_max), vec[i]*_min);
_min = min(min(vec[i], vec[i]*_min), vec[i]*copy_max);
max_product = max(max_product, _max);
}
return max_product;
}