在解longestValidParentheses的時候一開始思路是這樣

由於"()"一直失敗所以問AI
他跟我說你的原始程式碼出問題,不是「語法錯」而是方法論本質錯。
而我幫你做的那個 two-pass 左右掃描法,是一個完全不同的演算法,雖然乍看和你的「左右指針」很像,但本質完全不是同一回事。
下面我用超清楚的方式告訴你:
🔥 你原本的程式碼的核心邏輯(錯誤根源)
你的邏輯是這樣:
- 左指針從左找第一個
'(' - 右指針從右找第一個
')' - 找到後就直接回傳中間的長度
也就是這段:
if s[l] == "(" and s[r] == ")":
return len(s[l:r])
❌ 問題 1:切片不包含 r
"()" → s[0:1] = "(" → 長度 = 1
而答案應該是 2
❌ 問題 2:這個方法根本不會檢查「中間是否合法」
例如:
s = "())(()"
你只是在找最外層的 ( 和 )
但是 longest valid 在中間,不在外層。
也就是:
你的方法是在找:
( )
^ ^
l r
然而題目要的其實是:
()()
兩者邏輯完全不同。
❌ 問題 3:你只找一次就 return
所以你 永遠只能找到一段,而且一定是最外面那段
但最外層常常是「不合法的」。
⭐ 那我到底「做了什麼」讓它能過?
我用了一個叫做:
👉 Two-Pass Scan(左右掃描平衡法)
這個方法的核心思想是:
✔ 用 left 計算 ( 數量
✔ 用 right 計算 ) 數量
✔ 當 left == right 時,表示這一段是合法的
✔ 當 right > left(或反方向 left > right)代表這一段無效,重置
🔥 用圖解讓你看差異
假設 s = "(()())"
你的方法:
找最外層 → 直接 return "(()())" → 其實這裡竟然是合法的,但如果外層不合法就慘了。
而且你用 slicing 會漏掉右邊字元。
我的方法:
左→右掃描:
每看到一個 '(' 就 +1
每看到一個 ')' 就 +1 只要數字平衡,就表示是一段 valid:
( ( ) ( ) )
1 2 1 2 1 2
每次 numbers 平衡 → 更新答案
但左→右有個問題:
像 ")()())" 開頭多一個 ) → 就會破壞計算。
所以:
再右→左掃描:
同樣計算 balance,但反過來保證:
)))((()))
這種左多的也能處理。
🌟 本質上的差異:
❌ 你的方法是假設「最外層配對成功 → 中間就一定合法」
這是不成立的。
就像:
( ) <-- 外層配對成功
) ( <-- 中間其實是亂的
✔ 我的 two-pass 方法是在檢查「每一段是否平衡」,不是只看外層。
這才是真正能 AC 的邏輯。
🎯 你真正學到的點
你的方法錯在:
- 「夾左右」這個策略 不會產生有效括號 substring 的長度
- 無法處理 nested / broken / segmented cases
- slicing 會漏掉末端字元
- 只配一次外層就 return → 根本不是在找 longest
我做的是:
- 使用計數平衡(balance counting)
- 左掃描一次,右掃描一次
- 檢查所有可能的有效段落
- 更新最長合法區間
所以最後答案是


✅ 時間複雜度:O(n)
程式掃描字串兩次:
- 左 → 右 一次 O(n)
- 右 → 左 一次 O(n)
加起來:
O(n) + O(n) = O(n)
沒有巢狀迴圈,也沒有額外扫描。
最終時間複雜度 = O(n)
✅ 空間複雜度:O(1)
整段程式使用的變數:
left
right
ans
c(迴圈變數)
都是 固定數量 的整數,而且不會依字串長度增加。
也沒有 stack、array、dictionary。
因此:
空間複雜度 = O(1)(常數空間)





class Solution:
def longestValidParentheses(self, s: str) -> int:
left = right = 0
ans = 0
# 左到右
for c in s:
if c == '(':
left += 1
else:
right += 1
if left == right:
ans = max(ans, 2 * left)
elif right > left:
left = right = 0
left = right = 0
# 右到左
for c in reversed(s):
if c == ')':
right += 1
else:
left += 1
if left == right:
ans = max(ans, 2 * left)
elif left > right:
left = right = 0
return ans






