给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"
示例 2:输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"
示例 3:输入:s = ""
输出:0
提示:
0 <= s.length <= 3 * 104
s[i] 为 '(' 或 ')'来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
官方解法代码实现:
自己更新一波简洁代码:
dp[i-1]只有0和非零两种状态(所以两种状态可以统一起来,这是最后一种方法的改进):
若为0,则可能是左括号,会进行配对;
否则大于0的话,就向前看钱dp[i-1]+1个元素 对应 s[i-1-dp[i-1]]是否是左括号,如果是就更新当前dp[i]为依据匹配的2, 还有 dp[i-2-dp[i-1]] ,与 dp[i-1]之和。
class Solution {
public:
int longestValidParentheses(string s) {
int len = s.length(), rs = 0, dp[len + 1];
if(len <= 1) return 0;
s = ")" + s;
memset(dp, 0, sizeof(dp));
for(int i = 2; i <= len; i++){
if(s[i] != ')') continue;
if(i - 1 - dp[i-1] > 0 && s[i - 1 - dp[i - 1]] == '('){
dp[i] = 2 + dp[i - 2 - dp[i-1]] + dp[i-1];
}
rs = max(rs, dp[i]);
}
return rs;
}
// int longestValidParentheses(string s) {
// int left = 0, right = 0;
// int max=0;
// //从左往右,遇到右括号就判断右括号是不是比左括号多
// for(int i = 0; i < s.length(); i++){
// if(s.at(i)=='('){
// left++;
// }else{
// right++;
// }
// if(right > left){
// left = 0, right = 0;
// }else if(max < right*2&&left==right){//注意left==right的条件
// max = right*2;
// }
// }
// //从左往右,遇到右括号就判断右括号是不是比左括号多
// left = 0, right = 0;
// for(int i = s.length()-1; i>=0; i--){
// if(s.at(i)==')'){
// right++;
// }else{
// left++;
// }
// if(right < left){
// left = 0, right = 0;
// }else if(max < left*2&&left==right){//注意left==right的条件
// max = left*2;
// }
// }
// return max;
// }
};
解法一:双向扫描法
int longestValidParentheses(string s) {
int left = 0, right = 0;
int max=0;
//从左往右,判断右括号是不是比左括号多
for(int i = 0; i < s.length(); i++){
if(s.at(i)=='('){
left++;
}else{
right++;
}
if(right > left){
left = 0, right = 0;
}else if(max < right*2&&left==right){//注意left==right的条件
max = right*2;
}
}
//从右往左,判断左括号是不是比右括号多
left = 0, right = 0;
for(int i = s.length()-1; i>=0; i--){
if(s.at(i)==')'){
right++;
}else{
left++;
}
if(right < left){
left = 0, right = 0;
}else if(max < left*2&&left==right){//注意left==right的条件
max = left*2;
}
}
return max;
}
解法二:栈
public static int longestValidParentheses(String s) {
int rs = 0, count = 0;
Stack<Integer> stack = new Stack<>();
stack.push(-1);
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i)=='(') {
stack.push(i);
}else if(stack.size()>1) {
stack.pop();
count = i - stack.peek();
if(count > rs) {
rs = count;
}
}else {
stack.clear();
stack.push(i);
}
}
return rs;
}
解法三:终于写出来了动态规划,因为一下子i-1一下子i的,感觉不太舒服,我直接在字符串前面加了一个右括号“)”,这个右括号显然是匹配不上的,永远打光棍,不过却使得dp的下标和字符串的下标保持一致,不容易出错,也算是牺牲一个人的幸福,成全了大家。。。。。。
class Solution {
public static int longestValidParentheses(String s) {
int rs = 0;
if(s==null||s.length()<2) {
return rs;
}
s = ')'+ s;
int dp[] = new int[s.length()];
for(int i = 2; i < s.length(); i++) {
if(s.charAt(i)==')') {//准备在"认识的人"(已经扫描过的,而且是最近一段时间认识的,而不是幼儿园小学认识的人)中找对象,
if(s.charAt(i-1)=='(') {//刚好凑一对,别抢别人的对象吧,珍惜眼前人
dp[i] = 2 + dp[i-2];//但是如果他对象之前又有一对或者很多对呢?例如:(()()) () 所以对于最后一对来说,他应该加上前一对,才能知道连续的一组璧人有多少
}else if(dp[i-1]>0){//他最近认识的人是同性朋友,而且这人已经有对象,需要再往之前认识的人中去找
if(i - dp[i-1] - 1 >= 0 && s.charAt(i - dp[i-1] - 1)=='(') {//最近认识的人中无对象的异性朋友,适合成为他对象
dp[i] = 2 + dp[i-1] + dp[i - dp[i-1] - 2];
}else {//只能打光棍
dp[i] = 0;
}
}
}//如果是女生"(",只能往后找,不能忘前找。。。。。。 java int数组 默认是0 这里就不用赋值为0了
if(rs < dp[i]) {
rs = dp[i];
}
}
return rs;
}
}