动态规划
动态规划算法 (Dynamic Programming,DP)
算法思想
种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路
经典使用场景
1:最长有效括号
题目
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”
代码
/*
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
dp 动态规划问题
1:首先明确,有)才会有完整的有效括号,如果(我们要往后遍历,由于我们使用的是动态规划,把问题分解成小问题,那就得向遍历前面的小问题。
2:)可能为第一个,所以我们从第二个开始遍历。
3:)前一个可能为(,那我们可以直接获取前面的最优解。然后进行+2;
4:)前面可能是),但是这个)前面已经匹配,那就寻找前面的)哪个匹配的( 前一个是否为) 如果不为嘛,那就这个无效,
*/
int longestValidParent1heses(string s)
{
int len = s.size();
int resmax = 0;//保存最大值
if (len <= 1) return 0;
vector<int> dp(len,0);//初始化记录容器
for (int i = 1; i < len;i++)
{
if (s[i] == ')')//1:首先明确,有)才会有完整的有效括号,如果(我们要往后遍历,由于我们使用的是动态规划,把问题分解成小问题,那就得向遍历前面的小问题。
{
if (s[i - 1] == '(')//3:)前一个可能为(,那我们可以直接获取前面的最优解。然后进行+2;
{
dp[i] = ((i >= 2) ? dp[i - 2] : 0) + 2;
}
else if (i-dp[i-1]>0&&s[i-dp[i-1]-1]=='(')//4:)前面可能是),但是这个)前面已经匹配,那就寻找前面的)哪个匹配的( 前一个是否为) 如果不为嘛,那就这个无效,
{
dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
}
resmax = max(resmax, dp[i]);
}
};
return resmax;
}
解法及解析
这里的状态转移方程比较简单,但是背包问题都是这种套路比较好理解。主要记住,动态规划就是分解问题,从小问题开始求,但解不是最后的解。
中间可能会发生状态的改变,这也就是动态规划的优,你要深思这个状态转移过程,多思考,一定有收获。