[LeetCode解題攻略] 32. Longest Valid Parentheses

更新於 發佈於 閱讀時間約 8 分鐘

題目描述

給定一個只包含 '(' 和 ')' 的字串,找出其中包含的最長的有效括號子字串的長度。

範例1:

Input: s = "(()"
Output: 2
Explanation: 最長的有效括號子字串是 "()",長度為 2

範例2:

Input: s = ")()())"
Output: 4
Explanation: 最長的有效括號子字串是 "()()",長度為 4

範例3:

Input: s = ""
Output: 0


解法一:使用堆疊 (Stack)

我們可以使用堆疊來追蹤括號的索引。堆疊的初始狀態是放入一個基準值 -1,用來計算有效括號的長度。

步驟

  1. 初始化一個空堆疊,並放入基準值 -1
  2. 遍歷字串的每個字符:
    • 如果是左括號 (,將其索引推入堆疊。
    • 如果是右括號 )
      • 從堆疊彈出一個元素(匹配到最近的左括號)。
      • 如果堆疊為空,將當前索引推入堆疊作為新的基準。
      • 如果堆疊不為空,計算當前索引與堆疊頂部索引之間的距離,更新最長有效括號長度。

程式碼實現

class Solution:
def longestValidParentheses(self, s: str) -> int:
stack = [-1]
max_length = 0

for i, char in enumerate(s):
if char == '(': # 左括號
stack.append(i)
else: # 右括號
stack.pop()
if not stack: # 如果堆疊為空,更新基準索引
stack.append(i)
else: # 計算當前有效括號長度
max_length = max(max_length, i - stack[-1])

return max_length

時間與空間複雜度

  • 時間複雜度: O(n),其中 n 是字串的長度。我們只需遍歷字串一次。
  • 空間複雜度: O(n),在最壞情況下堆疊可能存儲所有索引。


解法二:動態規劃 (Dynamic Programming)

動態規劃的思路是使用一個陣列 dp,其中 dp[i] 表示以下標 i 為結尾的最長有效括號的長度。

步驟

  1. 初始化一個長度為 n 的陣列 dp,所有元素初始為 0
  2. 遍歷字串從第二個字符開始:
    • 如果當前字符是右括號 ),檢查其前一字符:
      • 如果前一字符是左括號 (,則 dp[i] = dp[i-2] + 2。
      • 如果前一字符是右括號,且在其有效括號前一位 i - dp[i-1] - 1 是左括號,則 dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2。
  3. 返回 dp 陣列中的最大值。

程式碼實現

class Solution:
def longestValidParentheses(self, s: str) -> int:
n = len(s)
if n == 0:
return 0

dp = [0] * n
max_length = 0

for i in range(1, n):
if s[i] == ')':
if s[i-1] == '(':
dp[i] = dp[i-2] + 2 if i >= 2 else 2
elif i - dp[i-1] - 1 >= 0 and s[i - dp[i-1] - 1] == '(':
dp[i] = dp[i-1] + (dp[i-dp[i-1]-2] if i-dp[i-1]-2 >= 0 else 0) + 2
max_length = max(max_length, dp[i])

return max_length

時間與空間複雜度

  • 時間複雜度: O(n),我們只需遍歷字串一次。
  • 空間複雜度: O(n),需要存儲長度為 n 的 dp 陣列。


解法三:雙指針法 (Two Pointers)

我們可以使用雙指針分別從左到右和從右到左遍歷字串,計算有效括號的長度。

步驟

  1. 初始化兩個計數器 leftright,分別計算左括號和右括號的數量。
  2. 從左到右遍歷:
    • 遇到左括號 (,增加 left
    • 遇到右括號 ),增加 right
    • 如果 left == right,計算當前有效括號長度。
    • 如果 right > left,重置計數器。
  3. 從右到左遍歷,類似操作,交換 leftright 的計算順序。

程式碼實現

class Solution:
def longestValidParentheses(self, s: str) -> int:
left = right = max_length = 0

# 從左到右遍歷
for char in s:
if char == '(':
left += 1
else:
right += 1
if left == right:
max_length = max(max_length, 2 * right)
elif right > left:
left = right = 0

left = right = 0

# 從右到左遍歷
for char in reversed(s):
if char == ')':
right += 1
else:
left += 1
if left == right:
max_length = max(max_length, 2 * left)
elif left > right:
left = right = 0

return max_length

時間與空間複雜度

  • 時間複雜度: O(n),需要兩次遍歷字串。
  • 空間複雜度: O(1),只使用了常數空間。


總結

  • 堆疊法: 簡單直接,適合理解括號匹配的邏輯。
  • 動態規劃: 使用額外的記憶體來存儲中間結果,計算最長有效括號。
  • 雙指針法: 常數空間解法,效率較高。

根據實際需求選擇合適的解法。如果需要處理長度較大的字串且對空間要求較高,雙指針法是最佳選擇。

歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
實現一個函數來重新排列數字序列,使其成為下一個更大的排列。如果不存在更大的排列,則將其排列為最小的順序(即升序)。 這個排列必須是 "原地" 完成,也就是說,只能使用常數級額外空間。
給定一個字符串 s 和一個由多個單詞組成的列表 words,請找出所有能夠在字符串 s 中連續拼接所有單詞的子字符串的起始索引。
實作一個函數 divide(dividend, divisor),計算兩個整數 dividend 和 divisor 的商,並返回其結果。
實作一個函數 strStr(haystack, needle),用來找出字串 needle 在字串 haystack 中第一次出現的索引。如果 needle 不是 haystack 的一部分,則返回 -1。
給定一個整數數組 nums 和一個值 val,需要就地刪除數組中所有等於 val 的元素,並返回刪除後數組的新長度。 要求在 O(1) 額外空間內完成操作,並且元素的相對順序不需要保持一致。
給定一個按非降序排序的整數數組 nums,就地刪除重複項,使得每個元素只出現一次。元素的相對順序應保持相同。然後傳回 nums 中唯一元素的數量。
實現一個函數來重新排列數字序列,使其成為下一個更大的排列。如果不存在更大的排列,則將其排列為最小的順序(即升序)。 這個排列必須是 "原地" 完成,也就是說,只能使用常數級額外空間。
給定一個字符串 s 和一個由多個單詞組成的列表 words,請找出所有能夠在字符串 s 中連續拼接所有單詞的子字符串的起始索引。
實作一個函數 divide(dividend, divisor),計算兩個整數 dividend 和 divisor 的商,並返回其結果。
實作一個函數 strStr(haystack, needle),用來找出字串 needle 在字串 haystack 中第一次出現的索引。如果 needle 不是 haystack 的一部分,則返回 -1。
給定一個整數數組 nums 和一個值 val,需要就地刪除數組中所有等於 val 的元素,並返回刪除後數組的新長度。 要求在 O(1) 額外空間內完成操作,並且元素的相對順序不需要保持一致。
給定一個按非降序排序的整數數組 nums,就地刪除重複項,使得每個元素只出現一次。元素的相對順序應保持相同。然後傳回 nums 中唯一元素的數量。
你可能也想看
Google News 追蹤
Thumbnail
題目敘述 Longest Palindromic Substring 給定一個輸入字串s,請找出最長的回文子字串。 答案可能不只一個,回傳任何一個合法的答案皆可。
Thumbnail
給定一個字串s,以s擁有的字元製造迴文字串。要能製造出的迴文字串長度最長是多少,觀察迴文字串不外乎兩種模式對稱部分 + 核心字元 + 對稱部分,其中,核心字元在正中央出現一次,或者 對稱部分 + 對稱部分。使用演算法統計出現次數並推理出盡可能充分利用每個字元的迴文字串製造方法。
Thumbnail
Append Characters to String to Make Subsequence 給定兩個字串s和字串t。 請計算最少的字元串接數量是多少,串接在s的尾端,使得t是s的子序列。 測試範例 Example 1: Input: s = "coaching", t =
Thumbnail
題目敘述 題目會給定一個輸入字串s和一套編碼規則,要求我們針對字串s進行解碼,並且以字串的形式返回答案。 編碼規則: 數字[字串] -> []內的字串以對應倍數做展開,而且允許巢狀編碼。 例如: 3[a] 解碼完就是 aaa 2[bc] 解碼完就是 bcbc 2[a2[b]] = 2
Thumbnail
題目敘述 題目會給定一個字串s,和指定長度k,問我們包含母音的子字串中,母音數量的最大值是多少? 題目的原文敘述 測試範例 Example 1: Input: s = "abciiidef", k = 3 Output: 3 Explanation: The substring "iii
Thumbnail
題目敘述 題目會給定兩個輸入字串str1和str2,要求我們找出這兩個字串的最大共同子字串。 如果無解,則返回空字串""。 題目的原文敘述 測試範例 Example 1: Input: str1 = "ABCABC", str2 = "ABC" Output: "ABC" Exam
Thumbnail
題目敘述 題目會給定我們兩個輸入字串word1, word2,要求我們依照word1,word2,word1,word2, ... 交叉前進的方式,合併兩個字串,作為輸出。 題目的原文敘述 測試範例 Example 1: Input: word1 = "abc", word2 = "pq
Thumbnail
這題也是滿經典的DP動態規劃教學案例和題目,就順便複習一下吧。 題目敘述 題目會給我們兩個字串text1, text2。 要求我們找出兩個字串的最長共同子序列,並且返回最長共同子序列的長度。 如果彼此沒有共同子序列,則返回0。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
題目會給定一個字串s,裡面都是由() [] {}打散交錯而成。 問我們給定的輸入字串s裡面,最長的合法括弧配對字串長度是多少? 例如 s = "()()" ,最長的合法括弧配對字串長度為4
Thumbnail
題目敘述 Longest Palindromic Substring 給定一個輸入字串s,請找出最長的回文子字串。 答案可能不只一個,回傳任何一個合法的答案皆可。
Thumbnail
給定一個字串s,以s擁有的字元製造迴文字串。要能製造出的迴文字串長度最長是多少,觀察迴文字串不外乎兩種模式對稱部分 + 核心字元 + 對稱部分,其中,核心字元在正中央出現一次,或者 對稱部分 + 對稱部分。使用演算法統計出現次數並推理出盡可能充分利用每個字元的迴文字串製造方法。
Thumbnail
Append Characters to String to Make Subsequence 給定兩個字串s和字串t。 請計算最少的字元串接數量是多少,串接在s的尾端,使得t是s的子序列。 測試範例 Example 1: Input: s = "coaching", t =
Thumbnail
題目敘述 題目會給定一個輸入字串s和一套編碼規則,要求我們針對字串s進行解碼,並且以字串的形式返回答案。 編碼規則: 數字[字串] -> []內的字串以對應倍數做展開,而且允許巢狀編碼。 例如: 3[a] 解碼完就是 aaa 2[bc] 解碼完就是 bcbc 2[a2[b]] = 2
Thumbnail
題目敘述 題目會給定一個字串s,和指定長度k,問我們包含母音的子字串中,母音數量的最大值是多少? 題目的原文敘述 測試範例 Example 1: Input: s = "abciiidef", k = 3 Output: 3 Explanation: The substring "iii
Thumbnail
題目敘述 題目會給定兩個輸入字串str1和str2,要求我們找出這兩個字串的最大共同子字串。 如果無解,則返回空字串""。 題目的原文敘述 測試範例 Example 1: Input: str1 = "ABCABC", str2 = "ABC" Output: "ABC" Exam
Thumbnail
題目敘述 題目會給定我們兩個輸入字串word1, word2,要求我們依照word1,word2,word1,word2, ... 交叉前進的方式,合併兩個字串,作為輸出。 題目的原文敘述 測試範例 Example 1: Input: word1 = "abc", word2 = "pq
Thumbnail
這題也是滿經典的DP動態規劃教學案例和題目,就順便複習一下吧。 題目敘述 題目會給我們兩個字串text1, text2。 要求我們找出兩個字串的最長共同子序列,並且返回最長共同子序列的長度。 如果彼此沒有共同子序列,則返回0。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
題目會給定一個字串s,裡面都是由() [] {}打散交錯而成。 問我們給定的輸入字串s裡面,最長的合法括弧配對字串長度是多少? 例如 s = "()()" ,最長的合法括弧配對字串長度為4