最长合法字串问题

最长合法字串问题

算法概论第八周

文章目录

32. Longest Valid Parentheses — 题目链接

题目描述

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.

Example 1:

Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"
Example 2:

Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"

思路分析

方法一:暴力枚举

  • 最朴素的方法就是把所有可能的长度都试一遍
  • 每个长度都要从左至右找一遍字串验证是否合法
  • 判断一个字串是否合法只需要维护一个栈,遇到(入栈,遇到)出栈,如果栈为空仍然需要出栈,则返回false
  • 复杂度:
    • 时间:将所有长度试一遍为 O ( n ) O(n) O(n),每个长度的所有字符串为 O ( n ) O(n) O(n),栈判断为 O ( n ) O(n) O(n),一共为 O ( n 3 ) O(n^3) O(n3)
    • 空间:维护一个栈为 O ( n ) O(n) O(n)

方法二:动态规划

  • 对于动态规划,我们要找出它的最优子问题
  • dp[i]为以s[i]结尾的最长合法字串的长度
  • 那么dp[i]的递推式只有两种情况
    • s[i] == ')' && s[i-1] == '(',则dp[i] = dp[i-2] + 2
    • s[i] == ')' && s[i-1] == ')' && s[i-dp[i-1]-1] == '(',则dp[i] = dp[i-1] +dp[i-dp[i-1]-2] + 2
    • 当然要注意检查数组是否越界
    • 从左至右遍历,每一次用dp[i]更新最大值
  • 复杂度:
    • 时间:遍历一遍即可得出所有值, O ( n ) O(n) O(n)
    • 空间:用dp数组储存, O ( n ) O(n) O(n)

方法三:计算左右括号

  • 从左至右和从右至左分别遍历
  • 如果遇到左括号,left++,右括号,right++,如果right > left,清零
  • 每一次迭代,如果left == right,更新最大值
  • 需要两个方向的遍历原因是为了计算类似(((()的情况
  • 复杂度:
    • 时间: O ( n ) O(n) O(n)
    • 空间:仅leftright,为 O ( 1 ) O(1) O(1)

代码实现

方法一:暴力枚举

TLE

class Solution {
public:
    int longestValidParentheses(string s) {
        int len = s.size();
        int res = 0;
        for(int i = 2; i <= len; i++){
            for(int j = 0; j <= len - i; j++){
                if(verifyString(s.substr(j, i))){
                    res = i;
                    break;
                }
            }
        }
        return res;
    }
    bool verifyString(string a){
        int len = a.size();
        stack <int> s;
        for(int i = 0; i < len; i++){
            if(a[i] == '(')
            s.push(1);
            else{
                if(!s.empty())
                    s.pop();
                else
                    return false;
            }
        }
        return s.empty();
    }
};

方法二:动态规划

AC 超过61.92%的cpp程序

class Solution {
public:
    int longestValidParentheses(string s) {
        int len = s.size();
        if(len < 2)
        return 0;
        int* dp = new int[len];
        int res = 0;
        for(int i = 0; i < len; i++){
            dp[i] = 0;
        }
        for(int i = 1; i < len; i++){
            if(s[i] == ')' && s[i-1] == '('){
                dp[i] = ((i-2 >= 0) ?dp[i-2] : 0) + 2;
            }
            else if(s[i] == ')' && s[i-1] == ')'){
                if(i - dp[i-1] - 1 >= 0 && s[i-dp[i-1]-1] == '('){
                    dp[i] = dp[i-1] + ((i-dp[i-1]-2 >= 0) ? dp[i-dp[i-1]-2]:0) + 2;
                }
            }
            res = max(res, dp[i]);
        }
        return res;
    }
};

方法三:计算左右括号

AC 超过99.93%的cpp程序

class Solution {
public: 
    int longestValidParentheses(string s) {
        int left = 0, right = 0, maxlength = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s[i] == '(') {
                left++;
            } else {
                right++;
            }
            if (left == right) {
                maxlength = max(maxlength, 2 * right);
            } else if (right >= left) {
                left = right = 0;
            }
        }
        left = right = 0;
        for (int i = s.length() - 1; i >= 0; i--) {
            if (s[i] == '(') {
                left++;
            } else {
                right++;
            }
            if (left == right) {
                maxlength = max(maxlength, 2 * left);
            } else if (left >= right) {
                left = right = 0;
            }
        }
        return maxlength;
    }
};
    原文作者:算法
    原文地址: https://www.twblogs.net/a/5bd3ac2f2b717778ac20ad5f
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞