使用Java中的栈和队列 + 栈习题

目录

一、如何在Java中使用栈和队列。

1. 操作队列的方法:

2.  操作栈的方法:

二、 关于栈的习题练习

1. 有效的括号

2. 逆波兰表达式求值

3. 栈的压入、弹出序列


一、如何在Java中使用栈和队列。

1. 操作队列的方法:

(1) 创建队列:  Queue<String> queue = new LinkedList<>();

(2) 入队列:  queue.offer("×××"); 

(3) 出队列: String e = queue.poll();

(4) 查看队首元素: String e = queue.peek();

(5) 查看队列是否是空的(empty): boolean b = queue.isEmpty();

(6) 查看队列中的元素个数: int s = queue.size();

(7) 清空队列: queue.clear();

2.  操作栈的方法:

(1) 创建栈: Deque<String> stack = new LinkedList<>();

(2) 压栈: stack.push();

(3) 弹栈: String e = stack.pop();

(4) 查看栈顶元素: String e = stack.peek();

(5) 查看栈是否是空的(empty): boolean b = stack.isEmpty();

(6) 查看栈中的元素个数: int s = stack.size();

(7) 清空栈: stack.clear();

队列:Queue         offer / poll / peek

栈: Deque            push / pop / peek

二、 关于栈的习题练习

1. 有效的括号

题目:

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

有效字符串需满足:

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

示例:

输入:s = "()"

输出true

思路:使用栈

栈中存放左括号,将字符串利用 toCharArray() 方法转换为字符数组用来进行遍历比较。遇到左括号就放入栈中,遇到右括号就跟栈的栈顶元素进行比较配对。如果该右括号不能和栈顶元素的左括号匹配(如" [ " 和 " } ")则不满足题目要求,返回 flase;若该右括号匹配成功,则删除栈顶元素,并且进行下一轮的判断。

代码:

class Solution {
    public boolean isValid(String s) {
        Deque<Character> stack = new LinkedList<>();
        char[] array = s.toCharArray();
        for (char i : array){
            if (i == '(' || i == '[' || i == '{'){
                // 如果是左括号,入栈
                stack.push(i);
            } else {
                //代码执行到这里说明是右括号
                if (stack.isEmpty()){
                    //说明遇见了一个没有左括号的右括号,返回 false
                    return false;
                }
                //代码执行到这里,说明栈中有左括号,进行比较
                //如果匹配失败,返回 false
                //如果匹配成功,进行下一轮的判断匹配
                char e = stack.pop();
                if (!isMatch(e,i)){
                    return false;
                }
            }
        }
        //循环结束,说明每个右括号都有匹配的左括号,但是还要确保栈里没有元素,即所有的左括号和右括号都配对成功
        if (stack.isEmpty()){
            return true;
        } else {
            return false;
        }

    }
    public boolean isMatch(char a,char b){
        if (a == '(' && b == ')') {
            return true;
        }
        if (a == '[' && b == ']') {
            return true;
        }
        if (a == '{' && b == '}') {
            return true;
        }
        return false;

    }
}

2. 逆波兰表达式求值

题目: 

根据 逆波兰表示法,求表达式的值。

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

注意 两个整数之间的除法只保留整数部分。

可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

思路:利用栈

遇到运算数就入栈,当遇到运算符时,就出栈两个元素进行运算,运算后的结果再接着入栈。

代码:

class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Long> stack = new LinkedList<>();
        for (String i : tokens){
            //遍历过程中,要最先判断是运算数还是运算符
            if (!isOperator(i)){
                //代码执行到这里说明是运算数
                //此时 tokens 中的元素都是 String 类型,但是我们需要运算所以要将 String 转换为 long 类型
                Long e = Long.parseLong(i);
                stack.push(e);
            } else {
                //代码执行到这里说明是运算符,要连续两次取出栈顶元素跟该运算符进行运算,再将运算后的结果压入栈中
                long n2 = stack.pop();
                long n1 = stack.pop();
                long a = calc(n1,n2,i);
                stack.push(a);
            }
        }
        //循环结束,栈中剩下一个元素,即波兰表达式的结果值
        long n = stack.pop();
        return (int)n;
    }
    public long calc(long n1,long n2,String i) {
        if (i.equals("+")){
            return n1 + n2;
        }
        if (i.equals("-")){
            return n1 - n2;
        }
        if (i.equals("*")){
            return n1 * n2;
        }
        if (i.equals("/")){
            return n1 / n2;
        }
        return -1;
    }
    public boolean isOperator(String i) {
        if (i.equals("+")){
            return true;
        }
        if (i.equals("-")){
            return true;
        }
        if (i.equals("*")){
            return true;
        }
        if (i.equals("/")){
            return true;
        }
        return false;
    }
}

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. pushV 的所有数字均不相同

示例:

输入:[ 1 , 2 , 3 , 4 , 5 ] , [ 4 , 5 , 3 , 2 , 1 ]

返回值: true

说明: 可以通过

            push( 1 ) =>  push( 2 ) =>  push( 3 ) =>  push( 4 ) => pop( ) => push( 5 ) => pop( ) => pop( ) => pop( ) => pop( ) 这样的顺序得到[ 4 , 5 , 3 , 2 , 1  ] 这个序列,返回 true

思路:使用栈

  定义两个int类型的数组用来接收数据,但是为了方便操作,再将数组转化为链表。同时创建一个栈来完成判断。

  取出第二个序列的第一个元素,判断栈顶元素是否为第二个序列的第一个元素,如果没有这个元素,则将入栈序列中的元素依次压入栈中,直到栈顶元素为第二个序列的第一个元素为止;然后删除第二个序列的该元素,再依次判断剩下的元素。

  考虑失败的情况:① 两个列表的长度不相等;② 当要从入栈的链表中取元素时,入栈链表为空。

代码: 

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
      if (pushA.length != popA.length) {
            return false;
        }
        //将数组转化成链表,便于操作
        LinkedList<Integer> pushLinkedList = intArrayToList(pushA);
        LinkedList<Integer> popLinkedList = intArrayToList(popA);
        //创建栈
        Deque<Integer> stack = new LinkedList<>();
        //外层循环,循环整个出栈链表,对每个出栈元素进行判断
        while (!popLinkedList.isEmpty()) {
            int e = popLinkedList.remove(0);
            //内层循环,将入栈链表的元素 按照规则 压入栈中
            while(stack.isEmpty() || stack.peek() != e) {
                if (pushLinkedList.isEmpty()){
                    return false;
                }
                stack.push(pushLinkedList.remove(0));
            }
            //代码执行到这里,说明 栈不为空 并且 栈顶元素 等于 出栈链表的第一个元素,说明这个元素可以 弹出栈
            //所以判断完的栈顶元素弹出,进行下一个循环判断
            stack.pop();
        }
        //代码执行到这里说明外层循环顺利结束,没有中途退出
        return true;
    }
    public LinkedList<Integer> intArrayToList(int[] array) {
        LinkedList<Integer> list = new LinkedList<>();
        for (int i : array){
            list.add(i);
        }
        return list;
    }
}

注意:

    || :短路或,所以前后两个语句顺序不可换。前者的条件不成立,后者不再进行判断,直接返回 false ;前者条件成立,后者再进行判断。

如果将本题中的内层循环

stack.isEmpty() || stack.peek() != e

改为

stack.peek() != popE || stack.isEmpty()

就会报错,因为是短路或,最开始的时候 stack 栈为空(null),无法调用 peek() 方法。所以顺序不可换。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值