LeetCode 32. Longest Valid Parentheses(最長有效括號)
阿新 • • 發佈:2018-12-12
原題
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)
- 如果棧為空,說明左括號全部匹配掉了,就需要用當前位置i - start + 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
反思:
- 忽略了題目中有效性要求;
- 需要多反思自己答案一中出現錯誤的情況;
- 通過自己解決思路二,嘗試運用了dict型別,明白瞭如何對dict型別進行元素新增:
right_index[count_right] = i
- 對於多重迴圈,採用
for i in range(len(s))
到內層迴圈會很混亂,不如採用enumerate結構,for i,count in enumerate(len(s))