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;
    }
}
相关推荐
无敌憨憨大王2 小时前
DFS(深搜)
算法·深度优先·图论
Gin3872 小时前
SpringBoot实现文件上传和下载
java·spring boot·后端
sqyno1sky2 小时前
代码动态生成技术
开发语言·c++·算法
圣保罗的大教堂2 小时前
leetcode 1727. 重新排列后的最大子矩阵 中等
leetcode
蓝天星空2 小时前
C# .net闭源与Java开源框架的对比
java·c#·.net
superior tigre2 小时前
347 前k个高频元素
数据结构·算法·leetcode
金牌归来发现妻女流落街头2 小时前
【用 Java API Client 操作 Elasticsearch】
java·elasticsearch·jenkins
Seven972 小时前
调试排错 - 线程Dump分析
java
2401_853576502 小时前
C++中的策略模式变体
开发语言·c++·算法