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

文章目录

  • 题目描述与示例
    • 题目描述
    • 输入描述
    • 输出描述
    • 示例一
      • 输入
      • 输出
      • 说明
    • 示例二
      • 输入
      • 输出
      • 说明
  • 解题思路
  • 代码
    • 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.mfbz.cn/a/166892.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

磁钢的居里温度和工作温度

你知道吗&#xff0c;磁体在超过一定温度时会永久的失磁&#xff0c;不同的磁体能够承受的最大工作温度是不同的&#xff0c;那么与温度相关的指标有哪些&#xff1f;如何根据工作温度来选择合适的磁钢&#xff1f;今天我们就来解答一下这些问题。 居里温度 说到温度与磁性关…

Python武器库开发-flask篇之error404(二十七)

flask篇之error404(二十七) 首先&#xff0c;我们先进入模板的界面创建一个404的html页面 cd templates vim 404.html404.html的内容如下&#xff1a; <h1>error!!!</h1>在 Flask 应用程序中&#xff0c;当用户访问一个不存在的页面的时候&#xff0c;会出现 4…

LeetCode【32】最长的有效括号

题目&#xff1a; 思路&#xff1a; 括号字符串依次入栈&#xff0c;删除匹配的成对括号。最后栈中留下的都是无法匹配的断点。这些断点的差值减一就是断点间有效括号串的长度&#xff0c;取这些长度的最大值即可。 例如括号字符串 “)()((())(”&#xff0c;最后留在栈中的…

2023初中生古诗文大会复赛12月2日举行,来做做全真在线模拟题吧

2023年11月19日日&#xff0c;上海市古诗文大会主办方通过官微发布了2023上海中学生古诗文大会&#xff08;初中组&#xff09;复选将于12月2日举行的通知&#xff0c;就初中生古诗文大会复赛&#xff08;复选&#xff09;的相关安排做了说明&#xff0c;六分成长已经为您把通知…

ASUS华硕ROG幻13笔记本电脑GV301QE原厂Windows10系统

链接&#xff1a;https://pan.baidu.com/s/1aPW0ctRXRNAhE75mzVPdTg?pwdds78 提取码&#xff1a;ds78 华硕玩家国度幻13笔记本电脑锐龙版Ryzen 7 5800HS,显卡3050 3050Ti,3060,3060Ti,3070,3070Ti 原厂W10系统自带所有驱动、出厂主题壁纸、系统属性专属LOGO标志、Office办…

横向扩展统一存储备份解决方案的特点与优势

Infortrend 使企业能够实现高效和可靠的数据备份&#xff0c;确保业务不间断的运行&#xff0c;保护有价值的业务信息。用户可以依靠我们的存储解决方案实现恢复时间目标&#xff08;RTO&#xff09;和恢复点目标&#xff08;RPO&#xff09;&#xff0c;用于广泛的备份应用场景…

6.10二叉树的所有路径(LC257-E,不太会)

算法&#xff1a; 前序遍历&#xff1a; 因为要让父节点指向孩子节点&#xff0c;才能输出路径。 递归与回溯相辅相成&#xff0c;只要有递归&#xff0c;就一定有回溯。 举个例子理解一下&#xff1a; 中&#xff1a;先push入1 左&#xff1a;再Push入2 右&#xff1a;再…

MES管理系统与ERP系统的实施顺序与决策

在现今的数字化时代&#xff0c;制造企业纷纷寻求通过先进的系统来提升运营效率。其中&#xff0c;ERP管理系统与MES管理系统被誉为是数字化转型的两大利器。然而&#xff0c;在推进这两个系统时&#xff0c;企业常常面临一个关键问题&#xff1a;究竟应该先实施哪一个系统&…

BetterDisplay Pro v2.0.11(显示器颜色校准软件)

BetterDisplay Pro是一款为Mac电脑设计的屏幕亮度调节软件&#xff0c;旨在提高显示器的色彩和亮度表现。它可以根据用户的需求和显示器的特性&#xff0c;自动调整显示器的亮度、色温、对比度等参数&#xff0c;以获得更加真实、舒适的视觉效果。 这款软件拥有智能调节功能&a…

基于C#实现最长公共子序列

一、作用 最长公共子序列的问题常用于解决字符串的相似度&#xff0c;是一个非常实用的算法&#xff0c;作为码农&#xff0c;此算法是我们的必备基本功。 二、概念 举个例子&#xff0c;cnblogs 这个字符串中子序列有多少个呢&#xff1f;很显然有 27 个&#xff0c;比如其…

微创机器人:CRM撬动售后服务数字化升级

一方面&#xff0c;我国医疗器械行业起步较晚&#xff0c;更注重产品的销售和业务的拓展&#xff0c;企业售后服务整体比较滞后。 另一方面&#xff0c;医疗器械售后服务环节数字化程度不足&#xff0c;一些企业仍通过传统的线下手段管理售后服务&#xff0c;进行数字化尝试的…

element UI表格中设置文字提示(tooltip)或弹出框(popover)时候注意的地方

在表格中自定义内容的时候需要使用标签&#xff0c;否则无法正常显示 文档中有两种写法&#xff1a;1、使用 slot“reference” 的具名插槽&#xff0c;2、使用自定义指令v-popover指向 Popover 的索引ref。 使用tooltip 时用具名 slot 分发content&#xff0c;替代tooltip中…

SIMULIA-Simpack 2022x新功能介绍

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

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

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

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

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

基于C++实现循环赛日程表(分治算法)

一、问题描叙 设有n2^k个运动员&#xff0c;要进行网球循环赛。现在要设计一个满足以下要求的比赛日程表 每个选手必须与其他n-1个选手各赛一场每个选手一天只能赛一次循环赛一共进行n-1天 二、问题分析 按此要求可将比赛日程表设计成n行n-1列的表&#xff0c;在表中第 i 行…

【网络安全】国家专利局专利办理系统存在信息泄漏风险

今天在办理专利的时候&#xff0c;发现该系统存在严重的信息泄漏问题。 废话少说&#xff0c;贴图为证。 每一个都可以点开&#xff0c;查看身份证、港澳通信证扫描件&#xff0c;很清晰。 本人没找到可以反馈的渠道&#xff0c;微博被限流。 发此贴只为警醒相关主管部门和运…

Mac git查看分支以及切换分支

查看本地分支 git branch 查看远程仓库分支 git branch -r 查看本地与远程仓库分支 git branch -a 切换分支 git checkout origin/dev/js

JSP页面文本展示正常 但定义在java代码中的内容 输出在页面上会变成问号 问题解决

这里 我直接写在界面上的内容就是正常的 但是 java代码中定义的内容 就会变成问号 造成这个情况的原因可能是多样的 首先要确保JDK没问题 然后是 页面顶部配置 <% page language"java" contentType"text/html; charsetUTF-8" pageEncoding"UTF-…
最新文章