1. 程式人生 > >LeetCode 32. Longest Valid Parentheses(最長有效括號)

LeetCode 32. Longest Valid Parentheses(最長有效括號)

原題

Given a string containing just the characters ‘(’ and ‘)’, find the length of the longest valid (well-formed) parentheses substring.

題目: 給定一個只包含字元 “(’ 和 ')” 的字串, 查詢最長的有效 (格式正確) 圓括號子字串的長度。

Example 1:

Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"

Example 2:

Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"

My Solution

方案一(錯誤)

class Solution_four:
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        if len(s) <= 1:
            return 0
        res = 0

        list_s = list(s)
        while True:
            mark =
True for i in range(1, len(list_s)): if list_s[i - 1] == '(' and list_s[i] == ')': res += 1 # list_s.pop(i - 1) # list_s.pop(i) del list_s[i], list_s[i-1] mark = False break
else: pass if mark: break return res
  • 忽略了()(()情況,即只考慮了有多少個()沒有考慮有效性,所以得出上面這種情況為2,但實際應該為1;
  • list刪除元素有三種方式,remove(), del, pop(),其中pop的引數為列表索引值,每次只能pop一個;而del直接這對list元素,後可接多個;
  • 上述程式碼之所以將刪除方式由pop轉換為del,是因為list_s.pop(i - 1)之後,list_s的長度減1,造成list_s.pop(i)已經不再是自己當初所設想的i-1之後的第i個元素了(因為list_s長度發生了變化),並且這種方式很容易造成列表索引超出範圍(事實上,自己在這個地方卡了不少時間找原因);
  • 上述程式碼之所以在mark = False之後加上了break,是為了讓其跳出for迴圈,重新讓i從1開始取值;自己之前曾嘗試直接賦值i = 1,但事實證明這種方式並不能影響for迴圈中i的變化,for迴圈的中的i的取值不會隨著for迴圈中list_s長度變化而變化;(這點要尤其注意)

方案二(錯誤)

class Solution:
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s:
            return 0
        if len(s) <= 1:
            return 0
        count = count_left = count_right = 0
        mark_list = ['(']
        mark_start = False
        left_index = {}
        right_index = {}
        res = 0
        for i in range(1, len(list_s)):
           if s[i] == '(':
                count_left += 1
                count += 1
                mark_start = True
                left_index[count_left] = i
            if s[i] == ')' and mark_start:
                count_right += 1
                count -= 1
                right_index[count_right] = i
         
        if count_left == 0 or count_right == 0:
            return 0
        if count_left <= count_right:
            res = s[left_index[1]:right_index[count_left]+1]
        else:
            res = s[left_index[count_left - count_right + 1]:right_index[count_right]+1]
        return len(res)
  • 試圖採用之前做過的查詢有效括號的做法來做,依舊是少考慮了有效性; 即忽略了()(()情況,即只考慮了有多少個()沒有考慮有效性,所以得出上面這種情況為2,但實際應該為1;

Reference solution

思路分析:

思路一 : 首先,這個題的總體思路相當於Valid Parentheses這道題的升級版。括號匹配,肯定會想到用棧,但是這道題不同的是要找到最長的有效括號子串,子串在尋找的過程中你無法確定它是不是有效。 例如()((),在當前的狀態來看是兩個有效括號,但是如果繼續往後走,有可能是()(()),這樣的話兩個有效括號就變成了一個。 因此必須能夠記錄匹配的長度變化,可以採用位置記錄。例如()((),需要同時記錄中間(的位置起始的位置0,雖然當前子串的長度判斷是通過和(位置進行差值得到的,但是一旦這個(被匹配掉,就要和起始位置來進行比較。因此,需要一個變數start來記錄有效括號的可能的最早的起始位置。

通過start來記錄起始位置,

  • 如果當前為(則將位置入棧;
  • 如果是),則判斷當前棧:
    • 如果當前棧為空,說明匹配到了一個無效括號,start從i+1的位置開始
    • 如果當前棧不空,說明需要和棧裡的(匹配融合掉,這時再看棧:
      • 如果棧為空,說明左括號全部匹配掉了,就需要用當前位置i - start + 1來更新結果值(max(res, i - start + 1)
      • 如果棧不空,說明幹掉了一個左括號,還有多餘的左括號,就將最大值更新到這個左括號的位置,即max(res, i - stack[-1] + 1)
class Solution:
    def longestValidParentheses(self, s):
        """
        :type s: str
        :rtype: int
        """
        stack = []
        res = start_index = 0 
        for i, count in enumerate(s):
            if count == '(':
                stack.append(i)    
            else:
                if not stack:
                    start_index = i+1    # invalid match
                else:
                    stack.pop()
                    if not stack:    # totally match all stack
                        res = max(res, i - start_index + 1)
                    else:
                        res = max(res, i - stack[-1])
                    
        return res

反思:

  1. 忽略了題目中有效性要求;
  2. 需要多反思自己答案一中出現錯誤的情況;
  3. 通過自己解決思路二,嘗試運用了dict型別,明白瞭如何對dict型別進行元素新增:right_index[count_right] = i
  4. 對於多重迴圈,採用for i in range(len(s))到內層迴圈會很混亂,不如採用enumerate結構,for i,count in enumerate(len(s))