力扣100题解及笔记 栈

 目录

1.力扣100题解及笔记 哈希-CSDN博客

2.力扣100题解及笔记 堆-CSDN博客

3.力扣100题解及笔记 栈-CSDN博客

4.力扣100题解及笔记 双指针-CSDN博客

5.力扣100题解及笔记 链表-CSDN博客

6.力扣100题解及笔记 二叉树-CSDN博客

7.力扣100题解及笔记 二分查找-CSDN博客

8.力扣100及题解 滑动窗口&子串-CSDN博客

9.力扣100题解及笔记 回溯-CSDN博客

10.力扣100题解及笔记 dp&多维dp-CSDN博客

11.力扣100题解及笔记 贪心-CSDN博客

12.力扣100题解及笔记 数组-CSDN博客

13.力扣100题解及笔记 技巧-CSDN博客

14.力扣100题解及笔记 矩阵-CSDN博客

15.力扣100题解及笔记 图论-CSDN博客

理论基础

递归调用

栈的自然特点就是后进先出,适合追踪递归调用的返回路径。

在函数调用时,程序会将当前函数的上下文信息存入调用栈,等递归返回时再从栈顶弹出。

典型问题

  • 递归求解问题(如阶乘、斐波那契数列)。
  • 深度优先搜索(DFS):栈用于追踪回溯路径

表达式求值

栈适合处理表达式的括号匹配、运算符优先级等问题。

通过栈来保存操作数和操作符,逐步求解表达式。

典型问题

  • 中缀表达式转后缀表达式
  • 计算后缀表达式
  • 括号匹配:检查括号是否成对匹配。

回溯

涉及回溯时,栈能够帮助保存状态并在必要时进行回退。

典型问题

  • 迷宫问题:使用栈保存走过的路径,以便回溯。
  • N皇后问题:每次尝试放置一个皇后,无法满足条件时回溯。

支持撤销

在应用程序中,当用户执行某个操作时,可以通过栈来记录之前的操作,从而实现撤销功能。

典型问题

  • 文本编辑器中的撤销/重做功能。
  • 浏览器的前进/后退按钮

树的遍历(非递归)

典型问题

  • 二叉树的中序、前序、后序遍历:利用栈来记录当前节点,以便在回溯时访问。

单调栈

栈中保留的都是比当前入栈元素大的值,从栈顶到栈底 的元素是单调递增

快速找到一个元素旁边第一个比它大或者比它小的元素

用一个栈来记录遍历过的元素下标i,本质是空间换时间

Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < array.length; i++) {
    while (!stack.isEmpty() && array[stack.peek()] >= array[i]) {
        int index = stack.pop();
        // 进行处理
    }
    stack.push(i);
}

20.有效括号

20. 有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
 

示例 1:

输入:s = "()"

输出:true

示例 2:

输入:s = "()[]{}"

输出:true

示例 3:

输入:s = "(]"

输出:false

示例 4:

输入:s = "([])"

输出:true

 

提示:

1 <= s.length <= 104
s 仅由括号 '()[]{}' 组成
class Solution {
    public boolean isValid(String s) {
        Deque<Character> d=new LinkedList<>();
        for(char c:s.toCharArray()){
            if(c=='(') d.push(')');
            else if(c=='[') d.push(']');
            else if(c=='{') d.push('}');
            else if(d.isEmpty()||d.peek()!=c) return false;
            else d.pop();//注意逻辑,else不能省,自己画图去
        }
    return d.isEmpty();
    }
}

155.最小栈

155. 最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。
 

示例 1:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.
 

提示:

-231 <= val <= 231 - 1
pop、top 和 getMin 操作总是在 非空栈 上调用
push, pop, top, and getMin最多被调用 3 * 104 次

辅助栈 minStack用于存放对应主栈不同时期的最小值

  • 普通栈 s = [9, 7, 8, 6, 5, 10, 2, 4, 1, 3]:存储所有元素。
  • 辅助栈 ms =[9, 7, 6, 5, 2, 1]:仅存储当前及历史的最小值。
class MinStack {
    Stack<Integer> s,ms;
    public MinStack() {//初始化堆栈对象
        s=new Stack<>();
        ms=new Stack<>();
    }
    public void push(int val) {//将元素val推入堆栈
        s.push(val);
        if(ms.isEmpty()||val<=ms.peek()) ms.push(val);//判断元素是否当前最小
    }
    public void pop() {//删除堆栈顶部的元素
        if(s.pop().equals(ms.peek())) ms.pop();//为了确保内容相等,而不是引用相等
    }
    
    public int top() {//获取堆栈顶部的元素
        return s.peek();
    }
    public int getMin() {//获取堆栈中的最小元素
        return ms.peek();
    }
}

方便新加入和删除元素的时候维护最小值

394.字符串解码

394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

 

示例 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 <= s.length <= 30
s 由小写英文字母、数字和方括号 '[]' 组成
s 保证是一个 有效 的输入。
s 中所有整数的取值范围为 [1, 300] 

'['嵌套开始 ']'嵌套

使用 LinkedList 双端队列模拟栈,addLast() 相当于 push()removeLast() 相当于 pop()

class Solution {
    public String decodeString(String s) {
        LinkedList<Integer> sm = new LinkedList<>();//栈模拟数字,每层嵌套的重复次数
        LinkedList<StringBuilder> sr = new LinkedList<>();//栈模拟字符串,每层嵌套时的部分结果
        StringBuilder res = new StringBuilder();
        int m = 0;
        for (char c : s.toCharArray()) {
            if (Character.isDigit(c))  m = m * 10 + (c - '0'); //数字,处理多位
            else if (c == '[') {//左括号,数字和字符入栈,同时重置m和res
                sm.addLast(m);
                sr.addLast(res);
                m = 0;
                res = new StringBuilder();
            } else if (c == ']') {//右括号,进行解码,存tmp用于重复
                StringBuilder tmp = res;
                res = sr.removeLast();//弹出以便下一次
                res.append(tmp.toString().repeat(sm.removeLast()));
            } else res.append(c); //普通字母
        }
        return res.toString();
    }
}

739.每日温度

739. 每日温度

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 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 <= temperatures.length <= 105
30 <= temperatures[i] <= 100
class Solution {
    public int[] dailyTemperatures(int[] t) { 
        int l = t.length;
        int[] r = new int[l];
        Deque<Integer> d = new ArrayDeque<>();//存“还没找到更高温度的那些天”的索引
        for (int i = 0; i < l; i++) {
            while (!d.isEmpty() && t[d.peekLast()] < t[i]) {//当前温度比栈顶温度高
                int j = d.pollLast(); //找到了,弹出对应索引
                r[j] = i - j;//找到的和现在差了几天
            }
            d.addLast(i);//比较后加入表示没找到

        }
        return r;
    }
}

84.最大矩形h

84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。



输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10



输入: heights = [2,4]
输出: 4
 

提示:

1 <= heights.length <=105
0 <= heights[i] <= 104

第 i 位置最大面积:

 i 为中心,向左找第一个小于 heights[i] 的位置 left_i;向右找第一个小于于 heights[i] 的位置 right_i,即最大面积为 heights[i] * (right_i - left_i -1)

—>找right_i 和 left_i

class Solution {
    public int largestRectangleArea(int[] h) {
        ArrayDeque<Integer> d = new ArrayDeque<>();
        int a = 0;
        for (int i = 0; i <= h.length; i++) {
            int curh = (i == h.length) ? 0 : h[i];//末尾假设有一个额外的高度为0的柱子
            while (!d.isEmpty() && h[d.peek()] >= curh) {//小于
                int height = h[d.pop()];
                int width = d.isEmpty() ? i : i - d.peek() - 1; //最左边的柱子宽度为i;其余左边界为i减去栈顶索引再减1
                a = Math.max(a, height * width);
            }
            d.push(i);//存柱子的索引
        }
        return a;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值