leetcode-32.最长有效括号
作者:互联网
题目:
给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。 动态规划的详细思路和推倒过程写在注释了
class Solution { public: int longestValidParentheses(string s) { int max = 0; int N = s.size(); if ( N < 2) { return 0; } // 为了理解动态规划的思路,我们按照 暴力求解 --> 动态规划的过程 // 首先,我们知道,最终的最长有效括号,一定是以字符串s的某个位置为结尾,但是这个位置是不固定的 // 1. 暴力求解 // 很自然,我们就会想到,我们把以字符串s的每个位置为结尾的有效括号全部找出来,然后在所有的有效括号中找出最长 的就得到答案了 // 2. 对暴力求解的分析 // 如果分析暴力求解的所有结果,就会发现,对于某一个位置i而言,我们会把它所有有效括号都找出来,但是我们需要的是最长的那个, // 比如对于字符串"()()"的最后一个位置,我们可以找出两个有效括号由s[2]和s[3]构成的2个长度的(),以及由s[0]s[1]s[2]s[3]构成的4个长度的()(),而我们其实只需要由s[0]s[1]s[2]s[3]构成的,然后我们将以每个位置为结尾的最大有效括号长度做对比,取出最大的那个,就是答案 // 因此从这个角度看,我们定义dp[N], dp[i]其含义为以字符i结尾的(必须包含i位置字符)的最大有效括号长度 // 基于这个定义,我们最终要返回的是dp[N]中的最大值,而不是dp[N-1] // 很多同学没有理解这个dp数组含义,把以字符i结尾的最大有效括号长度,等同于了”到字符i为止的字符串所包含最大有效括号长度“,导致dp数组无法递归下去 // 因为如果按照错误的理解,对于字符串 ”(())(“那么就会想返回dp[N-1], // 就会得到这样的dp数组, dp[0] = 0; dp[1]=0, dp[2]=2,dp[3]=4,dp[4]=4, 请注意dp[4], 按照错误的定义的话,dp[4]是应该等于4,因为它自己虽然不能构成新的有效括号,但是它前面的括号已经构成了4个长度的括号,到s[4]为止的字符串,至少是有4个长度的括号的,因此dp[4]=4, // 然而一旦误入这个解释,就会发现无法解决各种括号的匹配问题,怎么也递归不下去到dp[N-1] // 因此强调一下, dp[i]其含义为以字符i结尾的(必须包含i位置字符)的最大有效括号长度, 而不是”到字符i为止的字符串所包含最大有效括号长度“ std::vector<int> dp (N, 0); for ( int i = 1; i < N ; i++ ) { if ( s[i] != ')' ) { continue; } int pre = i - dp[i-1] - 2; // 说明当前位置的字符s[i]=')', 且s[i-1]='(’, 两者构成有效括号,其长度为dp[i-1]+2 // 还应该考虑,一旦当前字符和其前一个字符构成有效括号后,它还可能和当前有效括号的前一个有效括号连起来, // 构成更长的有效括号 if ( s[i-1] == '(' ) { dp[i] = dp[i-1] + 2; if ( pre >= 0) { dp[i] = dp[i] + dp[pre]; } } // 如果s[i]的前一个字符不是'(', 则需要判断 s[i] 是否可以和遥远的更左边(i - dp[i-1] -1)构成有效括号 else { int index = i - dp[i-1] -1; // index 越界, 比如())的最后一个字符 if ( index < 0 ) { dp[i] = 0; } else if ( s[index] == '(' ) { dp[i] = dp[i-1] + 2; // 下面代码同之前是一样的含义解决 类似 (())(()) 的最后一个字符的括号长度计算情景 if ( pre >=0 ) { dp[i] = dp[i] + dp[pre]; } } else { // 这个代表找到遥远的括号,可惜对方和自己不是一对,无法构成有效口号,比如 )())的最后一个字符 dp[i] = 0; } } max = std::max( max, dp[i] ); } return max; } };
标签:字符,括号,int,32,有效,长度,leetcode,dp 来源: https://www.cnblogs.com/houjianli/p/16412923.html