503.下一个更大元素II
# 给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。 # 数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。 # # 示例 1: # 输入: nums = [1,2,1] # 输出: [2,-1,2] # 解释: 第一个 1 的下一个更大的数是 2; # 数字 2 找不到下一个更大的数; # 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。 # # 示例 2: # 输入: nums = [1,2,3,4,3] # 输出: [2,3,4,-1,4] # # 提示: # 1 <= nums.length <= 104 # -109<= nums[i] <= 109 # 通过次数179,433提交次数270,230
class Solution:
def nextGreaterElements(self, nums: [int]) -> [int]:
# dp = [-1] * len(nums)
# stack = []
# for i in range(len(nums)*2):
# while(len(stack) != 0 and nums[i%len(nums)] > nums[stack[-1]]):
# dp[stack[-1]] = nums[i%len(nums)]
# stack.pop()
# stack.append(i%len(nums))
# return dp
42. 接雨水
# 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 # # 示例 1: # 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] # 输出:6 # 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 # 示例 2: # # 输入:height = [4,2,0,3,2,5] # 输出:9 # n == height.length # 1 <= n <= 2 * 104 # 0 <= height[i] <= 105
from typing import List
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
# 单调栈压缩版
def trap0(self, height: List[int]) -> int:
stack = [0]
result = 0
for i in range(1, len(height)):
while stack and height[i] > height[stack[-1]]:
mid_height = stack.pop()
if stack:
# 雨水高度是 min(凹槽左侧高度, 凹槽右侧高度) - 凹槽底部高度
h = min(height[stack[-1]], height[i]) - height[mid_height]
# 雨水宽度是 凹槽右侧的下标 - 凹槽左侧的下标 - 1
w = i - stack[-1] - 1
# 累计总雨水体积
result += h * w
stack.append(i)
return result
# 4 这个是随想录上面的写法,也超时了,可能是力扣后来追加了案例,不允许这种写法了
def trap4(self, height: List[int]) -> int:
size = len(height)
res = 0
for i in range(size):
if i == 0 or i == size - 1:
continue
lefth = height[i-1]
righth = height[i+1]
for j in range(i):
if lefth < height[j]:
lefth = height[j]
for k in range(i+2,size):
if righth < height[k]:
righth = height[k]
rain = min(lefth,righth) - height[i]
if rain > 0:
res += rain
return res
# 3 应该也可以理解为双指针写法,和4是一样的,但是超时了
def trap3(self, height: List[int]) -> int:
size = len(height)
res = 0
for i in range(size):
if i == 0 or i == size - 1:
continue
lefth = max(height[:i])
righth = max(height[i + 1:])
rain = min(lefth, righth) - height[i]
if rain > 0:
res += rain
return res
"""
只要记录左边柱子的最高高度和右边柱子的最高高度,就可以计算当前位置的雨水面积,这就是通过列来计算。
当前列雨水面积:min(左边柱子的最高高度,记录右边柱子的最高高度) - 当前柱子高度。
为了得到两边的最高高度,用双指针遍历,每到一个柱子都向两边遍历一遍,这其实是有重复计算的。把每一个位置的左边
最高高度记录在一个数组上(maxLeft),右边最高高度记录在一个数组上(maxRight)。这样就避免了重复计算,这就
用到了动态规划。
当前位置,左边的最高高度是前一个位置的左边最高高度和本高度的最大值。
即从左向右遍历:maxLeft[i] = max(height[i], maxLeft[i - 1]);
从右向左遍历:maxRight[i] = max(height[i], maxRight[i + 1]);
"""
# 2.这个是卡哥动态规划的解法,感觉这个和双指针区别不大,不过优化了for循环,不用双重循环了
def trap2(self, height: List[int]) -> int:
size = len(height)
lhigh = [0] * size
rhigh = [0] * size
lhigh[0] = height[0]
rhigh[-1] = height[-1]
for i in range(1, size):
if height[i] > lhigh[i - 1]:
lhigh[i] = height[i]
else:
lhigh[i] = lhigh[i - 1]
for i in range(size - 2, -1, -1):
if height[i] > rhigh[i + 1]:
rhigh[i] = height[i]
else:
rhigh[i] = rhigh[i + 1]
res = 0
for i in range(size):
tmp = min(lhigh[i], rhigh[i]) - height[i]
if tmp > 0:
res += tmp
return res
# 1.这里是动态规划的写法,参考卡哥C语言的写法,有点点小区别
def trap1(self, height: List[int]) -> int:
size = len(height)
lhigh = [height[0]]
rhigh = [height[size - 1]]
for i in range(1, size):
if height[i] > lhigh[-1]:
lhigh.append(height[i])
else:
lhigh.append(lhigh[-1])
for i in range(size - 2, -1, -1):
if height[i] > rhigh[-1]:
rhigh.append(height[i])
else:
rhigh.append(rhigh[-1])
# 上面计算的时候是append,只能向后追加,这里需要倒转一下数组,数组存的是当前位置的右边最大值
rhigh.reverse()
res = 0
for i in range(size - 1):
tmp = min(lhigh[i], rhigh[i]) - height[i]
if tmp > 0:
res += tmp
return res
if __name__ == '__main__':
height = [0,1,0,2,1,0,1,3,2,1,2,1]
tmp = Solution()
res = tmp.trap(height)
print(res)