栈的相关算法

我们都知道栈和队列是两种很相似的数据结构,但是又有他们的特点

  • 栈是一种先进后出的数据结构,FILO(先进后出)

  • 队列是一种先进先出的数据结构,FIFO(先进先出)

本文主要关注几道leetcode上关于栈的题目,进而进一步熟悉使用栈

有效的括号表达式

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

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 注意空字符串可被认为是有效字符串。
输入: "()"
输出: true

输入: "()[]{}"
输出: true

输入: "([)]"
输出: false

我们知道,栈的一大应用就是用来检查表达式或者编译器的语法正确性,栈是检查是否每件事情都能成一对的好工具

public class IsValid {

    /**
     * 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
     *
     * 有效字符串需满足:
     *
     * 左括号必须用相同类型的右括号闭合。
     * 左括号必须以正确的顺序闭合。
     * 注意空字符串可被认为是有效字符串。
     */

    /**
     * 判断括号正确性
     * @param s
     * @return
     */
    public boolean isValid(String s) {
        // 使用栈数据结构来解决这道题
        Stack<Character> stack = new Stack<>();
        // 将字符串转为字符数组,依次进栈
        char[] charArray = s.toCharArray();

        for(char c : charArray){
            // 如果栈为空则,push进栈
            // 如果栈不为空,则判断要进栈的元素和栈顶元素是否匹配
            // 如果匹配则pop弹出栈顶元素
            // 不匹配则继续进栈
            // 最后判断栈是否为空,为空则表示全部匹配成功
            if(stack.size()==0){
                stack.push(c);
            }else if(isMatch(stack.peek(),c)){
                stack.pop();
            }else{
                stack.push(c);
            }

        }
        return stack.size() == 0;
    }

    // 判断两个符号是否匹配
    public boolean isMatch(char c1,char c2) {
        if ((c1 == '(' && c2 == ')') || (c1 == '{' && c2 == '}') || (c1 == '[' && c2 == ']')) {
            return true;
        } else {
            return false;
        }
    }
}

辅助栈

最小栈

实现一个最小栈,保证以线性时间从栈中返回栈中最小元素

要实现最小栈,关键就是如何构建栈,我们需要一个辅助栈,该辅助栈只存一个最小元素,一个是正常栈,存放每次压栈元素,所以,在正常栈的进栈的时候,要进行一个比较,即最小栈中栈顶元素和要插入的元素进行比较

public class MinStack {

    /**
     * <h>最小栈</h>
     * <li>push(x) -- 将元素 x 推入栈中。</li>
     * <li>pop() -- 删除栈顶的元素。</li>
     * <li>top() -- 获取栈顶元素。</li>
     * <li>getMin() -- 检索栈中的最小元素。</li>
     */

    Stack<Integer> stack;
    Stack<Integer> minStack;

    /**
     * initialize your data structure here.
     */
    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();
    }

    public void push(int x) {
        stack.push(x);
//        if (minStack.isEmpty() || x <= minStack.peek()) {
//            minStack.push(x);
//        }
        if(minStack.isEmpty()){
            minStack.push(x);
        }else{
            int min = minStack.pop();
            if(min > x){
                minStack.push(x);
            }else{
                minStack.push(min);
            }
        }
    }

    public void pop() {
        if (stack.peek().equals(minStack.peek())) {
            minStack.pop();
        }
        stack.pop();
    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return minStack.peek();
    }
}

最大栈

public class MaxStack {

    /**
     * <h>最大栈</h>
     * <li>push(x) -- 将元素 x 推入栈中。</li>
     * <li>pop() -- 删除栈顶的元素。</li>
     * <li>top() -- 获取栈顶元素。</li>
     * <li>getMax() -- 检索栈中的最大元素。</li>
     */

    Stack<Integer> stack;
    Stack<Integer> maxStack;

    /**
     * initialize your data structure here.
     */
    public MaxStack() {
        stack = new Stack<>();
        maxStack = new Stack<>();
    }

    public void push(int x) {
        stack.push(x);
         //我希望维护的最大栈是只有一个栈元素的辅助栈
//        if(maxStack.isEmpty() || maxStack.peek() <= x){
//            maxStack.push(x);
//        }
        if(maxStack.isEmpty()){
            maxStack.push(x);
        }else{
            int max = maxStack.pop();
            if(max < x){
                maxStack.push(x);
            }else {
                maxStack.push(max);
            }
        }
    }

    public void pop() {
        if(stack.peek().equals(maxStack.peek())){
            maxStack.pop();
        }
        stack.pop();
    }

    public int top() {
        return stack.peek();
    }

    public int getMax() {
        return maxStack.peek();
    }

    public boolean isEmpty(){
        return stack.isEmpty();
    }


    public static void main(String[] args) {
        MaxStack maxStack = new MaxStack();
        maxStack.push(1);
        maxStack.push(5);
        maxStack.push(32);
        maxStack.push(2);
        maxStack.push(1);
        maxStack.push(0);
        System.out.println(maxStack.getMax());
    }
}

栈实现队列

使用辅助栈实现队列也是一个不错的选择,栈是一个先进后出的结构,队列是一个先进先出的结构,我们能使用双栈实现,进栈还是正常的压入正常栈,但是在出栈的时候,要满足队列的先进先出的特性,所以,出栈出来的应该是栈底元素而不是栈顶元素,所以就需要用到辅助栈,在出栈时,将正常栈的元素一个一个从正常栈栈顶到栈底转移到辅助栈,当正常栈是空时,辅助栈栈顶元素就是刚刚正常栈的栈底元素,完成队列出队即将辅助栈栈顶元素出栈即可

public class MyQueue {

    /**
     * <h>用栈实现队列</h>
     * <li>push(x) -- 将一个元素放入队列的尾部。</li>
     * <li>pop() -- 从队列首部移除元素。</li>
     * <li>peek() -- 返回队列首部的元素。</li>
     * <li>empty() -- 返回队列是否为空。</li>
     *
     */
    //基于两个栈实现一个队列

    Stack<Integer> stack;
    Stack<Integer> temp;

    /** Initialize your data structure here. */
    public MyQueue() {
        stack = new Stack<>();
        temp = new Stack<>();
    }

    /** Push element x to the back of queue. */
    public void push(int x) {
        stack.push(x);
    }

    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        if(temp.isEmpty()) {
            int size = stack.size();
            for (int i = 0; i < size; i++) {
                int data = stack.pop();
                temp.push(data);
            }
        }
        return temp.pop();
    }

    /** Get the front element. */
    public int peek() {
        if(temp.isEmpty()) {
            int size = stack.size();
            for (int i = 0; i < size; i++) {
                int data = stack.pop();
                temp.push(data);
            }
        }
        return temp.peek();
    }

    /** Returns whether the queue is empty. */
    public boolean empty() {
        return temp.isEmpty() && stack.isEmpty();
    }
}

其他数据结构实现栈

上边使用栈实现了一个简单的队列,其实也可以用栈来实现一个简单的队列

基于双端队列实现栈,栈的操作就是双端队列的队尾的操作

public class MyStack {

    /**
     * <h>队列实现栈</h>
     * <li>push(x) -- 元素 x 入栈</li>
     * <li>pop() -- 移除栈顶元素</li>
     * <li>top() -- 获取栈顶元素</li>
     * <li>empty() -- 返回栈是否为空</li>
     */

    //也可以基于双端队列实现,deque实际上是由双向链表组成的双端队列 Linkedist implements Deque<T>

    Deque<Integer> deque;

    /** Initialize your data structure here. */
    public MyStack() {
       deque = new LinkedList<>();
    }

    /** Push element x onto stack. */
    public void push(int x) {
        deque.addLast(x);
    }

    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return deque.removeLast();
    }

    /** Get the top element. */
    public int top() {
        return deque.getLast();
    }

    /** Returns whether the stack is empty. */
    public boolean empty() {
        return deque.isEmpty();
    }
}

基于双向链表来实现栈,就是尾节点的部分的操作

public class MyStack {

    /**
     * <h>队列实现栈</h>
     * <li>push(x) -- 元素 x 入栈</li>
     * <li>pop() -- 移除栈顶元素</li>
     * <li>top() -- 获取栈顶元素</li>
     * <li>empty() -- 返回栈是否为空</li>
     */

    //基于双向链表linkedList实现栈,linkedList尾部就是栈顶

    List<Integer> list;

    /** Initialize your data structure here. */
    public MyStack() {
       list = new LinkedList<>();
    }

    /** Push element x onto stack. */
    public void push(int x) {
        list.add(x);
    }

    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        int length = list.size();
        return list.remove(length);
    }

    /** Get the top element. */
    public int top() {
        int length = list.size();
        return list.get(length);
    }

    /** Returns whether the stack is empty. */
    public boolean empty() {
        return list.isEmpty();
    }
}

逆序栈

比如 一个栈 入栈是 1 2 3 4 5 栈顶是5

我们想这个栈的 顺序变成 5 4 3 2 1 栈顶是1

递归实现

    /**
     * 递归获得栈底元素
     * @param stack
     * @return
     */
    public static int getTop(Stack<Integer> stack){
        int top = stack.pop();
        if (stack.isEmpty()){
            return top;
        }
        //下一个元素
        int next = getTop(stack);
        stack.push(top);
        return next;
    }

    /**
     * 将递归获得的栈底元素重新入栈
     * @param stack
     */
    public static void reverseStack(Stack<Integer> stack){
        if(stack.isEmpty()){
            return;
        }
        int next = getTop(stack);
        reverseStack(stack);
        stack.push(next);
    }

辅助栈实现

    /**
     * 使用非递归双栈实现栈的逆序
     */
    public static Stack reverse(Stack<Integer> stack){
        Stack<Integer> tmp = new Stack<>();
        while(!stack.isEmpty()){
            tmp.push(stack.pop());
        }
        return tmp;
    }

单栈实现

    /**
     * 非递归单栈解决栈逆序问题
     * @param stack
     * @return
     */
    public static Stack reverse2(Stack<Integer> stack){
        List<Integer> list = new ArrayList<>();
        while(!stack.isEmpty()){
            list.add(stack.pop());
        }
        while(list.size()!=0){
            stack.push(list.remove(list.size()-1));
        }
        return stack;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值