代码随想录算法训练营第十天 | LeetCode 232.用栈实现队列、LeetCode 225. 用队列实现栈

 代码随想录算法训练营第十天 | LeetCode 232.用栈实现队列、LeetCode 225. 用队列实现栈

文章链接:代码随想录用栈实现队列        代码随想录用队列实现栈

视频链接:代码随想录用栈实现队列        代码随想录用队列实现栈

目录

 代码随想录算法训练营第十天 | LeetCode 232.用栈实现队列、LeetCode 225. 用队列实现栈

1. 栈与队列理论基础

1.1 栈-概念

1.2 栈-使用

1.3 栈-模拟实现

1.4 队列-概念

1.5 队列-使用

1.6 队列-模拟实现

2. LeetCode 232. 用栈实现队列

2.1 思路

2.2 代码

3. LeetCode 225. 用队列实现栈

3.1 思路

3.2 代码

3.3 用两个队列实现栈的代码


1. 栈与队列理论基础

1.1 栈-概念

:一种特殊的线性表,其 只允许在固定的一端进行插入和删除元素操作 。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO Last In First Out )的原则。
压栈:栈的插入操作叫做进栈 / 压栈 / 入栈, 入数据在栈顶
出栈:栈的删除操作叫做出栈。 出数据在栈顶

1.2 栈-使用

Stack 继承了 Vector Vector ArrayList 类似,都是动态的顺序表,不同的是 Vector 是线程安
全的。

1.3 栈-模拟实现

public class MyStack {
    private int[] elem;
    private int usedSize;

    public MyStack() {
        this.elem = new int[5];//初始长度为5,随你定
    }

    //入栈
    public void push(int val) {
        if (isFull()) {
            elem = Arrays.copyOf(elem, 2 * elem.length);//如果满了扩容
        }
        elem[usedSize] = val;
        usedSize++;
    }

    //栈是否满
    public boolean isFull() {
        return usedSize == elem.length;
    }

    //出栈
    public int pop() {
        //判断栈是否为空
        if (empty()) {//抛出栈空异常
            throw new StackEmptyException("栈为空");
        }
        //开始删除
        //这种删除方法原理就是把usedSize往前挪,原本最后位置的元素就放在那但没法调用了,下次添加元素就直接覆盖
        return elem[--usedSize];//如果是return elem[usedSize--]就没有返回最后的元素,是返回最后元素的下一个位置
    }

    //栈是否为空
    public boolean empty() {
        return usedSize == 0;
    }

    //获取栈顶元素,但不弹出
    public int peek() {
        //判断栈是否为空
        if (empty()) {//抛出栈空异常
            throw new StackEmptyException("栈为空");
        }
        //开始获取
        return elem[usedSize - 1];//不用删除,只需要获取
    }

    //递归打印
    public void recursivePrint(MyStack stack) {
        if (!stack.empty()) {
            int value = stack.pop(); // 弹出栈顶元素
            recursivePrint(stack); // 递归打印剩余栈中的元素
            System.out.print(value + " "); // 打印当前弹出的元素
            stack.push(value); // 将元素重新压回栈中,保持栈的原有状态
        }
    }
}

1.4 队列-概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)。
入队列:进行插入操作的一端称为队尾(Tail/Rear
出队列:进行删除操作的一端称为队头 Head/Front)

1.5 队列-使用

Java 中, Queue 是个接口,底层是通过链表实现 的。
注意: Queue 是个接口,在实例化时必须实例化 LinkedList 的对象,因为 LinkedList 实现了 Queue 接口。

1.6 队列-模拟实现

public class MyQueue {
    static class ListNode{
        public int val;
        public ListNode next;//单链表实现队列

        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head;
    public ListNode last;//方便实现单链表的尾插法

    public int usedSize;

    //入队操作(单链表的尾插法)
    public void offer(int val){
        ListNode node=new ListNode(val);
        if(head==null){
            head=node;
            last=node;
        }else{
            last.next=node;
            last=last.next;
        }
    }

    public int getUsedSize(){
        return usedSize;
    }

    //弹出元素(单链表的删除头节点)
    public int poll(){
        if(head==null){
            return -1;
        }
        int val=-1;
        if(head.next==null){
            val=head.val;
            head=null;
            last=null;
            return val;
        }
        val= head.val;
        head=head.next;
        usedSize--;
        return val;
    }

    //获取队头元素
    public int peek(){
        if(head==null){
            return -1;
        }
        return head.val;
    }
    
}

2. LeetCode 232. 用栈实现队列

2.1 思路

  1. 队列是先进先出的,栈是先进后出的,用一个栈模拟队列的先进先出的行为是不可能的,肯定是先进后出,因此借用另一个栈
  2. 此时两个栈一个叫输入栈一个叫输出栈,类似负负得正的思想,做两次先进后出就做到了先进先出的操作了
  3. 进队:这个操作很简单,全部进入输入栈
  4. 出队:这个操作比较难,当输出栈为空时,就需要把输入栈的元素全部按照栈出栈的方式然后进入输出栈,此时顺序就是一致的了,一直到输出栈为空才把输入栈的元素全部放入到输出栈中,注意是全部,如果不是全部,那顺序会乱的
  5. 查看队首元素:类似出队的方式,只是不要弹出,只是查看
  6. 判断队列是否为空:输入栈和输出栈均为空则模拟队列为空
  7. 注意,定义stack1和stack2时不要在构造方法里声明创建,这样是局部变量的,下面的方法访问不到,因此要声明为全局变量

2.2 代码

class MyQueue {

    Stack<Integer> stackIn;
    Stack<Integer> stackOut;

    /** Initialize your data structure here. */
    public MyQueue() {
        stackIn = new Stack<>(); // 负责进栈
        stackOut = new Stack<>(); // 负责出栈
    }
    
    /** Push element x to the back of queue. */
    public void push(int x) {
        stackIn.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    public int pop() {    
        dumpstackIn();
        return stackOut.pop();
    }
    
    /** Get the front element. */
    public int peek() {
        dumpstackIn();
        return stackOut.peek();
    }
    
    /** Returns whether the queue is empty. */
    public boolean empty() {
        return stackIn.isEmpty() && stackOut.isEmpty();
    }

    // 如果stackOut为空,那么将stackIn中的元素全部放到stackOut中
    private void dumpstackIn(){
        if (!stackOut.isEmpty()) return; 
        while (!stackIn.isEmpty()){
                stackOut.push(stackIn.pop());
        }
    }
}

3. LeetCode 225. 用队列实现栈

3.1 思路

  1. 可用一个队列实现模拟实现栈,也可用两个队列实现,下面将一个队列的
  2. 这里关键在于出栈操作:我们按照正常顺序入队1、2、3,正常顺序入栈1、2、3,按照栈应该弹出的是3先,但队列是先弹出1,因此我们让前两个元素依次进行出队、入队的操作,就是先出队然后立刻入队,这样原来的队首元素就跑到队尾了,直到进行到元素3才停止,这时出队就是3了
  3. 问题关键:怎么知道先把1、2先弹出,然后再弹出3,那么我们假设队列有size个元素,就把size-1个元素依次先弹出再入队,然后再把原本最后一个元素弹出即可

3.2 代码

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());
    }
}

3.3 用两个队列实现栈的代码

class MyStack {
    //q1作为主要的队列,其元素排列顺序和出栈顺序相同
    Queue<Integer> q1 = new ArrayDeque<>();
    //q2仅作为临时放置
    Queue<Integer> q2 = new ArrayDeque<>();

    public MyStack() {

    }
    //在加入元素时先将q1中的元素依次出栈压入q2,然后将新加入的元素压入q1,再将q2中的元素依次出栈压入q1
    public void push(int x) {
        while (q1.size() > 0) {
            q2.add(q1.poll());
        }
        q1.add(x);
        while (q2.size() > 0) {
            q1.add(q2.poll());
        }
    }

    public int pop() {
        return q1.poll();
    }

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

    public boolean empty() {
        return q1.isEmpty();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二天的算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值