LeetCode 32 最長有效括號

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)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

總結

這道題主要還是總結以下動態規劃部分,動態規劃的思考還是沒有搞出來。看完題解覺得思路倒是不難,但是後面編碼的時候,提交了好幾次都不對。總是發現有錯誤,上面代碼中註釋也提及到了注意的問題所在。這道題還是可以重新多做幾遍的。

發佈了53 篇原創文章 · 獲贊 9 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章