一、问题描述
解决动态规划问题,首先要判断是否需要用到动态规划。
可以使用动态规划的问题一般都遵循一些特点,比如提问的方式一般是:
1. 计数
有多少种方式走到右下角有多少种方法选出K个数使得和是Sum
2. 求最大最小值
从左上角到右下角路径的最大数字和最长上升子序列长度
3. 求存在性
取石子游戏,先手是否必胜能不能选出K个数字使得和是Sum。
针对以上最优解问题,往往可以先尝试动态规划的方法。这就需要我们首先找到构成最优问题的最优子问题,然后确定状态转移方程,问题便迎刃而解了。
二、解决方案
四步轻松搞定99%的动规题
1.确定状态是什么
2.状态转移方程是什么
3.状态的初始值是什么
4.问题要求的最后答案是什么
三、实例
1.题目
2.思路
首先第一步,我们需要定义dp数组的含义,定义二维布尔数组dp[i][j]数组表示:
dp[i][j]表示字符串s[i, j]范围内字符是否为回文串,i从后向前遍历,j从i位置向后遍历。
如果s[i] == s[j],那么i和j满足下面两个条件之一,则dp[i][j] = true。
1、如果i和j相邻或只隔着一个字符,则dp[i][j] = true
2、否则如果dp[i + 1][j - 1] = true,则dp[i][j] = true
if(s[i]) == s[j]){
dp[i][j] = dp[i+1][j-1];
}else{
dp[i][j] = false;
}
如果s[i]≠s[j]那么说明dp[i][j]必定不是回文子串。
3.代码
public:
int countSubstrings(string s) {
if (s.empty()) return 0;
int size = s.size(), res = 0;
vector<vector<bool>> dp(size, vector<bool>(size));
for (int i = size - 1; i >= 0; --i)
{
for (int j = i; j < size; ++j)
{
dp[i][j] = (s[i] == s[j]) && (j - i <= 2 || dp[i + 1][j - 1]);
if (dp[i][j]) ++res;
}
}
return res;
}
public:
int countSubstrings(string s) {
if (s.empty()) return 0;
int size = s.size(), res = 0;
vector<vector<bool>> dp(size, vector<bool>(size));
for (int i = size - 1; i >= 0; --i)
{
for (int j = i ; j < size; j++) {
if (s[i] == s[j]) {
if (j - i < 3) {//i和j相邻的时候
dp[i][j] = true;
}
else {
dp[i][j] = dp[i + 1][j - 1];
}
}
else {
dp[i][j] = false;
}
if (dp[i][j]) {
res++;
}
}
}
return res;
}
参考: