
嘿嘿~我們又回來啦!延續上次的 Longest Valid Parentheses 題目,這次我們要換個方式來解決。還記得上次我們用了動態規劃法嗎?
今天我們要來介紹一個超高效的解法——雙指針法!這個方法不用額外空間,只靠兩個小計數器就能快速找到最長有效括號的長度~
是不是很期待?接下來我們來介紹 方法 3:雙指針法。
雙指針法透過一次從左到右、一個從右到左的掃描,來計算最長的有效括號長度。這個方法的時間複雜度依然是 O(n),但不需要額外的空間,僅需兩個計數器,非常輕量級。
這個方法基於這樣一個觀察:在一個有效的括號序列中,左括號的數量必須等於右括號的數量,並且在任何時刻,右括號的數量不能超過左括號的數量。這為我們提供了使用雙指針掃描的可能性。
具體來說,我們會進行兩次掃描:
第一次從左到右掃描:在這個過程中,我們用兩個計數器 left 和 right 來計數左括號 ( 和右括號 ) 的數量。如果在某個時刻 left == right,那麼我們就找到了一個有效的括號序列,並記錄下它的長度。如果 right 超過了 left,說明這個時刻無法再形成有效序列,我們就重置計數器。
第二次從右到左掃描:同樣地,我們再次使用 left 和 right 進行計數,不過這次我們從右到左掃描字串,因為在有效的括號序列中,左括號的數量也不能超過右括號。
通過這兩次掃描,我們可以保證無論括號的排列方式如何,都能夠找出最長的有效子字串。
初始化計數器:
left 和 right 來計數括號。maxLength 來記錄最長有效括號的長度。第一次從左到右的掃描:
( 時,增加 left 計數;遇到右括號 ) 時,增加 right 計數。left == right 時,說明找到了一個有效的括號序列,更新 maxLength。right > left,說明右括號過多,無法再形成有效括號,重置計數器。第二次從右到左的掃描:
left == right 時,同樣更新 maxLength。left > right,說明左括號過多,無法形成有效括號,重置計數器。function longestValidParentheses(s: string): number {
let left = 0, right = 0, maxLength = 0;
// 從左到右掃描
for (let i = 0; i < s.length; i++) {
if (s[i] === '(') {
left++;
} else {
right++;
}
if (left === right) {
maxLength = Math.max(maxLength, 2 * right); // 有效括號長度是 2 * right
} else if (right > left) {
left = right = 0; // 重置計數器
}
}
// 從右到左掃描
left = right = 0;
for (let i = s.length - 1; i >= 0; i--) {
if (s[i] === ')') {
right++;
} else {
left++;
}
if (left === right) {
maxLength = Math.max(maxLength, 2 * left); // 有效括號長度是 2 * left
} else if (left > right) {
left = right = 0; // 重置計數器
}
}
return maxLength;
}
雙指針的意義:
時間與空間複雜度:
現在我們已經介紹了三種解法,讓我們來簡單比較一下這三種方法:
方法 1:堆疊法:
方法 2:動態規劃法:
dp 陣列有效追蹤每個位置的解,適合分析較複雜的括號結構。dp 陣列。方法 3:雙指針法:
今天我們學到了雙指針法這種高效的解法!通過兩次掃描字串,我們能夠在 O(n) 的時間內找到最長的有效括號長度,而且只需要常數空間,非常適合大數據量的處理。這種方法雖然不如堆疊法和動態規劃法直觀,但在追求效率時是一個很好的選擇。
希望這篇文章能幫助你掌握這種高效的解法!下次我們再來比較這三種方法的具體應用場景吧~ 💪