32. 最長有效括號
題目來源:力扣(LeetCode)https://leetcode-cn.com/problems/longest-valid-parenthesespython
題目
給定一個只包含 '(' 和 ')' 的字符串,找出最長的包含有效括號的子串的長度。bash
示例 1:微信
輸入: "(()" 輸出: 2 解釋: 最長有效括號子串爲 "()"
示例 2:app
輸入: ")()())" 輸出: 4 解釋: 最長有效括號子串爲 "()()"
解題思路
思路:棧優化
題目中,要查找有效括號,有可能須要從內往外擴展,這符合棧先入後出的特性。code
咱們先使用暴力解,來嘗試解決這個問題。blog
有效的括號是成對出現的,那麼咱們嘗試羅列全部可能的非空偶數長度子字符串,判斷其是否有效。索引
當咱們遇到左括號 (
時,咱們將它入棧。當遇到右括號 )
時,從棧中彈出一個左括號 (
,若是棧中沒有了左括號,或者遍歷完成後棧中還保留有元素,那麼這個子字符串就是無效的。循環遍歷,更新最大的長度。具體的代碼以下:leetcode
def longestValidParentheses(self, s: str) -> int: def is_valid(s): stack = [] for i in range(len(s)): if s[i] == '(': stack.append('(') elif stack and stack[-1] == '(': stack.pop() else: return False return not stack max_len = 0 for i in range(len(s)): for j in range(i+2, len(s)+1, 2): if is_valid(s[i:j]): max_len = max(max_len, j-i) return max_len
可是這裏最終的執行結果是超時。由於咱們的方法是從字符串中羅列出全部可能的非空偶數子字符串,這裏須要的時間複雜度爲 O(n^2)
。字符串
在這裏,咱們嘗試進行優化。
上面的暴力解法,是要先羅列全部可能的子字符串。在這裏,咱們直接在遍歷的過程當中去判斷所遍歷的子字符串的有效性,同時維護最大的長度。
這裏有個須要注意的地方,開始的時候,須要先將 -1
壓入棧中(後面解釋)。具體實現的方法以下:
- 當遇到
(
時,將其索引壓入棧中; - 當遇到
)
時,彈出棧頂元素,計算有效長度,循環遍歷,維護最大的長度。
第二步中,計算有效長度。這裏直接用當前遍歷的字符索引減去棧頂元素的索引。此時的棧頂索引對應的是:有效子字符串的前一位字符的索引值,用示例 1 來解釋下:
"(()"
按照前面的方法,實現的過程以下(stack 表示棧,i 爲遍歷時的索引值):
- 先將
-1
壓入棧中,那麼stack = [-1]
。 - 開始遍歷,先遇到
(
,索引壓入棧中,stack = [-1, 0], i = 0
; - 繼續遍歷,仍是
(
,索引入棧,stack=[-1, 0, 1], i = 1
; - 最後,遇到的是
)
,將棧頂元素出棧,stack=[-1, 0], i = 2
,這個時候,計算最大有效長度:當前字符索引減去棧頂元素的索引,也就是len = 2-0
。此時這個棧頂元素 0,就是最開始的(
第一個左括號對應的索引。
至於爲何要先將 -1
壓入棧中,這裏舉例解釋下:
"()"
若是遇到的是這樣的字符串,那麼按照上面的實現過程,當遍歷結束後,棧是空。那麼計算最大有效長度便會出錯。若是事先將 -1
壓入棧中,那麼此時棧中的元素爲 stack=[-1]
,那麼這裏能夠計算出結果。
再舉一個例子:
")()"
在這個字符串中,若是先遇到的是 )
,那麼須要先進行出棧操做,這裏若是棧中沒有元素,這裏一樣會報錯。
具體的實現代碼以下。
代碼實現
class Solution: def longestValidParentheses(self, s: str) -> int: max_len = 0 stack = [] # 當先遇到 `)` 須要先彈出元素,這裏能夠防止報錯 # 當遇到的 `()` 的字符時,-1 在計算長度的時候,發揮做用 stack.append(-1) for i in range(len(s)): if s[i] == '(': stack.append(i) else: stack.pop() if not stack: stack.append(i) else: max_len = max(max_len, i - stack[-1]) return max_len
實現結果
總結
- 由於要找出有效的括號,有可能會遇到括號由內往外擴展,這跟棧先入後出的特性類似,能夠考慮使用棧的方法來解決;
- 首先使用暴力解的方法嘗試解決問題,在這裏,羅列出全部非空偶數子字符串,檢查他的有效性,統計最大的有效長度(可是執行以後發現超時)
- 這裏對暴力解進行優化,不使用羅列的方法。直接在遍歷字符串的時候,檢查遍歷掃描的子字符串是否有效同時計算有效長度,具體的作法以下:
- 先將
-1
壓入棧中(具體的緣由前面已分析) - 當遇到
(
時,將其索引壓入棧中, - 當遇到
)
時,出棧,計算有效長度(用當前遍歷的字符索引減去此時棧頂元素)。 - 循環遍歷,獲得最大的有效長度。
- 先將
文章原創,若是以爲寫得還能夠,歡迎關注點贊。微信公衆號《書所集錄》同步更新,一樣歡迎關注點贊。