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<m and 0<=y<n and visited[x][y] == False:
h_new = max(h, heightMap[x][y])
res += h_new - heightMap[x][y]
heapq.heappush(que, (h_new, (x,y)))
visited[x][y] = True
return res
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<m and y>=0 and y<n:
if visited[x][y]:
continue
new_h = max(h, heightMap[x][y])
res += max(0, new_h - heightMap[x][y])
heapq.heappush(que, (new_h, (x,y)))
visited[x][y] = True
return res
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