題目
給定一個只包含 '(' 和 ')' 的字符串,找出最長的包含有效括號的子串的長度(連續的長度,而不是裏面有效括號長度)。
示例 1:
輸入: "(()"
輸出: 2
解釋: 最長有效括號子串爲 "()"
示例 2:
輸入: ")()())"
輸出: 4
解釋: 最長有效括號子串爲 "()()"
思路
難點:主要有3種情況
獨立括號:(()()()
嵌套括號:(())
兩者混合:()()(())
解法1:dp
dp數組:dp[i]表示以i爲結尾的最長有效括號長
假設我們已經知道了以第i個字符爲結尾的最長有效括號個數爲 x, 那麼如果它的下一個字符(i + 1) 也能匹配上的話,結果爲 x + 2, 就不需要重複計算之前的內容了。
那麼,我們應該如何判斷下一個字符可以匹配上呢?首先,爲了能夠完成匹配,下一個字符應該是'(',它需要在前面找到一個')'。假設當前字符能夠匹配x個,我們就需要跨過這x個字符,看這x字符的前一個字符是否是'(', 如果是,那麼得到結果x + 2。
通過以上方式,我們實際上相當於已知s是一個長度爲x的有效括號匹配字符串,我們檢測它的左右是否分別爲(和), 也就是 ( s )。通過這種辦法,我們得到了嵌套的括號遞增。
此外,我們還需要考慮另一種情況,對於有效括號匹配字符串,還有可能出現 s () 這樣的字符串。所以,在檢測到有效括號字符串後,我們需要在當前長度的前一個位置查詢對應子串是否也是有效括號字符串,如果是,把兩者結果疊加在一起。
最終,我們掃描所有結果,找到最大的那個輸出。
class Solution {
public:
int longestValidParentheses(string s) {
vector<int> dp(s.size(),0);
int max_len = 0,idx;
for(int i = 1;i < s.size();i++){
if(s[i] == ')'){
// 判斷前面(()),遇到第4個括號時,判斷第一個括號是否爲(
idx = i-1-dp[i-1];
if(idx >= 0 && s[idx] == '('){
dp[i] = dp[i-1]+2;
// ()()這種情況,要累加i-dp[i]位置的最長有效括號
if(i-dp[i] >= 0) dp[i]+= dp[i-dp[i]];
}
}
max_len = max(max_len,dp[i]);
}
return max_len;
}
};
解法2:使用棧(這種思路會比較亂)
這裏使用start記錄有效括號的起始,當棧空,且輸入爲右括號時,更新起點爲右括號下標+1
使用棧去存前方有效左括號的下標
class Solution {
public:
int longestValidParentheses(string s) {
stack<int> m;
int start = 0,max_len = 0;
for(int i = 0;i < s.size();i++){
if(s[i] == '(') m.push(i);
else if(s[i] == ')'){
if(m.empty()) start = i+1;
else{
m.pop();
max_len = m.empty()? max(max_len,i-start+1): max(max_len,i-m.top());
}
}
}
return max_len;
}
};