1. 程式人生 > >LeetCode-棧-Hard

LeetCode-棧-Hard

記錄了初步解題思路 以及本地實現程式碼;並不一定為最優 也希望大家能一起探討 一起進步


目錄



42.trapping-rain-water 接雨水

解題思路:
保留左右兩邊的值 中間的按照最高點灌滿
假設讓水從左側流出 如果左側的比本地的要小l[i]>l[i-1] 則水減少至左側或者本地的柱子高度max(height[i],l[i-1])
從左到右檢查一遍後 從右到左在檢查一遍

def trap(height):
    """
    :type height: List[int]
    :rtype: int
    [0,1,0,2,1,0,1,3,2,1,2,1]
    """
    m = max(height)
if len(height)<3: return 0 l = [height[0]]+[m]*(len(height)-2)+[height[-1]] def check(l,ori): for i in range(1,len(l)): if l[i]>l[i-1]: l[i] = max(height[i],l[i-1]) return l l=check(l,height) l.reverse() l = check(l,height.
reverse()) l.reverse() s =0 for i in range(len(height)): s += l[i]-height[i] print(s)

84.largest-rectangle-in-histogram 柱狀圖中最大的矩形

解題思路:
1.主要是超時問題
2.使用一個list來儲存數值的位置
遍歷heights:
如果棧為空或者當前值大於棧頂位置的值 則將這個位置放入棧中
如果當前值小於等於棧頂位置值 將棧頂的位置pop 計算這個值h能夠產生的矩形面積
此時會用到pop後的棧頂位置posl[-1] 是h左邊的邊界 則面積為(i-posl[-1]-1)*h
開始時加入0 對最後的棧中情況進行處理

def largestRectangleArea1(heights):
    """
    :type heights: List[int]
    :rtype: int
    """
    if not heights:
        return 0
    
    def check(h):
        cur=0
        ans=cur
        for i in heights:
            if i>=h:
                cur+=1
            else:
                ans = max(ans,cur)
                cur=0
        ans = max(ans,cur)
        return ans*h
    
    ret = 0
    for i in set(heights):
        tmp=check(i)
        ret = max(ret,tmp)
    return ret


def largestRectangleArea(heights):
    """
    :type heights: List[int]
    :rtype: int
    
    """
    posl =[]
    ret = 0
    
    heights.append(0)
    n = len(heights)
    for i in range(n):
        if not posl or heights[i] > heights[posl[-1]]:
            posl.append(i)
        else:
            while posl and heights[i] <= heights[posl[-1]]:
                h = heights[posl[-1]]
                posl.pop()
                if not posl:
                    l = i
                else:
                    l = i - posl[-1]-1
                ret = max(ret, h * l)
            posl.append(i)
    return ret

85.maximal-rectangle 最大矩形

解題思路:
可以利用84中的方法
每一層網上看都能轉換成84題中直方圖求舉證大小
每一層如果該層某一位置為0 則無論往上是否有1 改處在直方圖中的值為0

def maximalRectangle(matrix):
    """
    :type matrix: List[List[str]]
    :rtype: int
    """
    x = len(matrix)
    ret =0
    if x==0:
        return 0
    y = len(matrix[0])
    
    def largestRectangleArea(heights):
        posl =[]
        ret = 0
        
        heights.append(0)
        n = len(heights)
        for i in range(n):
            if not posl or heights[i] > heights[posl[-1]]:
                posl.append(i)
            else:
                while posl and heights[i] <= heights[posl[-1]]:
                    h = heights[posl[-1]]
                    posl.pop()
                    if not posl:
                        l = i
                    else:
                        l = i - posl[-1]-1
                    ret = max(ret, h * l)
                posl.append(i)
        return ret
            
    
    for i in range(x):
        height=[]
        for j in range(y):
            n = 0
            tmpi = i
            while matrix[tmpi][j]=="1" and tmpi>=0:
                n+=1
                tmpi-=1
            height.append(n)
        ret = max(ret,largestRectangleArea(height))
    return ret

145.binary-tree-postorder-traversal 二叉樹的後序遍歷

解題思路:
後序遍歷:左右根
取值時根右左,結果倒序

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

def postorderTraversal(root):
    """
    :type root: TreeNode
    :rtype: List[int]
    """
    ret =[]
    stack=[]
    if not root:
        return ret
    
    stack.append(root)
    while stack:
        v = stack.pop()
        if v.left:
            stack.append(v.left)
        if v.right:
            stack.append(v.right)
        
        ret.append(v.val)
    ret.reverse()
    return ret

224.basic-calculator 基本計算器

解題思路:
遍歷str 放入stack中 同時將數字整合到一起 如果遇到‘)’ 則開始往前尋找’(’ 將經過的數值計算
非負整數 所以最後stack中第一個數必定為正整數 使用+

def calculate(s):
    """
    :type s: str
    :rtype: int
    """
    stack=[]
    ret = 0
    numpre =""
    for i in s:
        if i==" ":
            continue
        if i!=")":
            if i.isdigit():
                numpre +=i
            else:
                if numpre!="":
                    stack.append(int(numpre))
                    numpre=""
                stack.append(i)
        else: 
            if numpre!="":
                stack.append(int(numpre))
                numpre=""
            tmp = stack.pop()
            pre = 0
            res = 0
            while tmp!="(":
                if tmp=="+":
                    res +=pre
                elif tmp=="-":
                    res -=pre
                else:
                    pre = int(tmp)
                tmp = stack.pop()
            res+=pre
            stack.append(res)
    if numpre!="":
        stack.append(int(numpre))
    action = "+"
    stack.append("+")
    for i in stack:
        if i in ("-","+"):
            if action=="+":
                ret +=pre
            else:
                ret -= pre
            action =i
        else:
            pre = i
    return ret

316.remove-duplicate-letters 去除重複字母

解題思路:
使用dic記錄所有字母出現的次數
當往stack中新增字母x時,判斷在他前面的字母是否比x大 而且在後面任然會出現
如果成立將這個字母從stack去除 繼續往前判斷
判斷結束後 將x加入stack中 此時有的字母結果為resultset
當有字母已在前面放入了stack並保留了下來(在set內) 則可以不需再判斷

def removeDuplicateLetters(s):
    """
    :type s: str
    :rtype: str
    """
    dic = {}
    for c in s:
        dic[c] = dic.get(c,0)+1
    resultSet = set()
    stack = list()
    for c in s:
        dic[c] -= 1
        if c in resultSet:
            continue
        while stack and stack[-1] > c and dic[stack[-1]]:
            stack.pop()
        stack.append(c)
        resultSet = set(stack)
    return ''.join(stack)