LeetCode Hot 100——栈

20. 有效的括号

正确嵌套的意思是:

  • 后出现的左括号必须先匹配(LIFO:后进先出)
  • 所以用 栈:遇到左括号就入栈;遇到右括号就用它去匹配栈顶的左括号

规则只有三条:

  1. 左括号 ( { [:入栈

  2. 右括号 ) } ]:栈必须不空,并且栈顶必须是对应的左括号,否则失败

  3. 扫描结束:栈必须为空才算成功(不能多出左括号)

    class Solution {
    public boolean isValid(String s) {
    Stack<Character> stack = new Stack<>();
    char[] charsArray = s.toCharArray();
    for(char c : charsArray) {
    if(c == '(' || c == '{' || c == '[') {
    stack.push(c);
    } else {
    if(stack.isEmpty()) {
    return false;
    }
    char topElem = stack.pop();
    if(c == ']' && topElem != '[' || c == '}' && topElem != '{' || c == ')' && topElem != '(') {
    return false;
    }

    复制代码
             }
         }
         return stack.isEmpty();
     }

    }

155. 最小栈

核心思路:双栈

  • stack:正常栈,存所有元素
  • minStack:辅助栈,每一层存"当前主栈中的最小值"

方法具体实现:

  • push(x):主栈正常压 x;辅助栈压 min(x, minStack.peek())
  • pop():两个栈同时 pop
  • getMin():直接返回 minStack.peek(),O(1)

关键理解:minStack 的第 i 层,记录的是主栈前 i 个元素中的最小值。主栈 pop 一个,辅助栈也 pop 一个,最小值信息自动回退到上一个状态。

复制代码
class MinStack {
    private Deque<Integer> stack;
    private Deque<Integer> minStack;

    public MinStack() {
        stack = new ArrayDeque<>();
        minStack = new ArrayDeque<>();
    }
    
    public void push(int val) {
        stack.push(val);
        if(minStack.isEmpty()) {
            minStack.push(val);
        } else {
            minStack.push(Math.min(val, minStack.peek()));
        }
    }
    
    public void pop() {
        stack.pop();
        minStack.pop();
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(val);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

关键是:括号可以嵌套,一旦进入内层,你需要"记住外层的状态",等内层解码完再回到外层继续拼接。

所以用栈保存现场:

  • 一个栈存外层的重复次数 kcountStack
  • 一个栈存进入括号前已经拼好的字符串 prefixstrStack
  • 当前正在构建的字符串用 cur
  • 当前正在读取的数字用 num(要支持多位数)

处理规则:

  • 遇到数字:num = num*10 + digit

  • 遇到 [:把 numcur 分别入栈,然后清空 num=0cur="" 开始处理括号内

  • 遇到字母:拼到 cur

  • 遇到 ]:弹出 kprefix,令 cur = prefix + cur重复k次

    class Solution {
    public String decodeString(String s) {
    Deque<StringBuilder> strStack = new ArrayDeque<>();
    Deque<Integer> countStack = new ArrayDeque<>();
    int num = 0;
    StringBuilder cur = new StringBuilder();
    for(int i = 0;i < s.length();++i) {
    char c = s.charAt(i);
    if(Character.isDigit(c)) {
    num = num * 10 + (c - '0');
    } else if(c == '[') {
    strStack.push(cur);
    countStack.push(num);
    // 开新的一层
    num = 0;
    cur = new StringBuilder();
    } else if(c == ']') {// 合成操作
    int k = countStack.pop();
    StringBuilder prefix = strStack.pop();
    StringBuilder repeat = new StringBuilder();
    for(int j = 0;j < k;++j) {
    repeat.append(cur); //这里append的是cur,不是prefix,prefix是用来跟重复的进行合并的
    }
    cur = prefix.append(repeat);
    } else {
    cur.append(c);
    }
    }
    return cur.toString();
    }
    }

739. 每日温度

这类"找右边第一个更大元素"的典型解法是 单调栈(递减栈):

  • 栈里存 下标(不是温度值),方便计算天数差
  • 栈保持"从栈底到栈顶,对应温度严格递减"
  • 扫描到新一天 i
    • 只要 temperatures[i] > temperatures[栈顶],说明栈顶那一天等到了更热的一天,就是今天
      • 弹出 idx
      • 答案 ans[idx] = i - idx
    • 然后把 i 入栈(表示它还在等更热的未来)

      class Solution {
      public int[] dailyTemperatures(int[] temperatures) {
      int n = temperatures.length;
      int[] ans = new int[n];
      Deque<Integer> stack = new ArrayDeque<>();
      for(int i = 0;i < n;++i) {
      while(!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
      int idx = stack.pop();
      ans[idx] = i - idx;
      }
      stack.push(i);
      }
      return ans;
      }
      }

84. 柱状图中最大的矩形

把每根柱子 i 当成"这块矩形的最矮高度",那它能扩到多宽取决于:

  • 左边第一个 比它矮 的柱子位置 L
  • 右边第一个 比它矮 的柱子位置 R

则以 h[i] 为高的最大矩形:

  • width = R - L - 1
  • area = h[i] * width

所以问题变成:对每个 i,快速找到左右最近更矮元素 → 用单调栈(递增栈)一次扫描解决。

复制代码
class Solution {
    public int largestRectangleArea(int[] heights) {
        int n = heights.length;
        int[] h = Arrays.copyOf(heights, n + 1);
        int ans = 0;
        Deque<Integer> stack = new ArrayDeque<>();
        for(int i = 0;i <= n;++i) {
            while(!stack.isEmpty() && h[i] < h[stack.peek()]) {
                int mid = stack.pop();
                int left = stack.isEmpty() ? -1 : stack.peek();
                int width = i - left - 1;
                ans = Math.max(ans, width * h[mid]);
            }
            stack.push(i);
        }
        return ans;
    }
}
相关推荐
Irene19911 分钟前
数据排序为什么默认升序
算法·排序
Devin~Y2 分钟前
大厂Java面试实录:Spring Boot/Cloud + Redis/Kafka + JWT + RAG/Agent(小Y翻车版)
java·spring boot·redis·spring cloud·kafka·spring security·jwt
Bat U14 分钟前
JavaEE|多线程(六)
java·java-ee
.54814 分钟前
DFS + BFS(深度优先搜索 & 广度优先搜索)
算法·深度优先·宽度优先
一行代码一行诗++17 分钟前
转义字符和语句
c语言·开发语言·算法
算法鑫探19 分钟前
算法与数据结构 以及算法复杂度
c语言·数据结构·算法·新人首发
胡利光19 分钟前
Context Engineering 实战 02|System Prompt 是架构决策,不是写说明书
java·架构·prompt
sinat_2554878121 分钟前
数组·学习笔记
java·javascript·笔记
江离w22 分钟前
codex等vibe coding初始化后端项目指令
java
Paxon Zhang23 分钟前
JavaEE 初阶大师之路之*线程,多线程编程,Thread类,变量捕获,中断线程* 一文全部搞懂!!
java·java-ee