[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),只使用了常數空間。


總結

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

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

留言
avatar-img
追極光的北極熊|軟體工程師的小天地
16會員
170內容數
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
看更多
你可能也想看
Thumbnail
創作不只是個人戰,在 vocus ,也可以是一場集體冒險、組隊升級。最具代表性的創作者社群「vocus 野格團」,現在有了更強大的新夥伴加入!除了大家熟悉的「官方主題沙龍」,這次我們徵召了 8 位領域各異的「個人主題專家」,將再度嘗試創作的各種可能,和格友們激發出更多未知的火花。
Thumbnail
創作不只是個人戰,在 vocus ,也可以是一場集體冒險、組隊升級。最具代表性的創作者社群「vocus 野格團」,現在有了更強大的新夥伴加入!除了大家熟悉的「官方主題沙龍」,這次我們徵召了 8 位領域各異的「個人主題專家」,將再度嘗試創作的各種可能,和格友們激發出更多未知的火花。
Thumbnail
看完上篇 4 位新成員的靈魂拷問,是不是意猶未盡?別急,野格團新血的驚喜正接著登場!今天下篇接力的另外 4 位「個人主題專家」,戰力同樣驚人──領域從旅行美食、運動、商業投資到自我成長;這些人如何維持長跑般的創作動力?在爆紅的文章背後,又藏著哪些不為人知的洞察?5 大靈魂拷問繼續出擊
Thumbnail
看完上篇 4 位新成員的靈魂拷問,是不是意猶未盡?別急,野格團新血的驚喜正接著登場!今天下篇接力的另外 4 位「個人主題專家」,戰力同樣驚人──領域從旅行美食、運動、商業投資到自我成長;這些人如何維持長跑般的創作動力?在爆紅的文章背後,又藏著哪些不為人知的洞察?5 大靈魂拷問繼續出擊
Thumbnail
題目敘述 Longest Palindromic Substring 給定一個輸入字串s,請找出最長的回文子字串。 答案可能不只一個,回傳任何一個合法的答案皆可。
Thumbnail
題目敘述 Longest Palindromic Substring 給定一個輸入字串s,請找出最長的回文子字串。 答案可能不只一個,回傳任何一個合法的答案皆可。
Thumbnail
題目敘述 題目會給定兩個輸入字串str1和str2,要求我們找出這兩個字串的最大共同子字串。 如果無解,則返回空字串""。 題目的原文敘述 測試範例 Example 1: Input: str1 = "ABCABC", str2 = "ABC" Output: "ABC" Exam
Thumbnail
題目敘述 題目會給定兩個輸入字串str1和str2,要求我們找出這兩個字串的最大共同子字串。 如果無解,則返回空字串""。 題目的原文敘述 測試範例 Example 1: Input: str1 = "ABCABC", str2 = "ABC" Output: "ABC" Exam
Thumbnail
這題也是滿經典的DP動態規劃教學案例和題目,就順便複習一下吧。 題目敘述 題目會給我們兩個字串text1, text2。 要求我們找出兩個字串的最長共同子序列,並且返回最長共同子序列的長度。 如果彼此沒有共同子序列,則返回0。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
這題也是滿經典的DP動態規劃教學案例和題目,就順便複習一下吧。 題目敘述 題目會給我們兩個字串text1, text2。 要求我們找出兩個字串的最長共同子序列,並且返回最長共同子序列的長度。 如果彼此沒有共同子序列,則返回0。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
題目會給定一個字串s,裡面都是由()*打散交錯而成。 配對規則 左括弧 ( 可以和 右括弧 ) 配對,其中 左括弧一定要在右括弧的左邊。 左括弧 ( 也可以和 *星號 配對,其中 左括弧一定要在*星號的左邊。 問我們給定的輸入字串s是否為合法括弧配對字串?
Thumbnail
題目會給定一個字串s,裡面都是由()*打散交錯而成。 配對規則 左括弧 ( 可以和 右括弧 ) 配對,其中 左括弧一定要在右括弧的左邊。 左括弧 ( 也可以和 *星號 配對,其中 左括弧一定要在*星號的左邊。 問我們給定的輸入字串s是否為合法括弧配對字串?
Thumbnail
題目會給定一個字串s,裡面都是由() [] {}打散交錯而成。 問我們給定的輸入字串s裡面,最長的合法括弧配對字串長度是多少? 例如 s = "()()" ,最長的合法括弧配對字串長度為4
Thumbnail
題目會給定一個字串s,裡面都是由() [] {}打散交錯而成。 問我們給定的輸入字串s裡面,最長的合法括弧配對字串長度是多少? 例如 s = "()()" ,最長的合法括弧配對字串長度為4
Thumbnail
題目會給定一個字串s,裡面都是由() [] {}打散交錯而成。 問我們給定的輸入字串s 是不是合法括弧自串,也就是所有的右括弧都在左括弧後面,而且可以兩兩相消。
Thumbnail
題目會給定一個字串s,裡面都是由() [] {}打散交錯而成。 問我們給定的輸入字串s 是不是合法括弧自串,也就是所有的右括弧都在左括弧後面,而且可以兩兩相消。
Thumbnail
題目會給定一個字串,問我們裡面最大的回文子字串內容為何? 本題目將用中心展開法來解題
Thumbnail
題目會給定一個字串,問我們裡面最大的回文子字串內容為何? 本題目將用中心展開法來解題
Thumbnail
題目會給定一個字串,要求我們計算,最長的不重複區間有多長? 不重複區間的定義,就是區間內的每個字元都不相同。
Thumbnail
題目會給定一個字串,要求我們計算,最長的不重複區間有多長? 不重複區間的定義,就是區間內的每個字元都不相同。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News