最長合法字串問題

最長合法字串問題

算法概論第八週


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(n3)O(n^3)
    • 空間:維護一個棧爲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)
    • 空間:用dp數組儲存,O(n)O(n)

方法三:計算左右括號

  • 從左至右和從右至左分別遍歷
  • 如果遇到左括號,left++,右括號,right++,如果right > left,清零
  • 每一次迭代,如果left == right,更新最大值
  • 需要兩個方向的遍歷原因是爲了計算類似(((()的情況
  • 複雜度:
    • 時間:O(n)O(n)
    • 空間:僅leftright,爲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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章