Leetcode 栈 2

题号直达: 394 字符串解码 | 739 每日温度 | 84 最大矩形

LeetCode 394. 字符串解码 ↑

题目

给定一个经过编码的字符串 s,按规则 k[encoded_string] 解码并返回结果,其中 encoded_string 需要重复 k 次(k 为正整数)。可保证输入有效,且原始数据不含数字(数字只表示重复次数)。

测试样例

  • 示例 1: s = "3[a]2[bc]"
    输出:"aaabcbc"
  • 示例 2: s = "3[a2[c]]"
    输出:"accaccacc"
  • 示例 3: s = "2[abc]3[cd]ef"
    输出:"abcabccdcdcdef"
  • 示例 4: s = "abc3[cd]xyz"
    输出:"abccdcdcdxyz"

提示

  • 1 ≤ len(s) ≤ 30
  • s 由小写英文字母、数字和方括号 '[]' 组成
  • s 是有效输入,且整数范围在 [1, 300]

代码(Python):栈展开(站主自主完成)

遇到普通字符(含数字、左括号)先入栈;遇到右括号 ] 时,弹栈得到本层 temp,再弹出前面的数字字符计算重复次数 repeat,把展开后的内容压回栈中。最终栈内容拼接即答案。

class Solution(object):
    def decodeString(self, s):
        """
        :type s: str
        :rtype: str
        """
        stack = []
        for i in range(len(s)):
            temp = []
            num = []
            repeat = 0
            if s[i] != "]":
                stack.append(s[i])
            else:
                while stack[-1] != "[":
                    temp.append(stack.pop())    # temp现在是要重复的内容
                stack.pop()                     # 现在把 '[' pop掉
                while stack[-1] in "0123456789":
                    num.append(stack.pop())
                    if not stack:
                        break
                for j in range(len(num)):
                    repeat += 10 ** j * int(num[j])

                for k in range(repeat):
                    temtemp = temp[:]      # 这里必须要加[:],不然temtemp和temp指向的是同一个地址
                    while temtemp:
                        stack.append(temtemp.pop())
        return "".join(stack)

思路解析

  • 按层还原:每遇到 ] 就还原一层最近的 [...],天然支持嵌套结构。
  • 数字逆序处理:数字是从栈顶反向弹出的,repeat += 10 ** j * int(num[j]) 可恢复正常十进制值。
  • 复制列表:temtemp = temp[:] 保证每轮重复使用独立副本,避免就地 pop 破坏 temp。
  • 复杂度:与解码后字符串长度线性相关;在题目约束下可通过。

LeetCode 739. 每日温度 ↑

题目

给定整数数组 temperatures,answer[i] 表示第 i 天之后要等几天才会出现更高温度;若之后都不会升高,则 answer[i] = 0。

测试样例

  • 示例 1: temperatures = [73,74,75,71,69,72,76,73]
    输出:[1,1,4,2,1,1,0,0]
  • 示例 2: temperatures = [30,40,50,60]
    输出:[1,1,1,0]
  • 示例 3: temperatures = [30,60,90]
    输出:[1,1,0]

提示

  • 1 ≤ len(temperatures) ≤ 10^5
  • 30 ≤ temperatures[i] ≤ 100

代码(Python):单调栈(站主自主完成)

维护一个单调递减温度栈(配套下标栈 index)。扫描到新温度 temperatures[i] 时,若它高于栈顶温度,说明找到了栈顶那一天的“下一个更高温度”,即可计算天数差并弹栈;重复直到恢复单调,再把当前温度与下标入栈。

class Solution(object):
    def dailyTemperatures(self, temperatures):
        """
        :type temperatures: List[int]
        :rtype: List[int]
        """
        stack = []
        index = []
        ans = [0] * len(temperatures)
        for i in range(len(temperatures)):
            if not stack:
                index.append(i)
                stack.append(temperatures[i])
            else:
                if temperatures[i] <= stack[-1]:
                    stack.append(temperatures[i])
                    index.append(i)
                else:
                    while temperatures[i] > stack[-1]:
                        ans[index[-1]] = i - index[-1]
                        index.pop()
                        stack.pop()
                        if not stack:
                            break
                    index.append(i)
                    stack.append(temperatures[i])
        return ans

思路解析

  • 单调性:stack 从栈底到栈顶递减,栈中每个位置都还没找到下一个更高温度。
  • 弹栈更新:当当前温度更高时,持续弹出所有更低温度,并立刻计算答案 i - index[-1]。
  • 下标作用:index 与 stack 同步,保证能 O(1) 取到“被更新那天”的位置。
  • 复杂度:每个下标最多入栈、出栈一次,时间 O(n),空间 O(n)。

LeetCode 84. 柱状图中最大的矩形 ↑

题目

给定 n 个非负整数 heights 表示柱状图高度,每个柱子宽度为 1。求该柱状图中可勾勒出的最大矩形面积。

提示

  • 1 ≤ len(heights) ≤ 10^5
  • 0 ≤ heights[i] ≤ 10^4

示例图

题目示意图(0414.png`):

柱状图最大矩形 题目示例

代码(Python)解法一:左右最近更小值 + 单调栈

先分别求每个柱子的左侧第一个更小元素下标 index_left[i] 与右侧第一个更小元素下标 index_right[i]。以 heights[i] 为高时,最大可扩展宽度为 index_right[i] - index_left[i] - 1,面积即 heights[i] * 宽度,遍历取最大。

class Solution(object):
    def largestRectangleArea(self, heights):
        """
        :type heights: List[int]
        :rtype: int
        """
        # 找左边界
        index_left = []
        index = []
        stack = []
        for i in range(len(heights)):
            if not stack:
                index_left.append(-1)
                index.append(i)
                stack.append(heights[i])
            else:
                while heights[i] <= stack[-1]:
                    stack.pop()
                    index.pop()
                    if not stack:
                        break
                if not stack:
                    index_left.append(-1)
                else:
                    index_left.append(index[-1])
                stack.append(heights[i])
                index.append(i)

        # 找右边界
        index_right = [0] * len(heights)
        index = []
        stack = []
        for i in range(len(heights) - 1, -1, -1):
            if not stack:
                index_right[i] = len(heights)
                index.append(i)
                stack.append(heights[i])
            else:
                while heights[i] <= stack[-1]:
                    stack.pop()
                    index.pop()
                    if not stack:
                        break
                if not stack:
                    index_right[i] = len(heights)
                else:
                    index_right[i] = index[-1]
                stack.append(heights[i])
                index.append(i)

        # 根据左右边界找最大值
        max_area = 0
        for i in range(len(heights)):
            area = heights[i] * (index_right[i] - index_left[i] - 1)
            if area > max_area:
                max_area = area
        return max_area

思路解析(解法一)

  • 单调栈边界:左扫维护递增栈可得到左侧最近更小元素;右扫同理得到右侧最近更小元素。
  • 面积公式:固定高度 heights[i] 时,左右边界之外都是更小值,故可覆盖的连续宽度是 right - left - 1。
  • 重复高度处理:用 <= 弹栈可保证边界严格指向“更小值”而非“相等值”,避免宽度重复计算混乱。
  • 复杂度:每个下标在左右两次扫描中最多进栈出栈各一次,总时间 O(n),空间 O(n)。

代码(Python)解法二:单调栈 + 尾部哨兵 0(一次扫描)

在末尾追加一个高度 0 作为哨兵,强制把栈中剩余柱子一次性结算。栈内存放下标,且对应高度单调不降;当遇到更矮柱子时,持续弹出并把被弹出的柱高作为当前矩形高度,宽度由“当前下标 i 与弹出后新的栈顶”确定。

class Solution(object):
    def largestRectangleArea(self, heights):
        heights.append(0)
        n = len(heights)
        stack = []
        ans = 0
        for i in range(n):
            while stack and heights[i] < heights[stack[-1]]:
                x = stack.pop()
                area = (i - stack[-1] - 1 if stack else i) * heights[x]
                ans = max(ans, area)
            stack.append(i)
        return ans

思路解析(解法二)

  • 哨兵作用:heights.append(0) 保证最后会触发弹栈,避免循环后再单独清栈。
  • 宽度计算:弹出 x 后,若栈非空,左边界是 stack[-1],宽度是 i - stack[-1] - 1;若栈空,说明左侧都不小于 heights[x],宽度是 i。
  • 与解法一关系:本质仍是找“左右最近更小值”,只是把边界计算隐含在弹栈时完成。
  • 复杂度:每个下标最多入栈、出栈一次,时间 O(n),空间 O(n)。
posted @ 2026-10-12 00:24  Phier  阅读(2)  评论(0)    收藏  举报