题目来自极客学院的视频教程-动态规划(一)
一句话解释动态规划:多阶段最优化决策解决问题的过程
解题技巧:只关注状态转移(子问题之间的关系),不要考虑某个状态是怎么出现的
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;
}