剑指 Offer 30. 包含min函数的栈 / 剑指 Offer 31. 栈的压入弹出序列

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer 30. 包含min函数的栈 / 剑指 Offer 31. 栈的压入弹出序列相关的知识,希望对你有一定的参考价值。

剑指 Offer 30. 包含min函数的栈

题目描述

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。


示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.min();   --> 返回 -2.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

能使用两个栈和一个栈
使用两个栈就另外使用一个辅助栈来帮助最小值的获取,有两种方法,第一种是每次放入新元素的时候同时更新辅助栈的最小值,另一种方法是只有新元素较小的时候才更新辅助栈,下面是使用第二种方法

class MinStack {
    //因为要在O(1)的时间内调用三个方法,因此肯定需要一个辅助的数据结构来实现
    //主要是实现min的方法,主要是想每次弹出怎么保证当前辅助栈中的栈顶依然是最小值
    //然后就想到了每次压入栈的时候,更新辅助栈的栈顶
    //但是我的思维局限在了两个栈中的元素要相同,那样就得调整辅助栈中元素的位置,不好实现
    //因此,这里学习了解答的思维,每次压入元素的时候,辅助栈中并不是需要压入同样的数,而是压入对应栈顶高度的最小值就行了
    //或者只有小于辅助栈顶的时候选择压入,而大于的时候就不操作,在弹出的时候注意辅助栈顶和数据栈顶相同再弹出


    /** initialize your data structure here. */

    Stack<Integer> data;
    Stack<Integer> helper;
    public MinStack() {
        data = new Stack<Integer>();
        helper = new Stack<Integer>();
    }
    
    public void push(int x) {
        data.push(x);
        if(helper.isEmpty() || (!helper.isEmpty() && helper.peek() >= x)){
            helper.push(x);
        }
    }
    
    public void pop() {
        int x = data.pop();
        if(helper.peek() == x)
            helper.pop();
    }
    
    public int top() {
        return data.peek();
    }
    
    public int min() {
        return helper.peek();
    }
}

使用一个栈,三种方法,第一种其实和两个栈的第一种方法一样,就是现在用一个数对来存储当前元素和当前最小值,本质上没啥变化
第二种方法是用一个栈存储最小值,最小值更新的时候将新的最小值进行存储
第三种方法存储当前元素与最小值的差值,具体实现上因为是做差,要注意溢出的风险,要用long存储

class MinStack {
    Stack<int[]> stack;
    //创建一个栈,栈中元素是当前值和当前对应的最小值
    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack<>();
    }
    
    public void push(int x) {
        if(stack.isEmpty()){
            stack.push(new int[]{x ,x});
        }
        else{
            stack.push(new int[]{x, Math.min(x, stack.peek()[1])});
        }
    }
    
    public void pop() {
        //获得刚加进来的元素
        stack.pop();
    }
    
    public int top() {
        return stack.peek()[0];
    }
    
    public int getMin() {
        return stack.peek()[1];
    }
}
class MinStack {
    //又去详细看了一下别的题解,一个栈实现,第一种方法是存放最小值
    //在最小值发生改变的时候同时栈中存放当前最小值

    /** initialize your data structure here. */
    Stack<Integer> stack;
    int min = Integer.MAX_VALUE;
    public MinStack() {
        stack = new Stack<>();
    }
    
    public void push(int x) {
        //如果比当前最小值小了,就把min入栈
        if(x <= min){
            stack.push(min);
            min = x;
        }
        stack.push(x);
    }
    
    public void pop() {
        //如果把当前的最小值弹出了,要更新最小值
        if(stack.pop() == min){
            min = stack.pop();
        }
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int min() {
        return min;
    }
}
class MinStack {
    //又去详细看了一下别的题解,一个栈实现,第二种方法是存储和当前最小值的差值

    /** initialize your data structure here. */
    Stack<Long> stack;
    long min = Long.MAX_VALUE;
    public MinStack() {
        stack = new Stack<>();
    }
    
    public void push(int x) {
        if(stack.isEmpty()){
            min = x;
            stack.push(x - min);
            return;
        }
        stack.push(x - min);
        //如果比当前最小值小了,更新min
        if(x < min)
            min = x;
    }
    
    public void pop() {
        //如果把当前的最小值弹出了,要更新最小值
        if(stack.peek() < 0){
            min = min - stack.pop();
        }else{
            stack.pop();
        }
    }
    
    public int top() {
        if(stack.peek() < 0)
            return (int)(min);
        return (int)(min + stack.peek());
    }
    
    public int min() {
        return (int)min;
    }
}

剑指 Offer 31. 栈的压入、弹出序列

题目描述

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

模拟这个过程,因为要弹出的元素肯定在栈顶,不在栈顶就继续压入,如果把所有元素压入了还是没有找到要弹出的元素就false

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        //我能想到的就是模拟这个过程了
        //先判断要弹出的数字是不是在栈顶,有的话直接弹出栈顶,没有的话压入
        //如果把所有数字都压入栈中了,仍然找不到当前要弹出的数字,说明这个数字不存在或者说顺序不对
        int l = popped.length;
        int index = 0;  //指向弹出栈的序列下标
        //模拟压入过程的栈
        Stack<Integer> stack = new Stack<>();
        for(int i = 0; i < l; i++){
            //如果栈为空或者说栈顶元素和此时要弹出的元素不相等
            if(stack.isEmpty() || stack.peek() != popped[index]){
                stack.push(pushed[i]);
            }
            while(!stack.isEmpty() && stack.peek() == popped[index]){
                stack.pop();
                index++;
            }
        }
        return index == l;
    }
}

以上是关于剑指 Offer 30. 包含min函数的栈 / 剑指 Offer 31. 栈的压入弹出序列的主要内容,如果未能解决你的问题,请参考以下文章

剑指 Offer 30. 包含min函数的栈 / 剑指 Offer 31. 栈的压入弹出序列

剑指Offer打卡30.包含min函数的栈

剑指Offer打卡30.包含min函数的栈

剑指Offer打卡30.包含min函数的栈

剑指Offer30包含min函数的栈

剑指 Offer 30. 包含min函数的栈