【力扣一刷】代码随想录day10(栈和队列基础、232、 225)

【队列和栈基础】

一、Java中的栈(先进后出,左边栈底,右边栈顶)

1、Stack类创建栈和使用栈

import java.util.Stack;

public class StackExample {
    public static void main(String[] args) {
        // 创建一个Stack对象
        Stack<String> stack = new Stack<>();

        // 添加元素到堆栈中
        stack.push("元素1");
        stack.push("元素2");
        stack.push("元素3");

        // 获取堆栈的大小
        int size = stack.size();
        System.out.println("堆栈的大小:" + size);

        // 检查堆栈是否为空
        boolean isEmpty = stack.isEmpty();
        System.out.println("堆栈是否为空:" + isEmpty);

        // 查看堆栈顶部的元素,但不移除它
        String topElement = stack.peek();
        System.out.println("堆栈顶部的元素:" + topElement);

        // 移除堆栈顶部的元素
        String poppedElement = stack.pop();
        System.out.println("移除的元素:" + poppedElement);

        // 再次查看堆栈顶部的元素
        topElement = stack.peek();
        System.out.println("堆栈顶部的元素:" + topElement);
        
        // 遍历堆栈中的元素
        System.out.println("遍历堆栈中的元素:");
        while (!stack.isEmpty()) {
            String element = stack.pop();
            System.out.println(element);
        }
    }
}

上面代码的输出:

堆栈的大小:3
堆栈是否为空:false
堆栈顶部的元素:元素3
移除的元素:元素3
堆栈顶部的元素:元素2
遍历堆栈中的元素:
元素2
元素1

2、用LinkedList实现栈

import java.util.LinkedList;

public class MyStack {
    private LinkedList<String> stack;

    public MyStack() {
        stack = new LinkedList<>();
    }

    public void push(String element) {
        stack.addLast(element);
    }

    public String pop() {
        return stack.removeLast();
    }

    public String peek() {
        return stack.getLast();
    }

    public int size() {
        return stack.size();
    }

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

注意:Stack类是继承自Vector类的经典栈数据结构,而LinkedList是一个实现了List接口的双向链表。官方建议使用LinkedList来替代Stack类实现栈的功能,因为LinkedList的性能更好。

二、队列(先进先出,左边队头,右边队尾)

import java.util.LinkedList;
import java.util.Queue;

public class Main {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();

        // 向队尾插入元素
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);

        // 查看队首元素
        System.out.println("队首元素:" + queue.peek());

        // 出队
        int removedElement = queue.poll();
        System.out.println("出队元素:" + removedElement);

        // 再次查看队首元素
        System.out.println("队首元素:" + queue.peek());
    }
}

上面代码的输出:

队首元素:1
出队元素:1
队首元素:2

注意:

1、Queue接口定义了一些用于添加、删除和检索元素的方法,如 offer() 、 poll() 、peek()。

2、LinkedList是Java集合框架中的一个类,它实现了List接口,并且也实现了Queue接口。由于LinkedList是一个双向链表,它具有在两端进行高效插入和删除操作的特性,非常适合实现队列的功能。因此,可以利用多态的写法定义Queue对象,如:Queue<Integer> queue = new LinkedList<>();

3、通过LinkedList实现的Queue具有队列的特性,可以使用 offer() 方法向队列尾部添加元素,使用 poll() 方法从队列头部移除并返回元素,使用 peek() 方法获取队列头部的元素但不移除它。

【232.用栈实现队列】

class MyQueue {
    private Stack<Integer> stackIn;  // 负责进队
    private Stack<Integer> stackOut;  // 负责出队

    public MyQueue() {
        this.stackIn = new Stack<>();
        this.stackOut = new Stack<>();
    }
    
    public void push(int x) {
        stackIn.push(x);
    }
    
    public int pop() {
        // 注意:只有stackOut空的时候倒过去才符合队列的顺序
        if (stackOut.isEmpty()){
            pour();
        }
        return stackOut.pop();
    }
    
    public int peek() {
        if (stackOut.isEmpty()){
            pour();
        }
        return stackOut.peek();
    }
    
    public boolean empty() {
        return stackIn.isEmpty() && stackOut.isEmpty();
    }

    private void pour(){
        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();
 */

时间复杂度: O(n),pop()和peak()都要用pour(),都是O(n), empty()和push()都是O(1)

空间复杂度: O(n),两个栈 stackIn 和 stackOut都为 O(n)

【225. 用队列实现栈】

方法一   用两个队列实现栈,push简单,pop难

push:

pop:

class MyStack {
    Queue<Integer> queue1;
    Queue<Integer> queue2;
    
    public MyStack() {
        queue1 = new LinkedList<>(); // 负责进栈、存储栈元素
        queue2 = new LinkedList<>();  // 辅助出栈
    }
    
    public void push(int x) {
        queue1.offer(x);
    }
    
    public int pop() {
        int popElement = 0;  // 必须初始化否则会报错,保证在栈非空情况下调用pop的前提下,初始值可以为任意值
        // 1、将除了栈顶元素之外的元素压进queue2,获取栈顶元素
        while(!queue1.isEmpty()){
            popElement = queue1.poll();
            // 如果queue1弹出元素后就空了,证明弹出的元素是队尾元素,不需要再进queue2队
            if (!queue1.isEmpty()){
                queue2.offer(popElement);
            }
        }

        // 2、将queue1和queue2交换,让queue1始终负责进栈
        Queue<Integer> queue = queue1;
        queue1 = queue2;
        queue2 = queue;

        return popElement;
    }
    
    public int top() {
        // 利用出栈获取队尾元素
        int q = pop();
        // 再进栈恢复原始栈
        push(q);
        return q;
    }
    
    public boolean empty() {
        return queue1.isEmpty(); // queue1始终用于存储栈元素,判断queue1是否空即可
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

时间复杂度: O(n),pop()和top()都是O(n), empty()和push()都是O(1)

空间复杂度: O(n),使用的三个队列都为 O(n)

方法二   用两个队列实现栈,push难,pop简单

push:

pop:

class MyStack {
    Queue<Integer> queue1;
    Queue<Integer> queue2;

    public MyStack() {
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }
    
    public void push(int x) {
        // 1、先将x放入queue2暂存
        queue2.offer(x);
        // 2、再将queue1的元素压进queue2
        while(!queue1.isEmpty()){
            queue2.offer(queue1.poll());
        }
        // 3、将queue2和queue1互换
        Queue<Integer> queue = queue1;
        queue1 = queue2;
        queue2 = queue;
    }
    
    public int pop() {
        return queue1.poll();
    }
    
    public int top() {
        return queue1.peek();
    }
    
    public boolean empty() {
        return queue1.isEmpty();
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

时间复杂度: O(n),只有push()是O(n),其余都是O(1)

空间复杂度: O(n),使用的三个队列都为 O(n)

方法三  优化版,只用一个队列实现(对应方法一的优化)

class MyStack {
    Queue<Integer> queue;
    int size;

    public MyStack() {
        queue = new LinkedList<>();
        size = 0;
    }
    
    public void push(int x) {
        queue.offer(x);
        size++;
    }
    
    public int pop() {
        // 1、除了栈顶以外的元素循环出队进队
        for (int i = 0; i < size - 1; i++){
            queue.offer(queue.poll());
        }

        // 2、弹出栈顶元素
        size--;
        return queue.poll();
    }
    
    public int top() {
        int q = pop();
        push(q);
        return q;
    }
    
    public boolean empty() {
        return queue.isEmpty();
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

时间复杂度: O(n),pop()和top()都是O(n), empty()和push()都是O(1)

空间复杂度: O(n),使用一个队列为 O(n)

方法四  优化版,只用一个队列实现(对应方法二的优化)

class MyStack {
    Queue<Integer> queue;
    int size;

    public MyStack() {
        queue = new LinkedList<>();
        size = 0;
    }
    
    public void push(int x) {
        // 1、先将x压进栈
        queue.offer(x);
        size++;

        // 2、再调整顺序使x为栈顶元素
        for (int i = 0; i < size - 1; i++){
            queue.offer(queue.poll());
        }
    }
    
    public int pop() {
        size--;
        return queue.poll();
    }
    
    public int top() {
        return queue.peek();
    }
    
    public boolean empty() {
        return queue.isEmpty();
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

时间复杂度: O(n),只有push()是O(n),其余都是O(1)

空间复杂度: O(n),使用一个队列为 O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值