LeetCode32-最長有效括號
阿新 • • 發佈:2018-12-08
最近這兩天有斷更了,大家知道是為什麼嗎?肯定不是因為是我懶哈(大家想要笑也要憋著)這兩天一直在研究回溯法,被折磨的死去活來的。終於是有些收穫了,所以會在這兩天再把我的一些關於解回溯法題目的心得分享出來,希望大家會有些收穫。寫的都會是很通俗易懂的大白話,會教大家怎麼寫遞迴的過程,因為回溯法雖然好用,但是如何寫出這個過程一直很麻煩,因為其抽象性比較高,很容易就被它搞糊塗了。而我這兩天在網上找的資料都是千篇一律,基本上都是把一些現貨炒來炒去,害人不淺!!!大家敬請期待我的文章。
32-最長有效括號
給定一個只包含 '(' 和 ')' 的字串,找出最長的包含有效括號的子串的長度。 示例 1: 輸入: "(()" 輸出: 2 解釋: 最長有效括號子串為 "()" 示例 2: 輸入: ")()())" 輸出: 4 解釋: 最長有效括號子串為 "()()"
這一題算是20題有效的括號進階版了,因為是要求最長的,所以我們必須是得儲存一個字串中所有有效括號的長度資訊,再從裡面選取長度最大值即可,這算是最直接的思路了。我第一次也是這樣做的。
思路:
- 首先用20題求解有效括號的方法(進棧出棧)求得給定字串中所有有效括號的成對下標值,並儲存在一List列表中。
- 因為成對括號下標可能相鄰也可能相差大於1,但是下標排序後連續且相差1的下標串對應的字串必然是合法結構,所以我只需要將1中得到的列表中的值做sort()排序操作。
- 依次檢查相鄰下標值相差為1的下標最大個數,取最大值即為所求的最長有效括號的長度
程式碼如下:
class Solution: # 本題還是採用較典型的進棧出棧法 # 字典再新增元素時key值並不是按照從小到大排列的,順序是混亂的 def longestValidParentheses(self, s): """ :type s: str :rtype: int """ if len(s) == 0 or len(s) == 1: return 0 s_list = list(s) # 定義一個字典用做棧,方便做進棧入棧操作,字典key值為括號對應的下標值,value值為相應的括號 s_queue = {0: s[0]} # 定義一個List列表用於儲存一對有效括號的兩個下標值 max_s_length = [] for s_index in range(1, len(s_list)): # 只有當元素為')'才能出棧,此時要比較棧頂元素, # 如果棧頂元素也就是s_queue[s_queue_lastkey]為'('則可以出棧,反之則不行 if len(s_queue) > 0 and s_list[s_index] == ")": # 字典再新增元素時key值並不是按照從小到大排列的,順序是混亂的,所以一定要把key值排序 # 這樣才能每次拿到s_queue字典最後一個值,也就是棧頂元素 s_queue_keys = list(s_queue.keys()) s_queue_keys.sort() s_queue_lastkey = s_queue_keys[-1] print("s_queue_lastkey", s_queue_lastkey) # 如果棧頂元素也就是s_queue[s_queue_lastkey]為'('則可以出棧 if s_queue[s_queue_lastkey] == "(": print("[s_queue_lastkey, s_index]", [s_queue_lastkey, s_index]) max_s_length.extend([s_queue_lastkey, s_index]) s_queue.pop(s_queue_lastkey) # 只有當元素為'('才能進棧,也就是s_queue字典才能儲存該key值 else: s_queue[s_index] = s_list[s_index] print("s_queue", s_queue) # 有效括號的下標值得到後排序,並對裡面相鄰的值檢查,即可得到最大長度值 # 關鍵:成對括號下標可能相鄰也可能相差大於1,但是下標排序後連續且相差1的下標串對應的字串必然是合法結構 max_s_length.sort() if len(max_s_length) == 0: return 0 print("max_s_length", max_s_length) length = 1 max_length = 0 # 遍歷max_s_length列表,尋找相差為1的下標的最大個數 for index in range(1, len(max_s_length)): if max_s_length[index] - max_s_length[index-1] == 1: length += 1 else: if length > max_length: max_length = length length = 1 return max(length, max_length) if __name__ == "__main__": s = "))(((()()" result = Solution().longestValidParentheses(s) print(result)
這段程式碼中我做了很多註解,大家應該挺好看懂的,但是執行效率挺差的,只有10%左右。
後來在網上看到了一大佬給的演算法,也是採用進棧出棧法,但是它是直接將有效括號對的下標值進行運算得到最大有效長度,真的是牛逼,不知道大佬們是怎麼能想到這麼簡單快捷的騷操作,我也把程式碼貼出來,大家可以學習學習。
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 if __name__ == "__main__": s = "))(((()()" result = Solution().longestValidParentheses(s) print(result)
執行效率也是真的高,再次跪拜大佬!!!