【剑指offer】栈与队列4题 全刷(详解)

news2024/10/6 8:30:14

目录

目录

目录

[简单]剑指 Offer 09. 用两个栈实现队列

题目

方法

[简单]剑指 Offer 30. 包含min函数的栈

题目

方法1:笨办法

方法2:辅助栈

[困难]剑指 Offer 59 - I. 滑动窗口的最大值

题目

方法:单调队列

[中等]剑指 Offer 59 - II. 队列的最大值

题目

方法1:暴力for

方法2:辅助双端队列

心得


[简单]剑指 Offer 09. 用两个栈实现队列

题目

        用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

 剑指 Offer 09. 用两个栈实现队列 - 力扣(LeetCode)

方法

思路

将一个栈当作输入栈,用于压入 appendTail 传入的数据;另一个栈当作输出栈,用于 deleteHead操作。

每次 deleteHead时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。

 代码

class CQueue {
    Stack<Integer> stack1 ;
    Stack<Integer> stack2 ;
    public CQueue() {
        stack1 = new Stack<>();//入栈
        stack2 = new Stack<>();//出栈

    }

    public void appendTail(int value) {
        stack1.add(value);
    }

    public int deleteHead() {
        //先看 出栈 空就 把入栈的数据全部倒入到出栈
        if (stack2.isEmpty()){
            if (!stack1.isEmpty()){
                while (!stack1.isEmpty()){
                    stack2.add(stack1.pop());
                }
            }
        }

        if (!stack2.isEmpty()){
            int res = stack2.pop();
            return res;
        }else return -1;


    }
}

效果

[简单]剑指 Offer 30. 包含min函数的栈

题目

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.min();   --> 返回 -2.

剑指 Offer 30. 包含min函数的栈 - 力扣(LeetCode)

方法1:笨办法

思路

求最小值?直接用迭代器遍历这个栈,找到最小值。

朴实无华

代码

class MinStack {
    Stack<Integer> stack ;
    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack<>();
    }

    public void push(int x) {
        stack.push(x);
    }

    public void pop() {
        stack.pop();
    }

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

    public int min() {
        int min = stack.peek();
        Iterator iterator = stack.iterator();

        while (iterator.hasNext()) {
            Integer next = (Integer) iterator.next();
            if (min > next){
                min = next;
            }
        }
        return min;
    }
}

 效果

 效果超级低,可见这个方法真的无脑、不好

我总是能第一时间想出最蠢的办法

方法2:辅助栈

思路

根据题意,我们需要在常量级的时间内找到最小值!

这说明,我们绝不能在需要最小值的时候,再做排序,查找等操作来获取!

所以,我们可以创建两个栈,一个栈是主栈,另一个是辅助栈 ,用于存放对应主栈不同时期的最小值。

 代码

class MinStack {
    Deque<Integer> xStack;
    Deque<Integer> minStack;

    public MinStack() {
        xStack = new LinkedList<Integer>();
        minStack = new LinkedList<Integer>();
        minStack.push(Integer.MAX_VALUE);
    }
    
    public void push(int x) {
        xStack.push(x);
        minStack.push(Math.min(minStack.peek(), x));
    }
    
    public void pop() {
        xStack.pop();
        minStack.pop();
    }
    
    public int top() {
        return xStack.peek();
    }
    
    public int min() {
        return minStack.peek();
    }
}

效果

[困难]剑指 Offer 59 - I. 滑动窗口的最大值

题目

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7] 
解释: 

  滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

剑指 Offer 59 - I. 滑动窗口的最大值 - 力扣(LeetCode)

同下面的题 

239. 滑动窗口最大值 - 力扣(LeetCode)

方法:单调队列

        头疼欲裂,第一次看到困难题,直接暴力肯定能做,但是大概率也是超时,想了半天想不出,只能硬着头皮看题解、教学视频。

        想到了要用队列,但是接下来就没思路了。

        很喜欢评论区里的一段话,他用一个很贴切的例子来说明出了这道题的解法,可以品味一下。

虫子的世界

发布于 广东

(编辑过)

2021.11.08

        单调队列真是一种让人感到五味杂陈的数据结构,它的维护过程更是如此.....就拿此题来说,队头最大,往队尾方向单调......有机会站在队头的老大永远心狠手辣,当它从队尾杀进去的时候,如果它发现这里面没一个够自己打的,它会毫无人性地屠城,把原先队里的人头全部丢出去,转身建立起自己的政权,野心勃勃地准备开创一个新的王朝.....这时候,它的人格竟发生了一百八十度大反转,它变成了一位胸怀宽广的慈父!它热情地请那些新来的“小个子”们入住自己的王国......然而,这些小个子似乎天性都是一样的——嫉妒心强,倘若见到比自己还小的居然更早入住王国,它们会心狠手辣地找一个夜晚把它们通通干掉,好让自己享受更大的“蛋糕”;当然,遇到比自己强大的,它们也没辙,乖乖夹起尾巴做人。像这样的暗杀事件每天都在上演,虽然王国里日益笼罩上白色恐怖,但是好在没有后来者强大到足以干翻国王,江山还算能稳住。直到有一天,闯进来了一位真正厉害的角色,就像当年打江山的国王一样,手段狠辣,野心膨胀,于是又是大屠城......历史总是轮回的。

当然了,如果你直接初读这段话也是不好理解的,建议在看几遍题解之后,再读这段话就懂了。

如果题解不好看懂,我推荐看这个视频

单调队列正式登场!| LeetCode:239. 滑动窗口最大值_哔哩哔哩_bilibili

搞不懂,以后遇到滑动窗口或者单调队列这样的再补一下这块吧。。。 

[中等]剑指 Offer 59 - II. 队列的最大值

题目

请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_valuepush_back 和 pop_front 的均摊时间复杂度都是O(1)。

若队列为空,pop_front 和 max_value 需要返回 -1

示例 1:

输入: 
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]

示例 2:

输入: 
["MaxQueue","pop_front","max_value"]
[[],[],[]]
输出: [null,-1,-1]

限制:

  • 1 <= push_back,pop_front,max_value的总操作数 <= 10000
  • 1 <= value <= 10^5

剑指 Offer 59 - II. 队列的最大值 - 力扣(LeetCode)

方法1:暴力for

思路

        队列我们用数组去模拟,两个指针,一个in,一个out,初始的时候都是指向-1,执行入队列的时候就in++,执行出队列的时候,就是out++,所以队列的有效范围就是arr[out] , arr[in] ,前开后闭。

        求最大值的操作就是遍历一遍这个队列,返回最大值即可。

代码



class MaxQueue {
    int arr[] = new int[10000];
    int in = -1;
    int out = -1;


    public MaxQueue() {

    }

    public int max_value() {
        if (!isNull()){
            int max = Integer.MIN_VALUE;
            for (int i = this.out+1; i <= this.in; i++) {
                if (arr[i] > max){
                    max = arr[i];
                }
            }
            return max;

        }else return -1;

    }


    public void push_back(int value) {
        in ++;
        arr[in] = value;


    }

    /**
     * 为空
     */
    public  boolean isNull(){
        if (this.out >= this.in){
            return true;
        }else return false;
    }

    public int pop_front() {
        if (!isNull()){
            out ++;
            return arr[out];
        }else return -1;


    }
}

方法2:辅助双端队列

思路

思路和图解取自

作者:腐烂的橘子
链接:https://leetcode.cn/problems/dui-lie-de-zui-da-zhi-lcof/solutions/136701/ru-he-jie-jue-o1-fu-za-du-de-api-she-ji-ti-by-z1m/

我们知道对于一个普通队列,push_back 和 pop_front 的时间复杂度都是 O(1),因此我们直接使用队列的相关操作就可以实现这两个函数。

对于 max_value 函数,我们通常会这样思考,即每次入队操作时都更新最大值:

 但是当出队时,这个方法会造成信息丢失,即当最大值出队后,我们无法知道队列里的下一个最大值。

为了解决上述问题,我们只需记住当前最大值出队后,队列里的下一个最大值即可。

具体方法是使用一个双端队列 deque,用于记录最大值,在每次入队时,如果 deque 队尾元素小于即将入队的元素 value,则将小于 value 的元素全部出队后,再将 value 入队;否则直接入队。

当3进入时,3比辅助队列中的0 和 2 大,所以3进入了后辅助队列中的2 0 就没用了,将2 0 移出辅助队列,因为是双端队列,所以2 0 可以从队尾走出去。

 出队列就简单了,出之前判断一下连队列的头和辅助队列的头是不是同一个,是同一个就一起出,不是的话就只出队列的头,不出辅助队列的头。

 

代码

class MaxQueue {
    //用链表来模拟队列
    LinkedList<Integer> list;
    //辅助队列,用链表来模拟双端队列
    LinkedList<Integer> helpList;
    public MaxQueue() {
        list = new LinkedList<>();
        helpList = new LinkedList<>();
    }

    public int max_value() {
        if(helpList.isEmpty())return -1;
        return helpList.peekFirst();
    }

    //入队列
    public void push_back(int value) {
        list.add(value);
        //如果新来的value 比 辅助队列前面的值大,那么前面的值都没有用了,将前面的比value小的值都从末尾排出
        while(!helpList.isEmpty() && helpList.peekLast() < value){
            helpList.pollLast();
        }
        //再将新来的大一大一点的这个value 入到辅助队列中
        helpList.offer(value);
    }

    //出队列
    public int pop_front() {
        if(list.isEmpty()) return -1;

        //如果队列的头 和 辅助队列的头 一样,那就两个队列都一起出
        if(list.peekFirst().equals(helpList.peekFirst())){
            helpList.pollFirst();
            return list.pollFirst();
        }
        //否则只出队列的
        return list.pollFirst();
    }
}

效果

(效果不好的话,多提交几次)

心得

1. 如果一道题实在想不出来好的方法,那能用for就用for吧,说不定暴力的解法也能过。

2. 多熟悉API,java的这个LinkedList太好用了,既可用于队列,又能模拟双端队列,实用性非常强,因为它可以查看、删除对头队尾的元素,所以灵活性很高,可以多用用这个。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/859973.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

固态硬盘对游戏性能的影响及优势解析

固态硬盘的作用在于提高电脑的读取速度&#xff0c;这对于游戏性能的提升有着重要的影响。在一台电脑中&#xff0c;CPU和显卡是核心硬件&#xff0c;而游戏的流畅度则主要取决于显卡的性能&#xff0c;显卡的性能直接影响游戏的帧数高低。如果我们的电脑配置与朋友的电脑相似&…

异常支出的真实成本意想不到!管理采购异常支出有实招

采购中的异常支出是指合同外支出&#xff0c;或在预先制定的采购政策之外从非首选供应商处购买的支出。不同组织中异常支出的差异会很大&#xff0c;异常支出的比例取决于管理下的支出、采购政策实施的成功程度和采购成熟度。 异常支出会给企业带来多少损失&#xff1f; 曾有…

springboot+mybatis实现简单的增、删、查、改

这篇文章主要针对java初学者&#xff0c;详细介绍怎么创建一个基本的springboot项目来对数据库进行crud操作。 目录 第一步&#xff1a;准备数据库 第二步&#xff1a;创建springboot项目 方法1&#xff1a;通过spring官网的spring initilizer创建springboot项目 方法2&am…

qt creater运行按钮灰色,问题记录

第一次安装还没运行就出了三个错误&#xff1a; 1.F:\wei\Qt\Tools\CMake_64\share\cmake-3.24\Modules\CMakeTestCXXCompiler.cmake:62: error: The C compiler "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/BIN/amd64/cl.exe" is not able to compil…

列队 Queue 接口概述

在Java中&#xff0c;Queue&#xff08;队列&#xff09;是一种基本的数据结构&#xff0c;用于按照先进先出&#xff08;FIFO&#xff09;的顺序存储元素。Java提供了多种实现Queue接口的类&#xff0c;以下是几种常见的实现方式&#xff1a; LinkedList&#xff1a;LinkedLis…

linux环形缓冲区kfifo实践4:异步通知fasync

基础知识 异步通知在内核中使用struct fasync_struct数据结构来描述。 <include/linux/fs.h> struct fasync_struct {spinlock_t fa_lock;int magic;int fa_fd;struct fasync_struct *fa_next; /* singly linked list */struct file *fa_file;struct rcu_head fa…

CTF竞赛密码学之 LFSR

概述: 线性反馈移位寄存器&#xff08;LFSR&#xff09;归属于移位寄存器&#xff08;FSR&#xff09;,除此之外还有非线性移位寄存器&#xff08;NFSR&#xff09;。移位寄存器是流密码产生密钥流的一个主要组成部分。 G F ( 2 ) GF(2) GF(2)上一个n级反馈移位寄存器由n个二元…

matlab使用教程(12)—随机数种子和随机数流

1.生成可重复的随机数 1.1指定种子 本示例显示如何通过首先指定种子来重复生成随机数数组。每次使用相同种子初始化生成器时&#xff0c;始终都可以获得相同的结果。首先&#xff0c;初始化随机数生成器&#xff0c;以使本示例中的结果具备可重复性。 rng( default ); 现在…

django实现登录和登录的鉴权

1、创建数据库的管理员表 在models.py 中定义admin表&#xff0c;为了简单&#xff0c;表里只有用户名和密码还有默认加的id 三个字段 from django.db import models# Create your models here.class Admin(models.Model):username models.CharField(verbose_name"用户…

新利好带动 POSE 持续上扬,月内几近翻倍

PoseiSwap 是 Nautilus Chain 上的首个 DEX&#xff0c;得益于 Nautilus Chain 的模块化 Layer3 构架&#xff0c;PoseiSwap 正在基于 zk-Rollup 方案构建全新的应用层&#xff0c;并基于此构建隐私、合规等全新的特性&#xff0c;为未来其布局 RWA 领域推动 Web2、Web3 世界的…

布谷鸟配音:一站式配音软件

这是一款智能语音合成软件&#xff0c;可以快速将文字转换成语音&#xff0c;拥有多种真人模拟发音&#xff0c;可以选择不同男声、女声、童声&#xff0c;以及四川话、粤语等中文方言和外语配音&#xff0c;并且可对语速、语调、节奏、数字读法、多音字、背景音等进行全方位设…

【gridsample】地平线如何支持gridsample算子

文章目录 1. grid_sample算子功能解析1.1 理论介绍1.2 代码分析1.2.1 x,y取值范围[-1,1]1.2.2 x,y取值范围超出[-1,1] 2. 使用grid_sample算子构建一个网络3. 走PTQ进行模型转换与编译 实操以J5 OE1.1.60对应的docker为例 1. grid_sample算子功能解析 该段主要参考&#xff1a;…

最大子数组和——力扣53

文章目录 题目描述解法一 动态规划题目描述 解法一 动态规划 int maxSubArray(vector<int>& nums){int pre=0, res=nums

spring boot策略模式实用: 告警模块为例

spring boot策略模式实用: 告警模块 0 涉及知识点 策略模式, 模板方法, 代理, 多态, 反射 1 需求概括 场景: 每隔一段时间, 会获取设备运行数据, 如通过温湿度计获取到当前环境温湿度;需求: 对获取回来的进行分析, 超过配置的阈值需要产生对应的告警 2 方案设计 告警的类…

详解双端队列单调队列

1. 双端队列 双端队列&#xff08;Double-ended Queue&#xff09;&#xff0c;简称Deque&#xff0c;是一种具有特殊功能的线性数据结构。它支持从两端进行元素的插入和删除操作&#xff0c;因此可以在队列和栈之间灵活地切换操作。双端队列在编程中经常用于需要在队列和栈之间…

MySQL多表连接查询2

目录 1 所有有门派的人员信息 2 列出所有用户&#xff0c;并显示其机构信息 3 列出不入派的人员 4 所有没人入的门派 5 列出所有人员和门派的对照关系 6 列出所有没入派的人员和没人入的门派 7 求各个门派对应的掌门人名称: ​8 求所有当上掌门人的平均年龄: 9 求所…

6.4 (通俗易懂)可视化详解多通道 多通道输入输出卷积代码实现

以前对多通道和多通道输入输出的卷积操作不理解&#xff0c;今天自己在草稿纸上画图推理了一遍&#xff0c;终于弄懂了。希望能帮助到大家。 多通道可视化 一通道的2x2矩阵 torch.Size([2,2]) 相当于 torch.Size([1,2,2])&#xff0c;是一通道的2x2矩阵 二通道的 2x2矩阵 …

go-zero 是如何实现令牌桶限流的?

原文链接&#xff1a; 上一篇文章介绍了 如何实现计数器限流&#xff1f;主要有两种实现方式&#xff0c;分别是固定窗口和滑动窗口&#xff0c;并且分析了 go-zero 采用固定窗口方式实现的源码。 但是采用固定窗口实现的限流器会有两个问题&#xff1a; 会出现请求量超出限…

断续模式(DCM)与连续模式(CCM)

断续模式&#xff08;DCM&#xff09;与连续模式&#xff08;CCM)是开关电源最常用的两种工作模式。当初级开关管导通前&#xff0c;初级绕组还存在能量&#xff0c;不完全传递到次级&#xff0c;这种情况就叫连续模式。若初级绕组能量完全传递到次级&#xff0c;则为断续模式。…

Linux与安卓安全对抗

导读大家都知道安卓是基于Linux内核&#xff0c;而且大家也知道Linux的安全性是公认的&#xff0c;那为什么和Linux有着类似嫡系关系的安卓却一直被人诟病不安全呢&#xff1f;要想说清楚这个问题&#xff0c;我们需要了解一下安卓和Linux到底是什么关系&#xff0c;而且这两个…