栈和队列练习

栈的应用OJ题目

1. 括号匹配

题目描述
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

括号匹配OJ链接
代码示例:

class Solution {
    public boolean isValid(String s) {
        Stack<Character> st=new Stack<>();
        //遍历字符串
        for(int i=0;i<s.length();i++){
            char c=s.charAt(i);
            if(c == '('||c == '['||c == '{'){
                //如果是左括号就入栈
                st.push(c);
            }else{
                //如果是右括号就与栈顶元素比较,前提是栈不空,匹配的上就出栈
                if(st.empty()){
                    return false;//此时栈空,无法匹配
                }
                //获取栈顶元素,与c来进行匹配
                char pop=st.peek();
                if((pop=='('&&c==')')||(pop=='['&&c==']')||(pop=='{'&&c=='}')){
                    st.pop();
                    continue;
                }else{
                    return false;
                }
            }
        }
        //如果完全匹配,栈一定是空的,结果是true;
        if(st.empty()){
            return true;
        }else{
            return false;
        }
    }
}

2. 逆波兰表达式求值

逆波兰表达式又叫做后缀表达式。逆波兰表达式把运算量写在前面,把算符写在后面。

正常的表达式逆波兰表达式
a+ba,b,+
a+(b-c)a,b,c,-,+
a+(b-c)*da,d,b,c,-,*,+
a*(b+c)+da,b,c,+,*,d,+

有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明

  1. 整数除法只保留整数部分。
  2. 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

逆波兰表达式求值
代码示例:

import java.util.ArrayList;
import java.util.Stack;
class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> s=new Stack<>();
        for(String e:tokens){
            if(!((e.equals("+"))||(e.equals("-"))||
                    (e.equals("*"))||(e.equals("/")))){
                //如果是数字,就入栈,需要把字符串转为数字类型再入栈
                s.push(Integer.parseInt(e));
            }else{
                //如果是运算符,就从栈顶取出两个元素,进行运算,先取出的是右操作数、后取出的是左操作数
                int  right=s.pop();
                int left=s.pop();
                switch(e){
                    case "+":
                        s.push(left+right);
                        break;
                    case "-":
                        s.push(left-right);
                        break;
                    case "*":
                        s.push(left*right);
                        break;
                    case "/":
                        s.push(left/right);
                        break;
                }
            }
        }
        return s.peek();
    }
}

3. 出栈入栈次序匹配

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

  1. 0<=pushV.length == popV.length <=1000
  2. -1000<=pushV[i]<=1000
  3. popV 的所有数字均在 pushV里面出现过
  4. pushV 的所有数字均不相同

栈的压入弹出序列OJ链接
代码示例:

import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        Stack<Integer> s = new Stack<>();
        int inIndex = 0;
        int outIndex = 0;
        while (outIndex < popA.length) {

            while (s.empty() || s.peek() != popA[outIndex]) {
                if (inIndex < pushA.length) {
                    s.push(pushA[inIndex]);
                    inIndex++;
                } else {
                    return false;
                }
            }
            s.pop();
            outIndex++;
        }
        return true;
  }
}

4. 用队列实现栈

用队列实现栈OJ链接
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

  1. void push(int x) 将元素 x 压入栈顶。
  2. int pop() 移除并返回栈顶元素。
  3. int top() 返回栈顶元素。
  4. boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意
  你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
  你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
代码示例:

class MyStack {
        Queue<Integer> q1=new LinkedList<>();
        Queue<Integer> q2=new LinkedList<>();

    public MyStack() {

    }
    
    //入栈,哪个队列不空就往哪个里面放,保持其中一个队列为空
    public void push(int x) {
        if(q2.isEmpty()){
            q1.offer(x);
        }else{
            q2.offer(x);
        }
    }

    //出栈,哪个队列中有元素,就将哪个队列中的前n-1个元素搬移到另一个队列中,然后将此队列中的队头元素删除
    public int pop() {
        int ret=0;
        if(!q1.isEmpty()){
            //q1中有元素
            while(q1.size()>1){
                //把q1中的前n-1个元素放到q2中
                q2.offer(q1.poll());
            }
           //此时q1中只剩下一个队头元素,也就是栈顶元素
            ret=q1.poll();
        }else{
            //q2中有元素
            while(q2.size()>1){
                //把q2中的前n-1个元素放到q1中
                q1.offer(q2.poll());
            }
           //此时q2中只剩下一个队头元素,也就是栈顶元素
           ret=q2.poll();
        }
        return ret;
    }
    
    public int top() {
         int ret=0;
        if(!q1.isEmpty()){
            //q1中有元素
            while(q1.size()>1){
                //把q1中的前n-1个元素放到q2中
                q2.offer(q1.poll());
            }
           //此时q1中只剩下一个队头元素,也就是栈顶元素
            ret=q1.peek();
            q2.offer(q1.poll());
        }else{
            //q2中有元素
            while(q2.size()>1){
                //把q2中的前n-1个元素放到q1中
                q1.offer(q2.poll());
            }
           //此时q2中只剩下一个队头元素,也就是栈顶元素
           ret=q2.peek();
           q1.offer(q2.poll());
        }
        return ret;
    }
    
    public boolean empty() {
        return q1.isEmpty()&&q2.isEmpty();
    }
}

5. 用栈实现队列

用两个栈实现队列

class MyQueue {
    Stack <Integer> s1=new Stack<>();//用s1模拟入队列
    Stack <Integer> s2=new Stack<>();//用s2模拟出队列
    public MyQueue() {

    }
    
    public void push(int x) {
        s1.push(x);
    }
    
    public int pop() {
        if(s2.empty()){
            while(s1.size() >0){
                s2.push(s1.pop());
            }
        }
        return s2.pop();
    }
    
    public int peek() {
         if(s2.empty()){
            while(s1.size() >0){
                s2.push(s1.pop());
            }
        }
        return s2.peek();
    }
    
    public boolean empty() {
        return s1.empty()&&s2.empty();
    }
}

6. 实现一个最小栈

实现一个最下栈

class MinStack {
    //用两个栈来实现
    Stack<Integer> s1;//用s1来保存栈中的元素
    Stack<Integer> s2;//用s2来保存最小元素

    public MinStack() {
        s1=new Stack<>();
        s2=new Stack<>();
    }
    
    public void push(int val) {
        //入栈,如果s2是空的,将元素往s1、s2各压入一份
        if(s2.empty()){
            s1.push(val);
            s2.push(val);
        }else if(val>s2.peek()){
            //如果val>s2栈顶元素,就把val压入s1
                s1.push(val);
        }else{
            //如果val<=s2栈顶元素,就把val往s1、s2各压入一份
            s1.push(val);
            s2.push(val);
        }

    }
    
    public void pop() {
        //出栈,如果s1和s2栈顶元素相同,则s1和s2同时出栈
        //否则,只出栈s1
        if(s1.peek().equals(s2.peek())){//包装类型,不能直接用==来比较
            s1.pop();
            s2.pop();
        }else{
            s1.pop();
        }

    }
    
    public int top() {
        return s1.peek();
    }
    
    public int getMin() {
        return s2.peek();
    }
}

7. 设计循环队列

  设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
  循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作

  1. MyCircularQueue(k): 构造器,设置队列长度为 k 。
  2. Front: 从队首获取元素。如果队列为空,返回 -1 。
  3. Rear: 获取队尾元素。如果队列为空,返回 -1 。
  4. enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  5. deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  6. isEmpty(): 检查循环队列是否为空。
  7. isFull(): 检查循环队列是否已满。
class MyCircularQueue {
    int[] array;//用数组来存储元素
    int front=0;//队头
    int rear=0;//队尾
    int count=0;
    int N;
    public MyCircularQueue(int k) {
        array=new int[k];
        N=k;
    }
    
    public boolean enQueue(int value) {
        //向队列中插入元素
        if(isFull()){
            return false;
        }
        array[rear]=value;
        rear++;
        //如果存满了,要把rear重置为1;
        if(rear==N){
            rear=0;
        }
        count+=1;
        return true;
    }
    
    public boolean deQueue() {
        //出队列,从队头出
        if(isEmpty()){
            return false;
        }
        front++;
        front%=N;
        count-=1;
        return true;
    }
    
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return array[front];
    }
    
    public int Rear() {
          if(isEmpty()){
            return -1;
        }
        return array[(rear-1+N)%N];
    }
    
    public boolean isEmpty() {
        return count==0;
    }
    
    public boolean isFull() {
        return count==N;
    }
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值