大厂秋招真题【单调栈】Bilibili2021秋招-大鱼吃小鱼

news2024/9/22 13:34:00

文章目录

  • 题目描述与示例
    • 题目描述
    • 输入描述
    • 输出描述
    • 示例一
      • 输入
      • 输出
      • 说明
    • 示例二
      • 输入
      • 输出
      • 说明
  • 解题思路
  • 代码
    • Python
    • Java
    • C++
    • 时空复杂度
  • 华为OD算法/大厂面试高频题算法练习冲刺训练

题目描述与示例

题目描述

小明最近喜欢上了俄罗斯套娃、大鱼吃小鱼这些大的包住小的类型的游戏。

于是小明爸爸给小明做了一个特别版的大鱼吃小鱼游戏,他希望通过这个游戏能够近一步提高小明的智商。

游戏规则如下:

现在有N条鱼,每条鱼的体积为Ai,从左到右排成一排。A数组是一个排列。

小明每轮可以执行一次大鱼吃小鱼的操作。一次大鱼吃小鱼的操作:对于每条鱼,它在每一次操作时会吃掉右边比自己小的第一条鱼。

值得注意的是,在一次操作中,每条鱼吃比自己小的鱼的时候是同时发生的。

举一个例子,假设现在有三条鱼,体积为分别[5,4,3]5443,一次操作后就剩下[5]一条鱼。

爸爸问小明,你知道要多少次操作,鱼的数量就不会变了嘛?

输入描述

第一行输入长度N

第二行输入A数组,数字之间用空格隔开

1<=N<=10^5`,`1<=Ai<=N

输出描述

一个正整数, 表示要多少次操作,鱼的数量就不会变了。

示例一

输入

3
1 2 3

输出

0

说明

无需操作A数组。

示例二

输入

6
4 3 2 3 2 1

输出

2

说明

[4,3,2,3,2,1]-->[4,3]-->[4]

解题思路

用比较严谨的数学语言来翻译该题,描述如下。

对于数组nums中所有尽可能长的严格递减子区间[a, b],每一次我们都用区间的最大值a来替换掉该区间,得到一个新的数组nums_new。对于nums_new做相同的操作,直到nums_new不再发生变化,问一共需要几次操作。

该问题显然可以用模拟的暴力方法来解决,时间复杂度为O(N^2),部分用例将无法通过。在想不到更优解法的时候,可以尝试暴力法。本篇题解主要讨论单调栈解法。

考虑如下用例5 4 4 2 2 1 3 2,会经历以下过程。

在这里插入图片描述

观察可以发现,由于位于右边的较小的鱼迟早会被位于左边的较大的鱼吃掉,假设位于左边的大鱼所经历的轮数为time_big,若干位于右边的较小的鱼所经历的轮数构成的列表为time_small_list(这些小鱼之间不会再互相吞吃,即time_small_list从左到右呈现非递减的取值)。

对于time_small_list中特定的time_smalltime_big的表达式为

time_big = max(time_big+1, time_small)

其中+1表示在之前得到time_big的基础上,吃掉小鱼还需要多花费1轮,time_small为小鱼之前经历的轮数,两者的较大值才是time_big的结果。

得到该结论之后,就很容易想到本问题可以使用逆序遍历的****单调栈来解决了:

  1. 栈中储存一个二元元组(num, time),分别为鱼的体积和该鱼所经历的轮数
  2. 逆序遍历原数组nums中的元素num,若
    1. 栈为空栈,或num小于等于栈顶元素储存鱼的体积,则该条鱼无法吃到任何一条鱼。
      • (num, 0)压入栈中
    2. num大于栈顶元素储存鱼的体积,则该大鱼可以吃掉若干栈顶的小鱼。
      • 初始化time_big = 0
      • 使用一个while循环,不断弹出栈顶小鱼,更新time_big = max(time_big+1, time_small)
      • while循环结束后,将(num, time_big)压入栈中

上述过程的核心代码为

for num in nums[::-1]:
    if len(stack) == 0 or stack[-1][0] >= num:
        stack.append((num, 0))
    else:
        time_big = 0
        while stack and stack[-1][0] < num:
            num_small, time_small = stack.pop()
            time_big = max(time_big+1, time_small)
        stack.append((num, time_big))

下面的图解展示了用单调栈解决该问题的过程。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

我们发现我们的过程中在对于5 4 2 2 3的情况我们用4把后面3条鱼吃掉了,但实际上4在第2轮就会被5吃掉了。这实际上这并不影响答案的正确性,因为后面的小鱼2 2 3终究会被吃掉,不论是被4还是被5吃掉,都需要花费3轮,我们让4来做该操作,是让4代替5来吃鱼,后续的花费会在取最大值的过程中转换。

代码

Python

# 题目:【单调栈】Bilibili2021秋招-大鱼吃小鱼
# 作者:闭着眼睛学数理化
# 算法:单调栈
# 代码有看不懂的地方请直接在群上提问

# 输入数组大小,数组
n = input()
nums = list(map(int, input().split()))
# 初始化空的单调栈,栈中储存(num, time)这样一个二元组
stack = list()

# 逆序遍历nums中的每一个元素num
for num in nums[::-1]:
    # 空栈以及栈顶元素对应的鱼体积大于等于num的情况
    # 该分支语句其实可以不用单独列出,可以被else中的语句所包含
    # 但为了代码逻辑清晰,还是单独列出该分支
    if len(stack) == 0 or stack[-1][0] >= num:
        stack.append((num, 0))
    # 栈顶元素对应的鱼体积小于num的情况
    # 即num可以吃掉若干栈顶元素对应的鱼
    else:
        # 初始化该大鱼需要经历的轮数为0
        time_big = 0
        # 用一个while循环弹出若干栈顶的小鱼
        # 将其中所经历的轮数的最大值+1后赋值给time_big
        while stack and stack[-1][0] < num:
            # 弹出栈顶小鱼,其体积和经历的轮数分别为num_small, time_small
            num_small, time_small = stack.pop()
            time_big = max(time_big+1, time_small)
        # 该大鱼吃掉若干小鱼后,要将其体积和所经历的轮数重新压回栈顶
        stack.append((num, time_big))

# 退出循环后,栈中剩余的所有鱼所经历轮数的最大值,即为答案
print(max(time for num, time in stack))

Java

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = scanner.nextInt();
        }

        // Initialize an empty stack of pairs (num, time)
        Stack<Pair> stack = new Stack<>();

        for (int i = n - 1; i >= 0; i--) {
            int num = nums[i];

            if (stack.isEmpty() || stack.peek().num >= num) {
                stack.push(new Pair(num, 0));
            } else {
                int timeBig = 0;
                while (!stack.isEmpty() && stack.peek().num < num) {
                    Pair pair = stack.pop();
                    int numSmall = pair.num;
                    int timeSmall = pair.time;
                    timeBig = Math.max(timeBig + 1, timeSmall);
                }
                stack.push(new Pair(num, timeBig));
            }
        }

        int maxTime = 0;
        while (!stack.isEmpty()) {
            maxTime = Math.max(maxTime, stack.pop().time);
        }

        System.out.println(maxTime);
    }

    static class Pair {
        int num;
        int time;

        Pair(int num, int time) {
            this.num = num;
            this.time = time;
        }
    }
}

C++

#include <iostream>
#include <vector>
#include <stack>

using namespace std;

struct Pair {
    int num;
    int time;

    Pair(int num, int time) : num(num), time(time) {}
};

int main() {
    int n;
    cin >> n;

    vector<int> nums(n);
    for (int i = 0; i < n; ++i) {
        cin >> nums[i];
    }

    stack<Pair> stack;

    for (int i = n - 1; i >= 0; --i) {
        int num = nums[i];

        if (stack.empty() || stack.top().num >= num) {
            stack.push(Pair(num, 0));
        } else {
            int timeBig = 0;
            while (!stack.empty() && stack.top().num < num) {
                Pair pair = stack.top();
                stack.pop();
                int numSmall = pair.num;
                int timeSmall = pair.time;
                timeBig = max(timeBig + 1, timeSmall);
            }
            stack.push(Pair(num, timeBig));
        }
    }

    int maxTime = 0;
    while (!stack.empty()) {
        maxTime = max(maxTime, stack.top().time);
        stack.pop();
    }

    cout << maxTime << endl;

    return 0;
}

时空复杂度

时间复杂度:O(N)。每个元素至多只需出入栈一次。

空间复杂度:O(N)。单调栈所占空间。


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

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

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

相关文章

汇编-loop循环指令

LOOP指令是根据ECX计数器循环&#xff0c;将语句块重复执行特定次数。 ECX自动作为计数器&#xff0c; 每重复循环一次就递减1。 语法如下所示&#xff1a; 循环目的地址必须在距离当前位置计数器的-128到127字节范围内 LOOP指令的执行有两个步骤&#xff1a; 第一步&…

记一次线上bug排查-----SpringCloud Gateway组件 请求头accept-encoding导致响应结果乱码

基于公司的业务需求&#xff0c;在SpringCloud Gateway组件的基础上&#xff0c;写了一个转发服务&#xff0c;测试开发阶段运行正常&#xff0c;并实现初步使用。但三个月后&#xff0c;PostMan请求接口&#xff0c;返回异常&#xff0c;经排查&#xff0c;从日志中获取到转发…

js高效函数库Lodash.js

Lodash 是一个 JavaScript 的实用工具库&#xff0c;提供了许多实用且高效的函数&#xff0c;可以简化 JavaScript 编程中的常见任务。 Lodash具有高性能、模块化和易用性等特点&#xff0c;表现一致性以及可扩展&#xff0c;下面将介绍一些 Lodash 的重要特性和用法&#xff1…

解决 VS2022 关于 c++17 报错: C2131 表达式必须含有常量值

使用 VS2022 编译 ORB-SLAM3 加载Vocabulary 二进制ORBvoc.bin 时&#xff0c;在 DBOW2 里修改 TemplatedVocabulary.h 代码显示这样的错误&#xff1a; 编译器错误 C2131 表达式的计算结果不是常数 定位到我的代码中&#xff1a; char buf [size_node] ; 原因 &#xff1a; …

Ultipa Transporter V4.3.22 即将发布,解锁更多易用功能!

Ultipa Graph 作为一款领先的实时图数据库分析平台&#xff0c;即将发布最新版的数据导入/导出工具Ultipa Transporter V4.3.22 以实现对 Neo4j数据源的导入支持。自今年以来&#xff0c;Ultipa Transporter不断增加新功能&#xff0c;除原本支持本地CSV文件导入导出外&#xf…

修改bat文件默认编辑软件

Windows默认编辑bat文件的软件是自带的文本编辑器。无法高亮显示bat中的命令。 修改方式一&#xff1a; 打开注册表文件&#xff0c;变更键值 HKEY_CLASSES_ROOT\batfile\shell\edit\command 对应软件地址 修改方式二&#xff1a; 制作批处理文件&#xff0c;代码如下&#x…

github 开源whisper ros llm

GitHub - openai/whisper: Robust Speech Recognition via Large-Scale Weak Supervision openai whisper ROS LLM https://github.com/Auromix/ROS-LLM/tree/ros2-humble/llm_input

我理解的反射

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 我之前对反射的理解未必…

uni-app:前端实现心跳机制(全局)+局部页面控制心跳暂停和重新心跳

一、App.vue全局中写入心跳 在data中定义变量heartbeatTimer&#xff0c;便于暂停心跳使用在onLaunch中引用开始心跳的方法startHeartbeat()写入开始心跳方法写入暂停心跳方法写入请求后端刷心跳机制 定义变量 // 在全局设置的心跳机制中添加一个变量来保存定时器的标识 data(…

利用API连接抖音外卖与电商平台和营销系统,实现无代码开发的集成

利用API连接抖音外卖和电商平台 抖音来客&#xff0c;作为抖音生活服务商家经营平台&#xff0c;为商家提供一站式经营服务&#xff0c;其中包括入驻、上品、经营和履约等功能。商家可以通过API调用&#xff0c;实现电商平台和抖音外卖的连接&#xff0c;从而优化运营效率。例…

源启容器平台KubeGien 打造云原生转型的破浪之舰

云原生是应用上云的标准路径&#xff0c;也是未来发展大的趋势。如何将业务平滑过渡到云上&#xff1f;怎样应对上云期间的各项挑战呢&#xff1f;中电金信基于金融级数字底座“源启”打造了一款非常稳定可靠、多云异构、安全可控、开放灵活的容器平台产品——源启容器平台Kube…

第二证券:知名私募美股持仓曝光 科技与消费板块成“心头好”

近来&#xff0c;美国证券交易委员会&#xff08;SEC&#xff09;网站闪现&#xff0c;高毅资产、HHLR&#xff08;高瓴旗下独立二级商场基金管理人&#xff09;、景林资产和千合本钱旗下对冲基金TOP ACE&#xff0c;陆续宣告了到三季度末的美股持仓。 据私募排排网核算&#…

代码逻辑修复与其他爬虫ip库的应用

在一个项目中&#xff0c;由于需要设置 http_proxy 来爬虫IP访问网络&#xff0c;但在使用 requests 库下载文件时遇到了问题。具体表现为在执行 Python 脚本时&#xff0c;程序会阻塞并最终超时&#xff0c;无法正常完成文件下载。 解决方案 针对这个问题&#xff0c;我们可以…

本地部署 Qwen-14B-Chat

本地部署 Qwen-14B-Chat 1. Qwen-14B 概述2. Github 地址3. 创建虚拟环境4. 安装依赖项5. 快速使用6. 启动 web 演示7. 访问 Qwen 1. Qwen-14B 概述 通义千问-14B&#xff08;Qwen-14B&#xff09; 是阿里云研发的通义千问大模型系列的140亿参数规模的模型。Qwen-14B是基于Tra…

【Java SE】如何解读Java的继承和多态的特性?

前言 什么是继承和多态&#xff0c;为什么被称为Java三大特性&#xff0c;这两大特性为我们程序员带来了什么影响呢&#xff1f;是让复杂的代码简化了&#xff0c;还是为程序员写代码提供了多样性呢&#xff1f;那让我们一起来揭开这层神秘的面纱吧&#xff01; 1.继承 1.1为…

日期相关整理

3214. 节日 有一类节日的日期并不是固定的&#xff0c;而是以“a 月的第 b 个星期 c ”的形式定下来的&#xff0c;比如说母亲节就定为每年的五月的第二个星期日。 现在&#xff0c;给你 a,b,c 和 y1,y2&#xff0c;希望你输出从公元 y1 年到公元 y2 年间的每年的 a 月的第 b 个…

重要功能丨支持1688API 接口对接一键跨境铺货及采购,解决跨境卖家货源烦恼!

在跨境电商运营中&#xff0c;不少卖家都会优先选择1688平台产品作为跨境店铺货源。 必不可少的1688商品详情接口 阿里巴巴中国站获得1688商品详情 API 返回值说明 item_get-获得1688商品详情 1688.item_get 公共参数 请求地址: 申请调用KEY测试 名称类型必须描述keyStrin…

鼠标点击网页任何地方都显示光标闪烁输入状态

出现这种情况的原因 因为大概是用户无意中打开了浏览器无障碍模式中的使用文本光标浏览网页的功能。 对于Chrome浏览器而言就是这样的&#xff1a; 直接按F7关闭这个模式

十倍增量的海外客户开发新方式来了!外贸企业可直接照做

外贸和B2大C型&#xff08;汽车、房产、保险、教育等&#xff09;企业出海过程中&#xff0c;除了常见的数字营销&#xff08;投放&#xff09;、平台营销、活动营销&#xff08;线下展会&#xff09;和内容营销&#xff0c;还有一个批量化可快速复制起量的营销方式&#xff1a…

SIMULIA-Simpack 2022x新功能介绍

通用功能 增加库伦摩擦类型 力元95 Coulomb Friction增加了3种新的摩擦方向类型用于模拟平面、圆柱和球面摩擦。 针对平移和旋转摩擦改进了滑动到粘着过渡阶段的检测&#xff0c;增加一个参数定义两种不同的滑移-粘滞过渡模式&#xff0c;即“Unloaded stick stiffness”和“…