重生之我在代码随想录刷算法第九天 | 232.用栈实现队列、 225. 用队列实现栈、 20. 有效的括号、1047. 删除字符串中的所有相邻重复项

参考文献链接:代码随想录

本人代码是Java版本的,如有别的版本需要请上代码随想录网站查看。

232.用栈实现队列

力扣题目链接

解题思路

这道题目要用栈实现队列,那我们要先弄清楚这两个数据结构

栈是先进后出,队列是先进先出。那如何用两个栈实现队列呢。

假设我们现在要push元素到模拟队列中,那就会先进入一个栈中,push几个后堆积到一个栈中。

此时我们要pop的话,如何让先进去的先出来呢?

那就是把这个栈的元素都弹到另一个栈,这样最先进入的元素就到了另一个栈顶,这样就是先进先出的队列了。

代码示例

代码实现很简单,唯一要注意把第一个栈元素弹入第二个时要确保第二个里面没有元素。(因为第二个里的元素都是上次弹进来的,我们必须保证他们一一被pop掉才算先进先出,如果你再从第一个往里弹,那么他们就到栈底了就出不去了)

class MyQueue {

    Stack<Integer> stackIn;
    Stack<Integer> stackOut;
    
    public MyQueue() {
        stackIn = new Stack<>();
        stackOut = new Stack<>();
    }
    
    public void push(int x) {
        stackIn.push(x);
    }
    
    public int pop() {
        pushToAnother();
        return stackOut.pop();
    }
    
    public int peek() {
        pushToAnother();
        return stackOut.peek();
    }
    
    public boolean empty() {
        return stackIn.isEmpty() && stackOut.isEmpty();
    }

    public void pushToAnother(){
        if(!stackOut.isEmpty()) return;
        while(!stackIn.isEmpty())
            stackOut.push(stackIn.pop());
    }
}

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * boolean param_4 = obj.empty();
 */
遇到的问题

这道题容易出错的地方就是while循环的条件该不该带等于号,这种情况我一般会拿一组用例在自己脑子里过一遍。

假设{1,2,3}这组用例我们要找的target值是3,第一次循环的左下标是0,右下标是2,找到中间值是2比target值3小,所以我们将左下标调整为中间下标+1即为2,此时我们数组左右下标均为2,但目标值正好是下标2对应的值,所以应有left=right这个循环条件。

225. 用队列实现栈

力扣题目链接

解题思路

这道题目刚上手的时候还以为也要和栈实现队列一样两个队列实现一个栈,但其实只需要一个队列即可,接下来我会用两个队列一个队列分别讲解,并且使用Queue,Deque分别讲解,带你了解java中的Queue

Java中的队列

Queue是Collection的子类,Collection我们早已接触过了,List、Set都是他的子类。

我们先来介绍Queue

在这里插入图片描述

这是官方文档中的方法。

  • add就是加入元素到队列尾,成功为true,队列满就抛出异常。offer也是添加但队列满返回false
  • remove是移除元素,队列为空的话会抛异常,而poll则相反
  • element是查看队列头元素但不移除,如果队列为空则抛异常,peek的话队列为空返回null
  • size返回队列中的元素个数。
  • isEmpty判断队列是否为空。
Deque

Deque是一个双端队列

添加元素:
在这里插入图片描述

在这里插入图片描述

对于add两个方法,队列满无法添加就抛出异常,而offer是会返回false

删除元素:
在这里插入图片描述

在这里插入图片描述

其实也跟Queue中一样,如果队列为空poll返回null,remove则报异常

获取头尾元素:
在这里插入图片描述

在这里插入图片描述

一个道理,队列为空peek返回null,get会抛异常

Deque接口还可以用作栈(LIFO)的数据结构。

通过在队列头部执行插入和删除操作,可以实现栈的功能。常见的栈操作可以使用Deque接口中的以下方法来实现:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

使用方法和栈一样。

Deque接口的常见实现类包括ArrayDeque和LinkedList。

ArrayDeque是一个基于数组实现的双端队列,支持高效的随机访问和动态扩展。LinkedList是一个基于链表实现的双端队列,支持高效的插入和删除操作。

两个队列解题

我的思路是push时先放到queue1,当pop或者top时将queue1的其他元素放到queue2,只留一个元素去pop或者top,然后完事后再将queue2的元素移入queue1,因此我有两个方法toOne和toTwo。

class MyStack {

    Queue<Integer> queue1; 
    Queue<Integer> queue2;
    

    public MyStack() {
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }
    
    public void push(int x) {
       queue1.add(x);
    }
    
    public int pop() {
        toTwo();
        int result = queue1.poll();
        toOne();
        return result;
    }
    
    public int top() {
        toTwo();
        int result = queue1.peek();
        queue2.add(queue1.poll());
        toOne();
        return result;
    }
    
    public boolean empty() {
        return queue1.size() == 0;
    }

    public void toTwo(){
        while(queue1.size() != 1){
            queue2.add(queue1.poll());
        }
    }

    public void toOne(){
        while(queue2.size() != 0){
            queue1.add(queue2.poll());
        }
    }
}
一个队列解题

其实上述两个队列完全可以简化为一个队列,比如说队列中有1,2,3。我们此时要pop出3,我们可以先pop1然后push1,pop2再push2,这样3就到了队列最前面,弹出即可。

如下代码既是这样,push正常push即可,pop前要把除最后一个元素外其他元素都重新入队,这样队首就是该弹出的元素。

class MyStack {
    Queue<Integer> queue;
    
    public MyStack() {
        queue = new LinkedList<>();
    }
    
    public void push(int x) {
        queue.add(x);
    }
    
    public int pop() {
        rePosition();
        return queue.poll();
    }
    
    public int top() {
        rePosition();
        int result = queue.poll();
        queue.add(result);
        return result;
    }
    
    public boolean empty() {
        return queue.isEmpty();
    }

    public void rePosition(){
        int size = queue.size();
        size--;
        while(size-->0)
            queue.add(queue.poll());
    }
}

20. 有效的括号

力扣题目链接

解题思路

这道题目就是进行括号的匹配,看到这样的题目就该想到用栈去做。当前字符是左括号则入栈,如果是右括号,那就出栈一个跟其匹配,如果不匹配就不是有效的括号。for循环遍历完之后如果栈中没有元素则说明是有效的括号。

代码示例
class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i = 0;i < s.length();i++){
            char temp = s.charAt(i);
            if(temp == '}'){
                if(stack.empty() || stack.pop() != '{'){
                    return false;
                }
            }else if(temp == ')'){
                if(stack.empty() || stack.pop() != '('){
                    return false;
                }
            }else if(temp == ']'){
                if(stack.empty() || stack.pop() != '['){
                    return false;
                }
            }else{
                //左括号则入栈,上面三个情况的右括号则比较
                stack.push(temp);
            }
        }
        if(!stack.empty()){
            return false;
        }
        return true;
    }
}

1047. 删除字符串中的所有相邻重复项

力扣题目链接

解题思路

这道题目和上一题类似,很明显要用的栈的特性,因为他要变化的观察有没有重复的,那么我们用栈即可。

代码示例

如果栈内是空的就入栈,如果栈不为空,则把即将要入栈的元素和栈顶元素比较,如果是同一个字符,那就符合题意,把栈顶元素出栈,并且该入栈元素也不要入栈,这样就删除了同类字符。

class Solution {
    public String removeDuplicates(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i = 0;i < s.length();i++){
            char temp = s.charAt(i);
            if(!stack.empty() && stack.peek() == temp){
                stack.pop();
            }else{
                stack.push(temp);
            }
        }
        StringBuilder sb = new StringBuilder();
        while(!stack.empty()){
            sb.append(stack.pop());
        }
        return new String(sb.reverse());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值