1. 程式人生 > >Leetcode 032 最長有效括號 思路詳解 + 反思總結 python

Leetcode 032 最長有效括號 思路詳解 + 反思總結 python

本人一直在努力地積累Leetcode上用Python實現的題,並且會盡力講清每道題的原理,絕不像其他某些部落格簡略地帶過。
如果覺得講的清楚,歡迎關注。

給定一個只包含 '(' 和 ')' 的字串,找出最長的包含有效括號的子串的長度。

示例 1:

輸入: "(()"
輸出: 2
解釋: 最長有效括號子串為 "()"

示例 2:

輸入: ")()())"
輸出: 4
解釋: 最長有效括號子串為 "()()"

思路一:棧

思路1:通過進棧出棧的方式儲存一些括號的index。這個stack,右括號想進去,只有可能是上一個stack頂部元素也是右,而第一個右括號怎麼進?只能在stack為空的時候進,而且進還必須得連續進,否則只有把最新的左括號pop出來才能進。

#以下為第一種思路,通過棧來判斷當前位置對應的括號是否符合有效長度
class Solution:
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        j = len(s)
        maxlen = 0
        #stack用來儲存的是一些括號(不一定全是左,也不一定全是右)在s中的index
        stack = []
        #遍歷index
        for i in range(j):
            #如果遇到一個右括號並且我們的stack裡有東西可以pop出來
            #並且那個即將pop出來的東西是左括號,我們就pop
            if s[i] == ')' and len(stack) != 0 and s[stack[-1]] == '(':
                a = stack.pop()
                #如果pop完剛好 stack長度為0,說明這種情況是那種完全對稱形的並且剛好結束一次有效括號的排列
                #則我們需要計算此時的maxlen
                if len(stack) == 0:
                    maxlen = i + 1
                #如果還有剩下的括號,我們則更新此時的最長長度
                else:
                    maxlen = max(maxlen, i - stack[-1])

            else:
                stack.append(i)

        return maxlen

但是這種寫法有點不明晰,來看看比較清楚的一種

思路:只在遇到左括號時放入棧中。這題是valid parentheses的擴充套件,也可以利用棧結構來實現。這裡我們用棧存放左括號的下標,遇到左括號,將其下標存入棧中。遇到右括號,若此時棧為空,說明這個不是有效括號對裡的,跳過,更新有效括號的起始點;若是棧不為空,則棧頂元素出棧。此時,若棧為空,後面不一定沒有接合法的有效括號對,所以,計算當前和有效括號起始點的距離,並更新最大值,如:()();若不為空,用當前位置距離棧頂元素的距離和maxlen中的最大值更新maxlen,如:()(()()。參考了Grandyang的部落格。



class Solution:
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        tl = len(s)
        stack = []
        st = 0
        maxlen = 0
        for i in range(tl):
            #如果是左括號,直接入stack
            if s[i] == '(':
                stack.append(i)
            #如果右括號
            else:
                #如果stack裡沒有元素匹對,說明有效括號已經結束,更新起始位置
                if len(stack) == 0:
                    st = i+1
                    continue
                #有元素匹對
                else:
                    a = stack.pop()
                    #pop出一個左括號匹對
                    #如果此時沒了,不能保證不繼續有效括號,所以根據當前的最長距離去更新maxlen
                    if len(stack) == 0:
                        maxlen = max(i - st+1, maxlen)
                    #如果此時還有 則計算與棧頂的索引相減來計算長度
                    else:
                        maxlen = max(i-stack[-1], maxlen)

        return maxlen

思路二:動態規劃

這題還能使用動態規劃的方式解:

dp[i]為到i處最長的有效括號,如果s[i]為左括號,則dp[i]為0,因為若字串是以左括號結束,則不可能為有效的;若是為右括號,有兩種情況:

一:其前者s[i-1]為左括號,所以dp[i]=dp[i-2]+2;

二、s[i-1]為右括號且s[i-dp[i-1]-1]為左括號,所以 dp[i] = dp[i-1] + 2 + dp[i-dp[i-1]-2],其中i-dp[i-1]-1對應對應最長括號的起始點

LeetCode OJ程式碼如下:


classSolution:deflongestValidParentheses(self, s):""" :type s: str
:rtype: int """ a =len(s)if a <2:return0 maxlen =0#dp[i]表示剛好在s[i]以前(包括s[i]在內)的最長括號長度#如果s[i] = '(', dp[i] = 0 dp = [0for _ inrange(a)]for i inrange(1, a):#當前i的對稱點的索引 pos = i -1-dp[i-1]if s[i]==')'and s[i-1] =='('and i -2>=0:#等於前前項的最長長度+2 dp[i] = dp[i-2] +2elif s[i] ==')'and pos >=0and s[pos] =='(':#等於上個對稱點+2 dp[i] = dp[i-1] +2if pos -1>=0:#如果對稱點前還有長度,則加上那段長度 dp[i] += dp[i-dp[i-1]-2]returnmax(dp)