LeetCode 32 最長有效括號
題目
給定一個只包含 ‘(’ 和 ‘)’ 的字符串,找出最長的包含有效括號的子串的長度。
示例 1:
輸入: “(()”
輸出: 2
解釋: 最長有效括號子串爲 “()”
示例 2:
輸入: “)()())”
輸出: 4
解釋: 最長有效括號子串爲 “()()”
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-valid-parentheses
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
分析
方法 1:暴力
算法
在這種方法中,我們考慮給定字符串中每種可能的非空偶數長度子字符串,檢查它是否是一個有效括號字符串序列。爲了檢查有效性,我們使用棧的方法。
每當我們遇到一個 \text{‘(’}‘(’ ,我們把它放在棧頂。對於遇到的每個 \text{‘)’}‘)’ ,我們從棧中彈出一個 \text{‘(’}‘(’ ,如果棧頂沒有 \text{‘(’}‘(’,或者遍歷完整個子字符串後棧中仍然有元素,那麼該子字符串是無效的。這種方法中,我們對每個偶數長度的子字符串都進行判斷,並保存目前爲止找到的最長的有效子字符串的長度。
例子:
“((())”
(( --> 無效
(( --> 無效
() --> 有效,長度爲 2
)) --> 無效
((()–> 無效
(())–> 有效,長度爲 4
最長長度爲 4
方法 2:動態規劃
算法
這個問題可以通過動態規劃解決。我們定義一個dp 數組,其中第 i 個元素表示以下標爲 i 的字符結尾的最長有效子字符串的長度。我們將 dp 數組全部初始化爲 0 。現在,很明顯有效的子字符串一定以 ‘)’ 結尾。這進一步可以得出結論:以 ‘(’ 結尾的子字符串對應的 dp 數組位置上的值必定爲 0 。所以說我們只需要更新 ‘)’ 在 dp 數組中對應位置的值。
爲了求出 dp 數組,我們每兩個字符檢查一次,如果滿足如下條件
class Solution:
def longestValidParentheses(self, s: str) -> int:
if not s:
return 0
else:
length = len(s)
ans = [0]*length # 注意這裏的元素ans[i]的含義,是包括第i個字符的最長有效字符串的長度
# 比如 “()())" 這裏的 ans[4]=0
for i in range(1, length):
if s[i] == ')':
# 那麼就往前找左括號去匹配
if s[i-1] == '(':
# ans[i] = ans[i-2]+2 臥槽,這裏一定要注意,這裏i=1不會出現數組越界的情況,
# 因爲s[-1]指向最後一個字符,所以一定要小心
if i>=2:
ans[i]=ans[i-2]+2
else:
ans[i]=2
else:
if (i-ans[i-1]) >0 and s[i-ans[i-1]-1] == '(':
if i-ans[i-1]-1 >= 2:
ans[i] = ans[i-ans[i-1]-2]+ans[i-1]+2
else:
ans[i] = ans[i-1]+2
return max(ans)
方法 4:不需要額外的空間
算法
在這種方法中,我們利用兩個計數器 leftleft 和 rightright 。首先,我們從左到右遍歷字符串,對於遇到的每個 \text{‘(’}‘(’,我們增加 leftleft 計算器,對於遇到的每個 \text{‘)’}‘)’ ,我們增加 rightright 計數器。每當 leftleft 計數器與 rightright 計數器相等時,我們計算當前有效字符串的長度,並且記錄目前爲止找到的最長子字符串。如果 rightright 計數器比 leftleft 計數器大時,我們將 leftleft 和 rightright 計數器同時變回 00 。
接下來,我們從右到左做一遍類似的工作。
public class Solution {
public int longestValidParentheses(String s) {
int left = 0, right = 0, maxlength = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
left++;
} else {
right++;
}
if (left == right) {
maxlength = Math.max(maxlength, 2 * right);
} else if (right >= left) {
left = right = 0;
}
}
left = right = 0;
for (int i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) == '(') {
left++;
} else {
right++;
}
if (left == right) {
maxlength = Math.max(maxlength, 2 * left);
} else if (left >= right) {
left = right = 0;
}
}
return maxlength;
}
}
複雜度分析
時間複雜度: O(n)O(n) 。遍歷兩遍字符串。
空間複雜度: O(1)O(1) 。僅有兩個額外的變量 leftleft 和 rightright 。
作者:LeetCode
鏈接:https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
總結
這道題主要還是總結以下動態規劃部分,動態規劃的思考還是沒有搞出來。看完題解覺得思路倒是不難,但是後面編碼的時候,提交了好幾次都不對。總是發現有錯誤,上面代碼中註釋也提及到了注意的問題所在。這道題還是可以重新多做幾遍的。