您好,登錄后才能下訂單哦!
今天小編給大家分享一下C++怎么實現最長有效括號的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
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 "()()"
這道求最長有效括號比之前那道 Valid Parentheses 難度要大一些,這里還是借助棧來求解,需要定義個 start 變量來記錄合法括號串的起始位置,遍歷字符串,如果遇到左括號,則將當前下標壓入棧,如果遇到右括號,如果當前棧為空,則將下一個坐標位置記錄到 start,如果棧不為空,則將棧頂元素取出,此時若棧為空,則更新結果和 i - start + 1 中的較大值,否則更新結果和 i - st.top() 中的較大值,參見代碼如下:
解法一:
class Solution { public: int longestValidParentheses(string s) { int res = 0, start = 0, n = s.size(); stack<int> st; for (int i = 0; i < n; ++i) { if (s[i] == "(") st.push(i); else if (s[i] == ")") { if (st.empty()) start = i + 1; else { st.pop(); res = st.empty() ? max(res, i - start + 1) : max(res, i - st.top()); } } } return res; } };
還有一種利用動態規劃 Dynamic Programming 的解法。這里使用一個一維 dp 數組,其中 dp[i] 表示以 s[i-1] 結尾的最長有效括號長度(注意這里沒有對應 s[i],是為了避免取 dp[i-1] 時越界從而讓 dp 數組的長度加了1),s[i-1] 此時必須是有效括號的一部分,那么只要 dp[i] 為正數的話,說明 s[i-1] 一定是右括號,因為有效括號必須是閉合的。當括號有重合時,比如 "(())",會出現多個右括號相連,此時更新最外邊的右括號的 dp[i] 時是需要前一個右括號的值 dp[i-1],因為假如 dp[i-1] 為正數,說明此位置往前 dp[i-1] 個字符組成的子串都是合法的子串,需要再看前面一個位置,假如是左括號,說明在 dp[i-1] 的基礎上又增加了一個合法的括號,所以長度加上2。但此時還可能出現的情況是,前面的左括號前面還有合法括號,比如 "()(())",此時更新最后面的右括號的時候,知道第二個右括號的 dp 值是2,那么最后一個右括號的 dp 值不僅是第二個括號的 dp 值再加2,還可以連到第一個右括號的 dp 值,整個最長的有效括號長度是6。所以在更新當前右括號的 dp 值時,首先要計算出第一個右括號的位置,通過 i-3-dp[i-1] 來獲得,由于這里定義的 dp[i] 對應的是字符 s[i-1],所以需要再加1,變成 j = i-2-dp[i-1],這樣若當前字符 s[i-1] 是左括號,或者j小于0(說明沒有對應的左括號),或者 s[j] 是右括號,此時將 dp[i] 重置為0,否則就用 dp[i-1] + 2 + dp[j] 來更新 dp[i]。這里由于進行了 padding,可能對應關系會比較暈,大家可以自行帶個例子一步一步執行,應該是不難理解的,參見代碼如下:
解法二:
class Solution { public: int longestValidParentheses(string s) { int res = 0, n = s.size(); vector<int> dp(n + 1); for (int i = 1; i <= n; ++i) { int j = i - 2 - dp[i - 1]; if (s[i - 1] == "(" || j < 0 || s[j] == ")") { dp[i] = 0; } else { dp[i] = dp[i - 1] + 2 + dp[j]; res = max(res, dp[i]); } } return res; } };
此題還有一種不用額外空間的解法,使用了兩個變量 left 和 right,分別用來記錄到當前位置時左括號和右括號的出現次數,當遇到左括號時,left 自增1,右括號時 right 自增1。對于最長有效的括號的子串,一定是左括號等于右括號的情況,此時就可以更新結果 res 了,一旦右括號數量超過左括號數量了,說明當前位置不能組成合法括號子串,left 和 right 重置為0。但是對于這種情況 "(()" 時,在遍歷結束時左右子括號數都不相等,此時沒法更新結果 res,但其實正確答案是2,怎么處理這種情況呢?答案是再反向遍歷一遍,采取類似的機制,稍有不同的是此時若 left 大于 right 了,則重置0,這樣就可以 cover 所有的情況了,參見代碼如下:
解法三:
class Solution { public: int longestValidParentheses(string s) { int res = 0, left = 0, right = 0, n = s.size(); for (int i = 0; i < n; ++i) { (s[i] == "(") ? ++left : ++right; if (left == right) res = max(res, 2 * right); else if (right > left) left = right = 0; } left = right = 0; for (int i = n - 1; i >= 0; --i) { (s[i] == "(") ? ++left : ++right; if (left == right) res = max(res, 2 * left); else if (left > right) left = right = 0; } return res; } };
以上就是“C++怎么實現最長有效括號”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。