E-最大社交距离(100p)

刷题笔记合集🔗

最大社交距离

问题描述

在疫情期间,为了保证社交距离,公司组织了一场特殊的交流会议。会议室有一排共 个座位,编号从 。员工们需要按照以下规则进入并就座:

  1. 每位员工进入时,必须选择能够最大化社交距离的座位(即与其他已就座员工距离最远的位置)。
  2. 如果存在多个满足条件的座位,员工应选择编号最小的那个。
  3. 员工可以在任何时候离开会议室。
  4. 特别注意,坐在 0 号位置的员工不会离开。

你的任务是确定最后一位进入会议室的员工将会坐在哪个位置。

输入格式

第一行包含一个整数 ,表示座位总数。

第二行是一个整数数组 ,表示员工的进出顺序。数组中的元素含义如下:

  • 1 表示一名员工进入会议室
  • 负数 表示坐在 号位置的员工离开(保证该位置确实有人)

输出格式

输出一个整数,表示最后进入的员工所坐的位置编号。如果所有座位都已被占用,则输出 -1。

样例输入1

10
[1, 1, 1, 1, -4, 1]

样例输出1

5

样例输入2

5
[1, 1, 1, 1, 1, 1]

样例输出2

-1

样例解释

样例 解释说明
样例1 1. 第一个人进入,坐在 0 号位置
2. 第二个人进入,坐在 9 号位置(最远距离)
3. 第三个人进入,坐在 4 号位置(中间)
4. 第四个人进入,坐在 2 号位置
5. 4 号位置的人离开
6. 最后一个人进入,坐在 5 号位置
样例2 前 5 个人分别坐在 0, 4, 2, 1, 3 号位置
第 6 个人进入时所有座位已满,无法就座

数据范围

  • 数组长度不超过 500

题解

双指针+模拟

算法思路

  1. 数据结构

    • 使用一个数组 vis 来记录每个座位的占用状态。
    • 使用一个变量 ans 来记录最后一个进入的人的座位。
  2. 处理新人进入

    • 如果是第一个人,直接坐在第一个位置(索引1)。
    • 否则,遍历所有座位,找到能够最大化社交距离的位置。
    • 使用双指针技巧:lmaxv 记录左边最近的已占用座位,rmaxv 记录右边最近的已占用座位。
  3. 寻找最佳座位

    • 对于每个未占用的座位,计算它到左右两边最近已占用座位的距离。
    • 取这两个距离的较小值作为该座位的社交距离。
    • 更新全局最大社交距离和对应的座位索引。
  4. 处理人员离开

    • 直接将对应座位的状态标记为未占用。
  5. 特殊情况处理

    • 如果所有座位都已被占用,新人无法就座,返回-1。
    • 确保不会移除0号位置的人。

时间复杂度分析

  • 对于每个事件(进入或离开),我们最坏情况下需要遍历所有座位一次。
  • 总时间复杂度:O(n * m),其中 n 是座位数,m 是事件数。

空间复杂度分析

  • 我们使用了一个长度为 n+1 的数组来记录座位状态。
  • 空间复杂度:O(n)

代码实现的关键点

  1. 使用 vis 数组快速判断座位是否被占用。
  2. 使用双指针 lmaxvrmaxv 来高效计算社交距离。
  3. 特别处理第一个人和只有一个人的情况,以简化逻辑。
  4. 注意座位编号从0开始,但我们的实现从1开始,最后返回结果时需要减1。

参考代码

  • Python
def getResult(n, a):
    # 初始化座位占用状态数组,索引0不使用,所以长度为n+1
    vis = [0] * (n + 1)
    # 记录最后一个进入的人的座位
    ans = 0
    
    for val in a:
        if val == 1:  # 有新人进入
            lmaxv = 0  # 左边最近的已占用座位
            maxv = 0   # 当前最大社交距离
            idx = 1    # 当前选择的座位索引
            
            # 如果是第一个人,直接坐在第一个位置
            if vis.count(1) == 0:
                vis[idx] = 1
                ans = idx
                continue
            
            rmaxv = 0  # 右边最近的已占用座位
            
            # 遍历所有座位,寻找最大社交距离的位置
            for i in range(1, n + 1):
                if vis[i] == 0:  # 当前座位未被占用
                    ldist = i - lmaxv  # 到左边最近已占用座位的距离
                    rdist = rmaxv - i  # 到右边最近已占用座位的距离
                    if rmaxv == n + 1:  # 如果右边没有已占用的座位
                        rdist = n * 10  # 将右距离设置为一个很大的值
                    dist = min(ldist, rdist)  # 取左右距离的较小值作为社交距离
                    if dist > maxv:  # 更新最大社交距离和对应的座位
                        maxv, idx = dist, i
                else:  # 当前座位已被占用
                    lmaxv = i  # 更新左边最近的已占用座位
                    rmaxv = lmaxv + 1
                    while rmaxv <= n and vis[rmaxv] == 0:
                        rmaxv += 1  # 寻找右边最近的已占用座位
            
            # 选定座位,更新状态
            vis[idx] = 1
            ans = idx
        else:  # 有人离开
            vis[-val + 1] = 0  # 将对应座位标记为未占用
    
    return ans - 1  # 返回最后一个进入的人的座位号(减1是因为题目座位从0开始编号)

# 输入处理
n = int(input())  # 读取座位总数
a = eval(input())  # 读取事件序列

# 输出结果
print(getResult(n, a))
  • C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MIN(a, b) ((a) < (b) ? (a) : (b))

int getResult(int n, int* a, int aSize) {
    // 初始化座位占用状态数组,索引0不使用,所以长度为n+1
    int* vis = (int*)calloc(n + 1, sizeof(int));
    int ans = 0;  // 记录最后一个进入的人的座位
    
    for (int i = 0; i < aSize; i++) {
        int val = a[i];
        if (val == 1) {  // 有新人进入
            int lmaxv = 0;  // 左边最近的已占用座位
            int maxv = 0;   // 当前最大社交距离
            int idx = 1;    // 当前选择的座位索引
            
            // 检查是否是第一个人
            int firstPerson = 1;
            for (int j = 1; j <= n; j++) {
                if (vis[j] == 1) {
                    firstPerson = 0;
                    break;
                }
            }
            
            // 如果是第一个人,直接坐在第一个位置
            if (firstPerson) {
                vis[idx] = 1;
                ans = idx;
                continue;
            }
            
            int rmaxv = 0;  // 右边最近的已占用座位
            
            // 遍历所有座位,寻找最大社交距离的位置
            for (int i = 1; i <= n; i++) {
                if (vis[i] == 0) {  // 当前座位未被占用
                    int ldist = i - lmaxv;  // 到左边最近已占用座位的距离
                    int rdist = rmaxv - i;  // 到右边最近已占用座位的距离
                    if (rmaxv == n + 1) rdist = n * 10;  // 如果右边没有已占用的座位,将右距离设置为一个很大的值
                    int dist = MIN(ldist, rdist);  // 取左右距离的较小值作为社交距离
                    if (dist > maxv) {  // 更新最大社交距离和对应的座位
                        maxv = dist;
                        idx = i;
                    }
                } else {  // 当前座位已被占用
                    lmaxv = i;  // 更新左边最近的已占用座位
                    rmaxv = lmaxv + 1;
                    while (rmaxv <= n && vis[rmaxv] == 0) rmaxv++;  // 寻找右边最近的已占用座位
                }
            }
            
            // 选定座位,更新状态
            vis[idx] = 1;
            ans = idx;
        } else {  // 有人离开
            vis[-val + 1] = 0;  // 将对应座位标记为未占用
        }
    }
    
    free(vis);  // 释放动态分配的内存
    return ans - 1;  // 返回最后一个进入的人的座位号(减1是因为题目座位从0开始编号)
}

int main() {
    int n;
    scanf("%d", &n);  // 读

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

算法刷题笔记 文章被收录于专栏

本专栏收集并整理了一些刷题笔记

全部评论

相关推荐

米哈游校招进主页喵:大佬 考虑我司不 考虑的话可以看我主页帖子
点赞 评论 收藏
分享
刚刷到字节跳动官方发的消息,确实被这波阵仗吓了一跳。在大家还在纠结今年行情是不是又“寒冬”的时候,字节直接甩出了史上规模最大的转正实习计划——ByteIntern。咱们直接看几个最硬的数,别被花里胡哨的宣传词绕晕了。首先是“量大”。全球招7000多人是什么概念?这几乎是把很多中型互联网公司的总人数都给招进来了。最关键的是,这次的资源分配非常精准:研发岗给了4800多个Offer,占比直接超过六成。说白了,字节今年还是要死磕技术,尤其是产品和AI领域,这对于咱们写代码的同学来说,绝对是今年最厚的一块肥肉。其次是大家最关心的“转正率”。官方直接白纸黑字写了:整体转正率超过50%。这意味着只要你进去了,不划水、正常干,每两个人里就有一个能直接拿校招Offer。对于2027届(2026年9月到2027年8月毕业)的同学来说,这不仅是实习,这简直就是通往大厂的快捷通道。不过,我也得泼盆冷水。坑位多,不代表门槛低。字节的实习面试出了名的爱考算法和工程实操,尤其是今年重点倾斜AI方向,如果你简历里有和AI相关的项目,优势还是有的。而且,转正率50%也意味着剩下那50%的人是陪跑的,进去之后的考核压力肯定不小。一句话总结:&nbsp;27届的兄弟们,别犹豫了。今年字节这是铁了心要抢提前批的人才,现在投递就是占坑。与其等到明年秋招去千军万马挤独木桥,不如现在进去先占个工位,把转正名额攥在手里。
喵_coding:别逗了 50%转正率 仔细想想 就是转正与不转正
字节7000实习来了,你...
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务