Day 59 单调栈:503. 下一个更大元素 II, 42. 接雨水,407. 接雨水 II,11. 盛最多水的容器, 84. 柱状图中最大的矩形

503. 下一个更大元素 II

  • 思路
    • example
    • 循环数组
      • [1, 2, 1, 1, 2, 1]
      • 遍历两倍大小的数组(取模运算),按照常规数组操作,最后返回size n的结果数组即可。
        • 可能会有重复操作,但是方便。
  • 复杂度. 时间:O(n), 空间: O(n)
class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        n = len(nums)
        res = [-1 for _ in range(n)]
        stack = [0]
        for i in range(1, 2*n):
            while stack and nums[i%n] > nums[stack[-1]]:
                idx = stack.pop()
                res[idx] = nums[i%n]  
            stack.append(i%n)  
        return res  
class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        n = len(nums)  
        res = [-1 for _ in range(n)] 
        stack = [] 
        for i in range(2*n):
            if not stack or nums[stack[-1]] >= nums[i%n]:
                stack.append(i%n) 
            else: 
                while stack and nums[stack[-1]] < nums[i%n]:
                    idx = stack.pop()  
                    res[idx] = nums[i%n] 
                stack.append(i%n) 
        return res  
class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        nums1 = nums + nums 
        n = len(nums1) 
        res = [-1 for _ in range(len(nums1))] 
        stack = [0] 
        for i in range(1, n):
            while stack and nums1[i] > nums1[stack[-1]]:
                idx = stack.pop()
                res[idx] = nums1[i] 
            stack.append(i) 
        return res[:n//2]

42. 接雨水

  • 思路

    • example
    • 暴力(双指针,中心扩散法),DP (两次遍历), 双指针,优先队列: https://www.jianshu.com/p/538520fed566
      • 纵向接水


  • 复杂度. 时间:O(n), 空间: O(n)

# DP
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        leftMax = [0 for _ in range(n)]
        rightMax = [0 for _ in range(n)]
        for i in range(1, n):
            leftMax[i] = max(leftMax[i-1], height[i-1])
        for i in range(n-2, -1, -1):
            rightMax[i] = max(rightMax[i+1], height[i+1])
        res = 0
        for i in range(n):
            h = min(leftMax[i], rightMax[i])
            res += max(0, h-height[i])
        return res  
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height) 
        leftMax = [0 for _ in range(n)] 
        rightMax = [0 for _ in range(n)] 
        for i in range(1, n):
            leftMax[i] = max(leftMax[i-1], height[i-1]) 
        for i in range(n-2, -1, -1):
            rightMax[i] = max(rightMax[i+1], height[i+1])  
        res = 0 
        for i in range(n):
            res += max(min(leftMax[i], rightMax[i])-height[i], 0)
        return res  
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height) 
        left = [0 for _ in range(n)]
        right = [0 for _ in range(n)] 
        for i in range(1, n):
            left[i] = max(left[i-1], height[i-1]) 
        for j in range(n-2, -1, -1):
            right[j] = max(right[j+1], height[j+1]) 
        res = 0 
        for i in range(n):
            res += max(min(left[i], right[i]) - height[i], 0) # !!!
        return res 
  • 单调栈 ( 横向接水)


class Solution:
    def trap(self, height: List[int]) -> int:
        # 单调栈
        '''
        单调栈是按照 行 的方向来计算雨水
        从栈顶到栈底的顺序:从小到大
        通过三个元素来接水:栈顶,栈顶的下一个元素,以及即将入栈的元素
        雨水高度是 min(凹槽左边高度, 凹槽右边高度) - 凹槽底部高度
        雨水的宽度是 凹槽右边的下标 - 凹槽左边的下标 - 1(因为只求中间宽度)
        '''
        # stack储存index,用于计算对应的柱子高度
        stack = [0]
        result = 0
        for i in range(1, len(height)):
            # 情况一
            if height[i] < height[stack[-1]]:
                stack.append(i)

            # 情况二
            # 当当前柱子高度和栈顶一致时,左边的一个是不可能存放雨水的,所以保留右侧新柱子
            # 需要使用最右边的柱子来计算宽度
            elif height[i] == height[stack[-1]]:
                stack.pop()
                stack.append(i)

            # 情况三
            else:
                # 抛出所有较低的柱子
                while stack and height[i] > height[stack[-1]]:
                    # 栈顶就是中间的柱子:储水槽,就是凹槽的地步
                    mid_height = height[stack[-1]]
                    stack.pop()
                    if stack:
                        right_height = height[i]
                        left_height = height[stack[-1]]
                        # 两侧的较矮一方的高度 - 凹槽底部高度
                        h = min(right_height, left_height) - mid_height
                        # 凹槽右侧下标 - 凹槽左侧下标 - 1: 只求中间宽度
                        w = i - stack[-1] - 1
                        # 体积:高乘宽
                        result += h * w
                stack.append(i)
        return result

407. 接雨水 II

  • 思路
    • example
    • 接雨水 高维版本
    • 由外身内遍历边界 (水一定是从外边界溢出)
      • 优先队列 (最小堆 heapq)
      • directions方向向量: 方便考察最小边界周围点的水位
      • visited数组避免重复访问
        • 判断visited[x][y]时先检查x,y是否越界。
    • 复杂度. 时间:, 空间:
class Solution:
    def trapRainWater(self, heightMap: List[List[int]]) -> int:
        m, n = len(heightMap), len(heightMap[0])
        if m <= 2 or n <= 2:
            return 0  
        que = []
        visited = [[False for _ in range(n)] for _ in range(m)]
        for j in range(n):
            heapq.heappush(que, (heightMap[0][j], (0,j)))
            visited[0][j] = True
            heapq.heappush(que, (heightMap[m-1][j], (m-1,j)))  
            visited[m-1][j] = True 
        for i in range(1, m-1):
            heapq.heappush(que, (heightMap[i][0], (i,0)))
            visited[i][0] = True 
            heapq.heappush(que, (heightMap[i][n-1], (i,n-1)))
            visited[i][n-1] = True 
        res = 0
        directions = [(0,1), (0,-1), (-1,0), (1,0)]
        while que:  
            h, position = heapq.heappop(que) 
            x0, y0 = position[0], position[1]
            for direction in directions:
                x, y = x0 + direction[0], y0 + direction[1]
                if 0<=x
class Solution:
    def trapRainWater(self, heightMap: List[List[int]]) -> int:
        m, n = len(heightMap), len(heightMap[0]) 
        if m<=2 or n <=2:
            return 0 
        que = [] 
        visited = [[False for _ in range(n)] for _ in range(m)]
        for j in range(n):
            heapq.heappush(que, (heightMap[0][j], (0,j))) 
            heapq.heappush(que, (heightMap[m-1][j], (m-1,j))) 
            visited[0][j] = True 
            visited[m-1][j] = True 
        for i in range(1, m-1):
            heapq.heappush(que, (heightMap[i][0], (i,0)))
            heapq.heappush(que, (heightMap[i][n-1], (i,n-1)))
            visited[i][0] = True 
            visited[i][n-1] = True  
        directions = [(0,1), (1,0), (-1,0), (0,-1)]
        res = 0  
        while que:
            h, pos = heapq.heappop(que)
            x0, y0 = pos[0], pos[1] 
            for direction in directions:
                x, y = x0+direction[0], y0+direction[1]
                if x >=0 and x=0 and y
class Solution:
    def trapRainWater(self, heightMap: List[List[int]]) -> int:
        m, n = len(heightMap), len(heightMap[0]) 
        visit = [[False for _ in range(n)] for _ in range(m)] 
        que = []
        for j in range(n):
            visit[0][j] = True 
            visit[m-1][j] = True
            heapq.heappush(que, (heightMap[0][j], (0, j)))
            heapq.heappush(que, (heightMap[m-1][j], (m-1, j)))
        for i in range(m):
            visit[i][0] = True 
            visit[i][n-1] = True 
            heapq.heappush(que, (heightMap[i][0], (i, 0)))
            heapq.heappush(que, (heightMap[i][n-1], (i, n-1)))
        directions = [(-1,0), (1,0), (0,1), (0,-1)]
        res = 0
        while que:
            height, pos = heapq.heappop(que) 
            x0, y0 = pos[0], pos[1] 
            for i in range(4):
                x, y = x0+directions[i][0], y0+directions[i][1]
                if x >= 0 and x < m and y >=0 and y < n and visit[x][y] == False:
                    res += max(0, height - heightMap[x][y]) 
                    if height > heightMap[x][y]:
                        waterlevel = height 
                    else:
                        waterlevel = heightMap[x][y]
                    heapq.heappush(que, (waterlevel, (x,y)))
                    visit[x][y] = True # !!!
        return res 

11. 盛最多水的容器

  • 思路
    • example
    • 短板效应
      • [left, right]: 储水量 = min(height[left], height[right]) * (right - left)
    • 解法1:暴办法
      • 复杂度. 时间:, 空间:
class Solution:
    def maxArea(self, height: List[int]) -> int:
        n = len(height)
        res = 0
        for left in range(n):
            for right in range(left+1, n):
                res = max(res, min(height[left], height[right]) * (right - left))
        return res
  • 解法2:双指针, -->*<--
    • left, right = 0, n-1
    • 在更新完[left, right]结果后,考虑left += 1, 或者right -= 1
    • 如果height[left] < height[right]: 考虑left += 1, 这样在宽度减小的情况下,min_height有可能增大;否则如果right-=1, min_height <= height[left],不可能改进结果。(height[left] < height[right]的情况下,区间[left, j] where j < right不需要考虑了。)
    • 复杂度. 时间:, 空间:
class Solution:
    def maxArea(self, height: List[int]) -> int:
        n = len(height)
        left, right = 0, n-1
        res = 0
        while left < right:
            res = max(res, min(height[left], height[right])*(right-left))
            if height[left] < height[right]:
                left += 1
            else:
                right -= 1
        return res  
class Solution:
    def maxArea(self, height: List[int]) -> int:
        n = len(height) 
        left, right = 0, n-1  
        res = 0 
        while left < right:
            res = max(res, min(height[left], height[right])*(right-left))
            if height[left] < height[right]:
                left += 1 
            else:
                right -= 1
        return res  

84. 柱状图中最大的矩形

  • 思路
    • example
    • 暴力双指针(中心扩散):
    • 单调栈
    • 复杂度. 时间:, 空间:
TBA

你可能感兴趣的:(Day 59 单调栈:503. 下一个更大元素 II, 42. 接雨水,407. 接雨水 II,11. 盛最多水的容器, 84. 柱状图中最大的矩形)