Leetcode刷题笔记59:单调栈2(503. 下一个更大元素 II-42. 接雨水)

89 阅读3分钟

导语

leetcode刷题笔记记录,本篇博客是贪心部分的第二期,主要记录题目包括:

Leetcode 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

解法

这里可以使用两种思路解决:

  • 将数组复制一份拼接在原数组后面,就是一个环形数组展开
  • 使用取模的方式,在求超过数组长度的索引时,只需要对其下标i进行取模即可,无需真正复制和拼接数组

解决代码如下:

class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        stack = [0]  # 初始化栈,用于存放 nums 的索引
        result = [-1] * len(nums)  # 初始化结果数组,长度与 nums 相同,所有元素初始值为 -1

        # 循环数组的长度是原数组的两倍,这样可以模拟循环数组的行为
        for i in range(1, 2 * len(nums)):
            # 对数组长度取模,获取循环数组中的实际元素
            cur_val = nums[i % len(nums)]

            # 如果当前元素小于等于栈顶元素,则将其索引(对 len(nums) 取模后)添加到栈中
            if cur_val <= nums[stack[-1]]:
                stack.append(i % len(nums))
            else:
                # 如果当前元素大于栈顶元素,则进入循环
                while len(stack) > 0 and cur_val > nums[stack[-1]]:
                    # 更新结果数组中对应索引的值为当前元素
                    result[stack[-1]] = cur_val
                    # 弹出栈顶元素
                    stack.pop()

                # 如果当前元素的索引(在原数组中)还没有被处理过,就把它加入栈中
                if i % len(nums) not in stack:
                    stack.append(i % len(nums))
                    
        return result  # 返回结果数组

Leetcode 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

解法

这里计算凹槽面积,需要确定凹槽的宽和高,看图分析发现,我们实际上只要求出每个柱子的左边第一个比它高的柱子位置和右边第一个比它高的柱子位置即可。

对于相同数值的元素,我们只需要在处理时让他进栈后出栈,只计算一次即可。模拟过程如下图所示:

image.png

完整版代码如下:

class Solution:
    def trap(self, height: List[int]) -> int:
        stack = [0]  # 初始化一个栈,用于存放柱子的索引,栈内的柱子高度是单调递减的
        area = 0  # 初始化雨水总量为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 len(stack) > 0 and height[i] > height[stack[-1]]:
                    mid = stack[-1]  # 获取栈顶柱子的索引
                    stack.pop()  # 移除栈顶柱子
                    if len(stack) > 0:  # 如果栈不为空
                        # 计算当前积水区域的高度和宽度
                        h = min(height[i], height[stack[-1]]) - height[mid]
                        w = i - stack[-1] - 1
                        # 计算当前积水区域的面积,并加到总面积中
                        area += h * w
                stack.append(i)  # 将当前柱子加入栈中

        return area  # 返回总雨水量