【备战秋招】每日一题:4月29日美团春招:题面+题目思路 + C++/python/js/Go/java带注释

2023大厂笔试模拟练习网站(含题解)
www.codefun2000.com
最近我们一直在将收集到的各种大厂笔试的解题思路还原成题目并制作数据,挂载到我们的OJ上,供大家学习交流,体会笔试难度。现已录入200+道互联网大厂模拟练习题,还在极速更新中。欢迎关注公众号“塔子哥学算法”获取最新消息。

提交链接: 

https://codefun2000.com/p/P1138

为了更好的阅读体检,可以查看OJ上的题解。进入提交链接,点击右边菜单栏的"查看塔子哥的题解"

在线评测链接:P1268

题目内容

塔子哥和他的朋友们共 n 人是一群热爱生活的年轻人,他们经常在一起吃饭,聊天,玩游戏。有一天,他们决定去一家新开的酒吧,品尝各种美酒。但是他们发现,酒吧的老板是一个很奇怪的人,他给他们出了一个挑战:如果他们能在一个小时内喝完所有的酒,就可以免单;如果有人中途放弃,就要付双倍的钱。塔子哥和他的朋友们觉得这是一个很有趣的游戏,于是接受了挑战。

为了增加难度和乐趣,他们决定用一个特殊的方式来喝酒。他们顺时针围成一圈,假设标号为 1 到 n 。从 1 号开始,每次从当前的人顺时针数 k 个,然后这个人喝一杯酒。第 i 个人的酒量为a_i意味着当他喝了a_i杯酒后将因无法忍受而离席。现在他们请你依次输出离席的人的编号,以此来判断谁是酒王。

输入描述

输入第一行为两个正整数 n,k 。

输入第二行为 n 个正整数,第 i 个数为 a_i

对于所有的数据: 1\le n\le 1000,1\le k\le 10^9,1\le a_i \le 10000,n\times \sum a_i\le 10^7

输出描述

输出一行输出用空格隔开的 n 个正整数,表示按时间从早到晚离席的人的编号。

样例

输入

5 4
1 1 7 9 8

输出

1 5 2 4 3

思路

约瑟夫环问题+贪心

本题是经典的约瑟夫环问题变种。

从当前位置 cur 开始喝酒,下一个位置为顺时针的 cur + k 这个位置。由于这是一个圆,故一定会在一些人之间循环喝酒,一部分人在这段时间总是不会喝酒,我们称当前的情况为当前的酒局。喝酒的这部分人中,直到存在一个人喝完酒后,剩余酒杯数为 0 ,这一部分人的喝酒结束,整个酒局将被修改。

我们需要考虑,当前的喝酒的人中,从当前位置 cur 开始,一直顺时针 k次找下一个人,而离席的第一个人,必然是酒杯数最少的。

由于存在先后关系,从 cur 开始顺时针 k 次找下一个喝酒的人,这些人中,剩余酒杯数最少,且是所有剩余酒杯数最少的人中第一个喝酒的人,是第一个离席的人。这个人前面的人会和他和一样多的酒,后面的人会比他少喝一杯酒。

这个人离席后,其顺时针后面的人就接上其位置,进行下一次的酒局。

时间复杂度:O(n^2)

视频实况 v1, 21:12-65:56

类似题目推荐

LeetCode

剑指 Offer 62. 圆圈中最后剩下的数字

CodeFun2000

P1118 2023.03.26-阿里春招-第二题-报数字

代码

CPP

#include <bits/stdc++.h>
using namespace std;
​
const int N = 1010;
pair<int, int> a[N];
int ans[N], g;
int vis[N];
int people[N];
int n, k;
​
int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i) scanf("%d", &a[i].first), a[i].second = i + 1;
​
    int cur = 0;
    while (n > 0) {
        for (int i = 0; i < n; ++i) vis[i] = 0;
        int cnt = 0;
        int minv = 0x3f3f3f3f;
​
        // 找到当前回合所有可能需要喝酒的人
        while (!vis[cur]) {
            people[cnt++] = cur;
            vis[cur] = 1;
            minv = min(minv, a[cur].first);
            cur = (cur + k) % n;
        }
​
        // 我们找到从 cur 开始的最小值
        // cur 之前的人要减去 minv
        // cur 之后的人要减去 minv - 1
        for (int i = 0; i < cnt; ++i)
            if (minv == a[people[i]].first) {
                for (int j = 0; j < i; ++j) a[people[j]].first -= minv;
                for (int j = i + 1; j < cnt; ++j) a[people[j]].first -= minv - 1;
​
                //  将其排列好,然后再往后走 k 个
                int pos = people[i];
                ans[++g] = a[pos].second;
                for (int j = pos + 1; j < n; ++j) a[j - 1] = a[j];
​
                if (n > 1) {
                    // 走 k - 1步是因为下一个人继承了当前离席的人的位置,故从当前离席的顺时针走 k 个
                    cur = (pos + k - 1) % (n - 1);
                }
​
                break;
            }
​
        n -= 1;
    }
​
    for (int i = 1; i <= g; ++i) printf("%d%c", ans[i], " \n"[i == g]);
​
    return 0;
}

python

N = 1010
​
n, k = map(int, input().split())
​
a = [[0, 0] for i in range(N)]
vis = [0] * N
​
line = input().split()
for i in range(len(line)):
    a[i] = ([int(line[i]), i + 1])
​
cur = 0
ans = []
while n > 0:
    for i in range(n):
        vis[i] = 0
​
    people = []
    minv = 0x3f3f3f3f
    # 找到当前回合所有可能需要喝酒的人
    while vis[cur] == 0:
        people.append(cur)
        vis[cur] = 1
        minv = min(minv, a[cur][0])
        cur = (cur + k) % n
    
    # 我们找到从 cur 开始的最小值
    # cur 之前的人要减去 minv
    # cur 之后的人要减去 minv - 1
    for i in range(len(people)):
        if minv == a[people[i]][0]:
            for j in range(i):
                a[people[j]][0] -= minv
            for j in range(i + 1, len(people)):
                a[people[j]][0] -= minv - 1
​
            # 将其排列好,然后再往后走 k 个
            pos = people[i]
            ans.append(a[pos][1])
            a.pop(pos)
​
            if n > 1:
                # 走 k - 1步是因为下一个人继承了当前离席的人的位置,故从当前离席的顺时针走 k 个
                cur = (pos + k - 1) % (n - 1)
​
            break
    n -= 1
    
for i in ans:
    print(i, end=' ')
print()

Java

import java.util.Arrays;
import java.util.Scanner;
​
public class Main {
    static final int N = 1010;
    static int[] ans = new int[N], people = new int[N];
    static int[] vis = new int[N];
    static int[][] a = new int[N][2];
​
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        for (int i = 0; i < n; ++i) {
            a[i][0] = sc.nextInt();
            a[i][1] = i + 1;
        }
​
        int g = 0;
        int cur = 0;
        while (n > 0) {
            for (int i = 0; i < n; ++i) vis[i] = 0;
            int cnt = 0;
            int minv = 0x3f3f3f3f;
            // 找到当前回合所有可能需要喝酒的人
            while (vis[cur] == 0) {
                people[cnt++] = cur;
                vis[cur] = 1;
                minv = Math.min(minv, a[cur][0]);
                cur = (cur + k) % n;
            }
​
            // 我们找到从 cur 开始的最小值
            // cur 之前的人要减去 minv
            // cur 之后的人要减去 minv - 1  
            for (int i = 0; i < cnt; ++i) {
                if (minv == a[people[i]][0]) {
                    for (int j = 0; j < i; ++j) {
                        a[people[j]][0] -= minv;
                    }
                    for (int j = i + 1; j < cnt; ++j) {
                        if (j != i) {
                            a[people[j]][0] -= minv - 1;
                        }
                    }
                    
                    // 将其排列好,然后再往后走 k 个
                    int pos = people[i];
                    ans[++g] = a[pos][1];
                    for (int j = pos + 1; j < n; ++j) {
                        a[j - 1] = a[j];
                    }
​
                    // 走 k - 1步是因为下一个人继承了当前离席的人的位置,故从当前离席的顺时针走 k 个
                    if (n > 1) {
                        cur = (pos + k - 1) % (n - 1);
                    }
​
                    break;
                }
            }
            n -= 1;
        }
​
        for (int i = 1; i <= g; ++i) {
            System.out.print(ans[i] + " ");
        }
        System.out.println();
    }
}

Go

package main
​
import "fmt"
​
type Pair struct {
    first, second int
}
​
const N = 1010
​
var a [N]Pair
var ans [N]int
var vis [N]bool
var people [N]int
var g int
var n, k int
​
func main() {
    fmt.Scan(&n, &k)
    for i := 0; i < n; i++ {
        fmt.Scan(&a[i].first)
        a[i].second = i + 1
    }
​
    cur := 0
    for n > 0 {
        for i := 0; i < n; i++ {
            vis[i] = false
        }
        cnt := 0
        minv := 0x3f3f3f3f
​
        // 找到当前回合所有可能需要喝酒的人
        for !vis[cur] {
            people[cnt] = cur
            vis[cur] = true
            minv = min(minv, a[cur].first)
            cur = (cur + k) % n
            cnt++
        }
​
        // 我们找到从 cur 开始的最小值
        // cur 之前的人要减去 minv
        // cur 之后的人要减去 minv - 1
        for i := 0; i < cnt; i++ {
            if minv == a[people[i]].first {
                for j := 0; j < i; j++ {
                    a[people[j]].first -= minv
                }
                for j := i + 1; j < cnt; j++ {
                    a[people[j]].first -= minv - 1
                }
​
                //  将其排列好,然后再往后走 k 个
                pos := people[i]
                ans[g+1] = a[pos].second
                g++
                for j := pos + 1; j < n; j++ {
                    a[j-1] = a[j]
                }
​
                if n > 1 {
                    // 走 k - 1步是因为下一个人继承了当前离席的人的位置,故从当前离席的顺时针走 k 个
                    cur = (pos + k - 1) % (n - 1)
                }
​
                break
            }
        }
​
        n--
    }
​
    for i := 1; i <= g; i++ {
        if i == g {
            fmt.Printf("%d\n", ans[i])
        } else {
            fmt.Printf("%d ", ans[i])
        }
    }
}
​
func min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

Js

process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
    input += data;
    return;
});
process.stdin.on('end', () => {
    const lines = input.trim().split('\n');
    [n, k] = lines[0].split(' ').map(Number);
    const a = lines[1].split(' ').map((x, i) => [Number(x), i + 1]);
    const people = new Array(n);
    const ans = new Array(n);
​
    let cur = 0;
    let g = 0;
    while (n > 0) {
        const vis = new Array(n).fill(false);
        let cnt = 0;
        let minv = Infinity;
​
        // 找到当前回合所有可能需要喝酒的人
        while (!vis[cur]) {
            people[cnt++] = cur;
            vis[cur] = true;
            minv = Math.min(minv, a[cur][0]);
            cur = (cur + k) % n;
        }
​
        // 我们找到从 cur 开始的最小值
        // cur 之前的人要减去 minv
        // cur 之后的人要减去 minv - 1
        for (let i = 0; i < cnt; i++) {
            const p = people[i];
            if (minv === a[p][0]) {
                for (let j = 0; j < i; j++) {
                    a[people[j]][0] -= minv;
                }
                for (let j = i + 1; j < cnt; j++) {
                    a[people[j]][0] -= minv - 1;
                }
​
                // 将其排列好,然后再往后走 k 个
                const pos = p;
                ans[g++] = a[pos][1];
                for (let j = pos + 1; j < n; j++) {
                    a[j - 1] = a[j];
                }
​
                if (n > 1) {
                    // 走 k - 1 步是因为下一个人继承了当前离席的人的位置,故从当前离席的顺时针走 k 个
                    cur = (pos + k - 1) % (n - 1);
                }
​
                break;
            }
        }
​
        n--;
    }
​
    console.log(ans.join(' '));
});

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

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

相关文章

继承—JavaSE

文章目录 1.基础知识1.1继承的概念1.2语法 2子类对从父类继承下来的成员的访问2.1对成员变量的访问2.2对成员方法的访问 3.super关键字3.1访问父类的成员变量&#xff08;super.变量&#xff09;3.2访问父类的成员方法&#xff08;super.方法&#xff09;3.3调用父类的构造方法…

估计一个点云的表面法线

包含相关头文件 #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/features/normal_3d.h> #include <pcl/visualization/pcl_visualizer.h> 定义了两个类型别名 PointT 和 PointNT&#xff0c;用于表示输入点云和输出点云中各…

第14届蓝桥杯国赛真题剖析-2023年5月28日Scratch编程初中级组

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第149讲。 第14届蓝桥杯Scratch国赛真题&#xff0c;这是2023年5月28日上午举办的全国总决赛&#xff0c;比赛仍然采取…

进程管道:popen函数实例

基础知识 可能最简单的在两个程序之间传递数据的方法就是使用popen和pclose函数了。它们的原型如下所示&#xff1a; #include <stdio.h>FILE *popen(const char *command, const char *type);int pclose(FILE *stream); 1&#xff0e;popen函数 popen函数允许一个程…

FTL没有映射,跟发工资没有钱有什么区别

大家好&#xff0c;我是五月。 前言 FTL&#xff08;Flash Translation Layer&#xff09;&#xff0c;即闪存转换层&#xff0c;是各种存储设备的核心算法&#xff0c;作用是将Host传下来的逻辑地址转换成物理地址&#xff0c;也就是映射。 地址映射是FTL最原始最基本的功能…

苹果手机之间如何互传照片?批量传输操作指南

很多时候&#xff0c;我们用手机拍摄了好看的照片或者收藏了一些有趣的图片&#xff0c;想要分享给朋友&#xff0c;却不知道苹果手机之间如何互传照片&#xff1f;在分享大量照片的时候不清楚如何批量操作&#xff1f;别担心&#xff0c;下面小编就来分享一下苹果手机照片传输…

海思3559万能平台搭建:SPI输出h264码流

前言 面对各种各样的客户需求&#xff0c;spi接口也是一种传码流的形式&#xff0c;spi同步422可以保证抗干扰能力强的同时传输距离也很长&#xff0c;本文会介绍海思平台spi作为主机的发送功能以及发送码流的处理方式 1. 管脚复用&#xff1a; 首先需要配置的肯定是管脚复用&…

Linux进程间通信【共享内存】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 &#x1f307;前言&#x1f3d9;️正文1、什么是共享内存&#xff1f;2、共享内存的相关知识2.1、共享内存的数据结构…

load_dataset加载huggingface数据集失败

1. 一般的加载方式 from datasets import load_dataset dataset_dict load_dataset(cmrc2018)这种加载方式可能会显示因为连接问题导致失败&#xff0c;此时可以在hugging face里面找到对应的页面下载下来 然后改一下代码&#xff1a; from datasets import load_dataset d…

springmvc整合thymeleaf

概述 Thymeleaf提供了一组Spring集成&#xff0c;使您可以将其用作Spring MVC应用程序中JSP的全功能替代品。 这些集成将使您能够&#xff1a; Controller像使用JSP一样&#xff0c;将Spring MVC 对象中的映射方法转发到Thymeleaf管理的模板。在模板中使用Spring表达式语言&…

罗马不是一天建成的,那为什么建了那么多罗马?

这一个罗马&#xff0c;那一个罗马&#xff0c;东一个罗马&#xff0c;西一个罗马&#xff0c;世界历史的大半部分都在跟罗马打交道。更要命的是四大文明古国还没有古代罗马。 存在感这么强&#xff0c;还不是四大文明古国&#xff0c;名字还难记&#xff0c;公元前居然就有共…

【C++】在线编译器推荐,让你随时随地编写代码

▒ 目录 ▒ &#x1f6eb; 问题描述环境 1️⃣ 支持调试网站Repl.itOnlineGDB 2️⃣ 不支持调试网站Wandboxjson.cnjdoodletutorialspointcppshellideonecoliruonline-ide 3️⃣ 性能分析网站Quick C BenchmarkCompare C Builds 4️⃣ 其它C Insights&#xff08;学习模板、C11…

Hightopo 使用心得(3)- 吸附与锚点

吸附与锚点是 HT for Web 中两个比较重要的概念。这两个概念在执行交互和动画时会经常被用到。 吸附&#xff0c;顾名思义&#xff0c;是一个节点吸附到另一个节点上。就像船底的贝类一样&#xff0c;通过吸附到船身&#xff0c;在船移动的时候自己也会跟着移动&#xff1b;而…

pandas---缺失值的处理

1. 处理缺失值 判断数据中是否包含NaN&#xff1a; pd.isnull(df)&#xff1b;pd.notnull(df) 存在缺失值nan: 删除存在缺失值的:dropna(axisrows) 不会修改原数据&#xff0c;需要接受返回值&#xff1b; 替换缺失值:fillna(value, inplaceTrue) value:替换成的值&#…

JavaScript数学对象-数字进制转换

关注“大前端私房菜”微信公众号&#xff0c;输入暗号【面试宝典】即可免费领取107页前端面试题。 什么是进制 进制就是达到指定位置时候进一位 常见的进制 十进制: 0 1 2 3 4 5 6 7 8 9 10 11 12 ... 99 100 101 二进制: 0 1 10 11 100 101 110 111 1000 八进制: 0 1 2 3 4 …

走进人工智能|GANs AI时代下的前卫艺术

前言&#xff1a; GANs的作用是以生成模型的形式学习数据分布&#xff0c;从而产生逼真的样本数据&#xff0c;可以应用于图像合成、风格转换、视频生成等领域。 文章目录 序言背景适用领域技术支持应用领域程序员如何学总结 序言 GANs&#xff08;生成对抗网络&#xff09;是…

ASEMI代理台湾光宝LTV-3120光耦合器中文资料

编辑-Z LTV-3120是一种高性能光耦&#xff0c;由于其可靠性、效率和多功能性&#xff0c;在各种应用中都很受欢迎。本文将全面了解LTV-3120其功能、应用以及它如何改进您的电子设计。 什么是光电耦合器&#xff1f; 光耦&#xff0c;也称为光隔离器&#xff0c;是一种利用光在…

Mediapipe实时3D目标检测和跟踪(自动驾驶实现)

&#x1f680; 导语 3D目标检测是根据物体的形状、位置和方向来识别和定位物体的任务。在2D目标检测中&#xff0c;被检测到的物体仅表示为矩形边界框。3D目标检测任务通过预测物体周围的包围框&#xff0c;可以获取物体的三维位置信息。 3D目标检测在各行各业都有广泛的应用。…

Flink 系列二 Flink 状态化流处理概述

本篇作为Flink系列的第二篇&#xff0c;第一篇是环境准备&#xff0c;需要的同学可以看&#xff1a;https://blog.csdn.net/lly576403061/article/details/130358449?spm1001.2014.3001.5501。希望可以通过系统的学习巩固该方面的知识&#xff0c;丰富自己的技能树。废话不多说…

jmeter模拟多用户并发

目录 前言&#xff1a; 一、100个真实的用户 二、100个用户同时登录 前言&#xff1a; JMeter可以轻松地模拟多用户并发&#xff0c;从而测试Web应用程序的性能和稳定性。 一、100个真实的用户 1、一个账号模拟100虚拟用户同时登录和100账号同时登录 区别 &#xff08;…