LeetCode-32 最長有效括號
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/longest-valid-parentheses
題目描述
給你一個只包含 '(' 和 ')' 的字串,找出最長有效(格式正確且連續)括號子串的長度。
示例 1:
輸入:s = "(()"
輸出:2
解釋:最長有效括號子串是 "()"
示例 2:
輸入:s = ")()())"
輸出:4
解釋:最長有效括號子串是 "()()"
示例 3:
輸入:s = ""
輸出:0
提示:
0 <= s.length <= 3 * 104
s[i] 為 '(' 或 ')'
解題思路
本題有三種解法,分別是動態規劃法,棧法和兩次遍歷法。
動態規劃法比較難想,我們使用一個dp陣列來記錄有效括號的長度,對於“(”來說,可以形成的有效括號總為0,因為需要有右括號才能形成有效括號。對於“)”來說,需要考慮三個部分,首先是對於第i個位置的右括號,需要判斷第i - dp[i - 1] - 1的位置是否為左括號,如果不是左括號,那麼就無法構成有效括號,dp[i] = 0,如果是,則有效括號長度可以+2,這個時候考慮第i個括號內部的長度,所以dp[i] += dp[i - 1],最後,我們還得考慮第i個括號對應的左括號前面有效括號的長度,所以dp[i] += dp[i - dp[i - 1] - 1],所以,遞推公式為dp[i] = dp[i - dp[i - 1] - 1] + dp[i - 1] + 2(假設三個部分都為有效括號)
棧法和括號匹配的棧方法規則不太一樣,提前將棧加入-1,方便邊界處理,對於"("來說,入棧就可以了,對於")"來說,如果棧頂元素是-1或者是")"那麼這個右括號是無效的括號直接入棧,如果棧頂元素是"("那麼直接將棧頂出棧,這個右括號對應的最長有效括號長度就為這個右括號的下標減去了現在的棧頂元素。
雙向遍歷法其實才是剛剛開始想到的一個,只不過剛剛開始只想到了單向遍歷,可以使用left 和right同時記錄左右括號的個數,如果left = right 說明是有效括號,將其長度與最長長度比較並記錄,如果left < right說明當前括號非法,將left與right全部置0,但是有個問題是這種方法容易漏掉"(()"這種情況,在這種情況下,left和right永遠不能相等,這個時候可以從右往左再來一次遍歷,操作方法和之前遍歷類似,那麼從右往左的遍歷將漏掉"())"的情況,將兩種遍歷結合起來,就可以覆蓋所有情況了。
程式碼展示
動態規劃法:
class Solution { public: int longestValidParentheses(string s) { vector<int> dp(s.size(), 0); if(s.size() == 0) return 0; int Max = 0; for (int i = 0; i < s.size(); i++) { if (s[i] == '(') { dp[i] = 0; } else { if (i - 1 >= 0) { if(s[i - 1] == '(') { dp[i] = (i - 2 >= 0 ? dp[i - 2] : 0) + 2; } else { if(i - dp[i - 1] - 1 >= 0 && s[i - dp[i - 1] - 1] == '(') dp[i] = (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0 ) + dp[i - 1] + 2; else dp[i] = 0; } } } } for (auto iter : dp) Max = max(Max, iter); return Max; } };
棧法:
class Solution { public: int longestValidParentheses(string s) { stack<int> siStack; int iMax = 0; siStack.push(-1); for(int i = 0; i < s.size(); i++) { if(s[i] == '(') { siStack.push(i); } else { int top = siStack.top(); if(top == -1 || s[top] == ')') siStack.push(i); else { siStack.pop(); int iCount = i - siStack.top(); if(iCount > iMax) iMax = iCount; } } } return iMax; } };
兩次遍歷法:
class Solution { public: int longestValidParentheses(string s) { int iMax = 0; int left = 0, right = 0; for(int i = 0; i < s.size(); i++) { if(s[i] == '(') left++; else { right++; if(left < right) { left = 0; right = 0; } else if(left == right) { if(2* right > iMax) iMax = 2* right; } } } left = right = 0; for(int i = s.size() - 1; i >= 0; i--) { if(s[i] == ')') right++; else { left++; if(left > right) { left = 0; right = 0; } else if(left == right) { if(2* left > iMax) iMax = 2* left; } } } return iMax; } };
執行結果