疫情期间需要保证一定的社交距离,公司组织开交流会议。会议室有一排共 N
个座位,编号分别为 [0, N-1]
。要求员工一个接着一个进入会议室,并且可以在任何时候离开会议室。需要满足以下规则:
进入规则:
离开规则:
-4
表示坐在位置 4
的员工离开。0
的员工不会离开。seatNum
,满足 1 ≤ seatNum ≤ 500
。seatOrLeave
数组:
1
,表示进场。-4
表示坐在位置 4
的员工离开)。-1
。10
[1, 1, 1, 1, -4, 1]
5
0
号座位。9
号座位。4
号座位。2
号座位。-4
表示 4
号座位的员工离开。5
号座位。N
个座位,员工按顺序进入或离开。seat
记录当前已被占用的座位编号。seatOrLeave
,对于每个操作:
1
):
seat
为空,直接坐在 0
号座位。seat
不为空,计算每个相邻已占座位之间的距离,以及第一个座位到 0
号座位的距离和最后一个座位到 N-1
的距离。seat
数组中移除该座位编号。seat
数组,确保其有序,以便快速找到最佳座位。-1
。0
号座位的距离和最后一个座位到 N-1
的距离。seat
数组中移除该座位编号。seat
记录当前已被占用的座位编号。seat
数组,并确保其有序。10
[1, 1, 1, 1, -4, 1]
第一个员工进入:
seat
为空,直接坐在 0
号座位。seat = [0]
。第二个员工进入:
0
号座位的距离:0
。9
号座位的距离:9 - 0 = 9
。9
号座位。seat = [0, 9]
。第三个员工进入:
0
和 9
之间的距离:9 - 0 = 9
。4
号座位。seat = [0, 4, 9]
。第四个员工进入:
0
和 4
之间的距离:4 - 0 = 4
。4
和 9
之间的距离:9 - 4 = 5
。2
号座位。seat = [0, 2, 4, 9]
。第五个操作,-4
表示 4
号座位的员工离开:
4
号座位。seat = [0, 2, 9]
。第六个员工进入:
0
和 2
之间的距离:2 - 0 = 2
。2
和 9
之间的距离:9 - 2 = 7
。5
号座位。seat = [0, 2, 5, 9]
。最后一个进入的员工坐在 5
号座位,输出 5
。
本题通过动态维护已占用座位的有序数组,计算每次进入操作时的最佳座位,并处理离开操作更新座位状态。核心在于最大化社交距离并选择索引最小的座位,最终输出最后一个进入的员工的座位编号。
const readline = require('readline');
// 创建 readline 接口实例
const rl = readline.createInterface({
input: process.stdin, // 标准输入流
output: process.stdout // 标准输出流
});
// 监听 'line' 事件,每次输入一行触发
rl.on('line', (seatNum) => {
// 再次监听 'line' 事件,获取座位占用和离开的操作序列
rl.on('line', (str) => {
// 解析输入的字符串,去掉首尾的括号,分割后转换为数字数组
const seatOrLeave = str.slice(1, -1).split(',').map(Number);
let seat = []; // 存储已占用的座位
let ans = -1; // 下一个人的最佳座位号
// 遍历操作序列
for (let sol of seatOrLeave) {
if (sol !== 1) {
// 如果操作不是1,表示有员工离开,移除对应座位号
seat = seat.filter(s => s !== -sol);
} else {
// 如果操作是1,表示有员工进入,需要找到最佳座位
if (seat.length === 0) {
// 如果会议室为空,新员工坐在0号座位
ans = 0;
} else {
// 如果会议室不为空,找到最大的空闲区间
let max_distance = seat[0]; // 初始化最大距离为第一个座位号
ans = 0; // 初始化最佳座位号为0
for (let i = 0; i < seat.length; i++) {
// 计算当前座位与下一个座位之间的距离
let distance = i === seat.length - 1 ? seatNum - 1 - seat[i] : Math.floor((seat[i + 1] - seat[i]) / 2);
if (distance > max_distance) {
// 如果当前距离大于最大距离,则更新最大距离和最佳座位号
max_distance = distance;
ans = i === seat.length - 1 ? seatNum - 1 : seat[i] + distance;
}
}
}
// 如果会议室已满,设置最佳座位号为-1
if (seat.length === seatNum) {
ans = -1;
} else {
// 将新员工的座位号加入到座位列表,并按升序排序
seat.push(ans);
seat.sort((a, b) => a - b);
}
}
}
// 输出最后一个操作后的最佳座位号
console.log(ans);
// 关闭 readline 接口实例
rl.close();
});
});
readline
模块创建一个接口实例,用于读取标准输入。line
事件,当用户输入一行内容时触发回调函数:
line
事件读取座位总数 seatNum
。line
事件读取操作序列的字符串,并解析为整数数组 seatOrLeave
。seat
:用于存储当前已占用的座位编号,初始化为空数组。ans
:用于记录下一个员工的最佳座位号,初始化为 -1
。sol
:
sol
不是 1
(即负数),表示有员工离开,从 seat
数组中移除对应座位号。sol
是 1
,表示有员工进入,需要找到最佳座位:
seat
为空,新员工直接坐在 0
号座位。seat
不为空,计算最大空闲区间:
seat
数组,计算相邻座位之间的距离。0
号座位的距离和最后一个座位到 seatNum-1
的距离。seat.length === seatNum
),设置 ans
为 -1
。seat
数组,并排序。ans
。readline
接口实例。0
号座位的距离和最后一个座位到 seatNum-1
的距离。seat
数组中移除该座位编号。seat
数组记录当前已占用的座位编号。seat
数组,并确保其有序。10
[1, 1, 1, 1, -4, 1]
第一个员工进入:
seat
为空,直接坐在 0
号座位。seat = [0]
。第二个员工进入:
0
号座位的距离:0
。9
号座位的距离:9 - 0 = 9
。9
号座位。seat = [0, 9]
。第三个员工进入:
0
和 9
之间的距离:9 - 0 = 9
。4
号座位。seat = [0, 4, 9]
。第四个员工进入:
0
和 4
之间的距离:4 - 0 = 4
。4
和 9
之间的距离:9 - 4 = 5
。2
号座位。seat = [0, 2, 4, 9]
。第五个操作,-4
表示 4
号座位的员工离开:
4
号座位。seat = [0, 2, 9]
。第六个员工进入:
0
和 2
之间的距离:2 - 0 = 2
。2
和 9
之间的距离:9 - 2 = 7
。5
号座位。seat = [0, 2, 5, 9]
。最后一个进入的员工坐在 5
号座位,输出 5
。
这段代码通过动态维护已占用座位的有序数组,计算每次进入操作时的最佳座位,并处理离开操作更新座位状态。核心在于最大化社交距离并选择索引最小的座位,最终输出最后一个进入的员工的座位编号。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// 创建Scanner对象,用于读取输入
Scanner scanner = new Scanner(System.in);
// 读取座位总数
int seatNum = scanner.nextInt(); // 读取座位总数
scanner.nextLine(); // 读取换行符,避免影响后续输入
// 读取座位占用和离开的操作序列
String str = scanner.nextLine(); // 读取操作序列的字符串
// 去除字符串首尾的括号并分割成数组
String[] parts = str.substring(1, str.length() - 1).split(",");
ArrayList<Integer> seatOrLeave = new ArrayList<>(); // 存储操作序列的列表
for (String part : parts) {
seatOrLeave.add(Integer.parseInt(part.trim())); // 将字符串转换为整数并添加到列表
}
// 初始化变量
ArrayList<Integer> seat = new ArrayList<>(); // 存储已占用的座位编号
int ans = -1; // 下一个人的最佳座位号,初始化为-1
// 遍历操作序列
for (int sol : seatOrLeave) {
if (sol != 1) {
// 如果sol为负数,表示有员工离开,移除对应座位号
seat.remove(Integer.valueOf(-sol)); // 从seat列表中移除该座位号
} else {
// 如果sol为1,表示有员工进入,需要找到最佳座位
if (seat.isEmpty()) {
// 如果会议室为空,新员工坐在0号座位
ans = 0;
} else {
// 如果会议室不为空,找到最大的空闲区间
int maxDistance = seat.get(0); // 初始化最大距离为第一个座位号
ans = 0; // 初始化最佳座位号为0
for (int i = 0; i < seat.size(); i++) {
int distance;
if (i == seat.size() - 1) {
// 检查最后一个座位到座位总数之间的距离
distance = seatNum - 1 - seat.get(i);
} else {
// 检查相邻座位之间的距离
distance = (seat.get(i + 1) - seat.get(i)) / 2;
}
if (distance > maxDistance) {
// 更新最大距离和最佳座位号
maxDistance = distance;
ans = (i == seat.size() - 1) ? seatNum - 1 : seat.get(i) + distance;
}
}
}
// 如果会议室已满,设置最佳座位号为-1
if (seat.size() == seatNum) {
ans = -1;
} else {
// 将新员工的座位号加入到座位列表,并排序
seat.add(ans);
Collections.sort(seat); // 排序以便后续查找最大距离
}
}
}
// 打印最后一个操作后的最佳座位号
System.out.println(ans);
scanner.close(); // 关闭Scanner对象
}
}
Scanner
读取输入:
seatNum
。[]
。,
分割,并转换为整数列表 seatOrLeave
。seat
:用于存储当前已占用的座位编号。ans
:用于记录下一个员工的最佳座位号,初始化为 -1
。sol
:
sol
不是 1
(即负数),表示有员工离开,从 seat
列表中移除对应座位号。sol
是 1
,表示有员工进入,需要找到最佳座位:
seat
为空,新员工直接坐在 0
号座位。seat
不为空,计算最大空闲区间:
seat
列表,计算相邻座位之间的距离。0
号座位的距离和最后一个座位到 seatNum-1
的距离。seat.size() == seatNum
),设置 ans
为 -1
。seat
列表,并排序。ans
。Scanner
对象。0
号座位的距离和最后一个座位到 seatNum-1
的距离。seat
列表中移除该座位编号。seat
列表记录当前已占用的座位编号。seat
列表,并确保其有序。10
[1, 1, 1, 1, -4, 1]
第一个员工进入:
seat
为空,直接坐在 0
号座位。seat = [0]
。第二个员工进入:
0
号座位的距离:0
。9
号座位的距离:9 - 0 = 9
。9
号座位。seat = [0, 9]
。第三个员工进入:
0
和 9
之间的距离:9 - 0 = 9
。4
号座位。seat = [0, 4, 9]
。第四个员工进入:
0
和 4
之间的距离:4 - 0 = 4
。4
和 9
之间的距离:9 - 4 = 5
。2
号座位。seat = [0, 2, 4, 9]
。第五个操作,-4
表示 4
号座位的员工离开:
4
号座位。seat = [0, 2, 9]
。第六个员工进入:
0
和 2
之间的距离:2 - 0 = 2
。2
和 9
之间的距离:9 - 2 = 7
。5
号座位。seat = [0, 2, 5, 9]
。最后一个进入的员工坐在 5
号座位,输出 5
。
这段代码通过动态维护已占用座位的有序列表,计算每次进入操作时的最佳座位,并处理离开操作更新座位状态。核心在于最大化社交距离并选择索引最小的座位,最终输出最后一个进入的员工的座位编号。
import math
# 读取输入
seatNum = int(input()) # 读取座位总数
str = input() # 读取座位占用和离开的操作序列
seatOrLeave = list(map(int, str[1:-1].split(","))) # 将字符串转换为整数数组
# 初始化
seat = [] # 存储已占用的座位
ans = -1 # 下一个人的最佳座位号
for sol in seatOrLeave: # 遍历座位占用和离开的操作序列
if sol != 1:
# 如果 sol 为负数,表示有员工离开,移除对应座位号
seat.remove(-sol)
else:
# 如果 sol 为 1,表示有员工进入,需要找到最佳座位
if not seat:
# 如果会议室为空,新员工坐在 0 号座位
ans = 0
else:
# 如果会议室不为空,找到最大的空闲区间
max_distance = seat[0] # 初始化最大距离为第一个座位号
ans = 0 # 初始化最佳座位号为 0
for i in range(len(seat)):
if i == len(seat) - 1:
# 检查最后一个座位到座位总数之间的距离
distance = seatNum - 1 - seat[i]
else:
# 检查相邻座位之间的距离
distance = (seat[i + 1] - seat[i]) // 2
if distance > max_distance:
# 更新最大距离和最佳座位号
max_distance = distance
if i == len(seat) - 1:
ans = seatNum - 1
else:
ans = seat[i] + distance
# 如果会议室已满,输出 -1
if len(seat) == seatNum:
ans = -1
else:
# 将新员工的座位号加入到座位列表,并排序
seat.append(ans)
seat.sort()
print(ans)
input()
读取座位总数 seatNum
,并将其转换为整数。input()
读取操作序列的字符串。[]
,并按逗号 ,
分割,将结果转换为整数列表 seatOrLeave
。seat
:用于存储当前已占用的座位编号,初始化为空列表。ans
:用于记录下一个员工的最佳座位号,初始化为 -1
。sol
:
sol
不是 1
(即负数),表示有员工离开,从 seat
列表中移除对应座位号。sol
是 1
,表示有员工进入,需要找到最佳座位:
seat
为空,新员工直接坐在 0
号座位。seat
不为空,计算最大空闲区间:
seat
列表,计算相邻座位之间的距离。0
号座位的距离和最后一个座位到 seatNum-1
的距离。len(seat) == seatNum
),设置 ans
为 -1
。seat
列表,并排序。ans
。0
号座位的距离和最后一个座位到 seatNum-1
的距离。seat
列表中移除该座位编号。seat
列表记录当前已占用的座位编号。seat
列表,并确保其有序。10
[1, 1, 1, 1, -4, 1]
第一个员工进入:
seat
为空,直接坐在 0
号座位。seat = [0]
。第二个员工进入:
0
号座位的距离:0
。9
号座位的距离:9 - 0 = 9
。9
号座位。seat = [0, 9]
。第三个员工进入:
0
和 9
之间的距离:9 - 0 = 9
。4
号座位。seat = [0, 4, 9]
。第四个员工进入:
0
和 4
之间的距离:4 - 0 = 4
。4
和 9
之间的距离:9 - 4 = 5
。2
号座位。seat = [0, 2, 4, 9]
。第五个操作,-4
表示 4
号座位的员工离开:
4
号座位。seat = [0, 2, 9]
。第六个员工进入:
0
和 2
之间的距离:2 - 0 = 2
。2
和 9
之间的距离:9 - 2 = 7
。5
号座位。seat = [0, 2, 5, 9]
。最后一个进入的员工坐在 5
号座位,输出 5
。
这段代码通过动态维护已占用座位的有序列表,计算每次进入操作时的最佳座位,并处理离开操作更新座位状态。核心在于最大化社交距离并选择索引最小的座位,最终输出最后一个进入的员工的座位编号。
#include
#include
#include
#include
using namespace std;
// 寻找最佳座位的函数
int findBestSeat(const vector<int>& occupiedSeats, int seatNum) {
// 如果还没有人坐,第一个人坐在0号座位
if (occupiedSeats.empty()) return 0;
// 如果只有一个人坐,那么下一个人坐在最后一个座位
if (occupiedSeats.size() == 1) return seatNum - 1;
int maxDistance = 0, bestSeat = -1;
// 检查是否可以在第一个座位坐下(即第一个座位之前的空位)
if (occupiedSeats.front() > 0) {
maxDistance = occupiedSeats.front();
bestSeat = 0;
}
// 检查是否可以在最后一个座位坐下(即最后一个座位之后的空位)
if (seatNum - 1 - occupiedSeats.back() > maxDistance) {
maxDistance = seatNum - 1 - occupiedSeats.back();
bestSeat = seatNum - 1;
}
// 检查中间的最大间隔,寻找最佳座位
for (int i = 1; i < occupiedSeats.size(); ++i) {
int distance = (occupiedSeats[i] - occupiedSeats[i - 1]) / 2;
if (distance > maxDistance) {
maxDistance = distance;
bestSeat = occupiedSeats[i - 1] + distance;
}
}
// 返回最佳座位编号
return bestSeat;
}
int main() {
int seatNum; // 会议室座位总数
cin >> seatNum;
string input; // 存放员工进出顺序的字符串
cin >> ws; // 忽略前面的空白字符
getline(cin, input); // 读取整行作为字符串
// 处理输入字符串,将其转换为int数组
stringstream ss(input.substr(1, input.size() - 2)); // 去掉字符串的首尾括号
vector<int> seatOrLeave;
int num;
while (ss >> num) {
seatOrLeave.push_back(num);
if (ss.peek() == ',') ss.ignore();
}
vector<int> occupiedSeats; // 存储已占用座位的数组
int lastSeat = -1; // 存储最后一个坐下的员工的座位号
// 遍历员工的进出操作
for (int action : seatOrLeave) {
if (action == 1) { // 进场操作
int bestSeat = findBestSeat(occupiedSeats, seatNum);
if (bestSeat != -1) { // 如果找到了最佳座位
occupiedSeats.push_back(bestSeat); // 更新已占用座位列表
sort(occupiedSeats.begin(), occupiedSeats.end()); // 保持座位列表排序
lastSeat = bestSeat; // 更新最后一个坐下的座位号
}
} else if (action < 0) { // 出场操作
action = -action; // 转为正数,表示座位号
auto it = find(occupiedSeats.begin(), occupiedSeats.end(), action);
if (it != occupiedSeats.end()) occupiedSeats.erase(it); // 从已占用座位中移除
}
}
cout << lastSeat << endl; // 输出最后一个进来员工的座位号
return 0;
}
cin
读取座位总数 seatNum
。getline
读取操作序列的字符串,并去掉首尾的方括号 []
。stringstream
将字符串按逗号 ,
分割,并转换为整数数组 seatOrLeave
。findBestSeat
函数:
0
号座位。0
号座位的距离。seatNum-1
的距离。seatOrLeave
:
findBestSeat
找到最佳座位。occupiedSeats
数组,并排序。lastSeat
。occupiedSeats
数组中移除对应座位。lastSeat
。#include
#include
#define MAX_SIZE 500 // 定义最大座位数
// 比较函数,用于qsort排序
int cmp(const void *a, const void *b) {
return *((int *) a) - *((int *) b);
}
int main() {
int seatNum; // 座位总数
scanf("%d", &seatNum); // 读取座位总数
getchar(); // 读取换行符
int seatOrLeave[MAX_SIZE] = {0}; // 存储进出座位的数组
int seatOrLeave_size = 0; // 进出座位数组的当前大小
// 读取进出座位的序列,支持两种格式:[数字,] 或 数字,
while (scanf("[%d", &seatOrLeave[seatOrLeave_size]) || scanf("%d", &seatOrLeave[seatOrLeave_size])) {
seatOrLeave_size++; // 数组大小增加
if (getchar() != ',') break; // 如果不是逗号,则停止读取
}
int seat[MAX_SIZE]; // 存储已有人的座位号
int seat_size = 0; // 已有人的座位号数组的当前大小
int lastSeatIdx = -1; // 最后一个坐下的座位号
// 遍历所有进出记录
for (int i = 0; i < seatOrLeave_size; i++) {
int info = seatOrLeave[i]; // 当前记录
// 如果是负数,表示有人离开
if (info < 0) {
int leaveIdx = -info; // 离开的座位号
for (int j = 0; j < seat_size; j++) {
if (seat[j] == leaveIdx) {
// 移除离开的座位号
for (int k = j; k < seat_size - 1; k++) {
seat[k] = seat[k + 1];
}
seat_size--; // 座位数组大小减小
break;
}
}
} else {
// 如果是第一个人,则坐在第一个位置
if (seat_size == 0) {
lastSeatIdx = 0;
seat[seat_size++] = lastSeatIdx;
} else {
int maxDist = -1; // 最大距离
int bestSeat = -1; // 最佳座位
// 检查第一个座位是否空闲
if (seat[0] > 0) {
maxDist = seat[0];
bestSeat = 0;
}
// 遍历已坐座位,寻找最佳座位
for (int j = 1; j < seat_size; j++) {
int dist = (seat[j] - seat[j - 1]) / 2; // 计算距离
if (dist > maxDist) {
maxDist = dist;
bestSeat = seat[j - 1] + dist;
}
}
// 检查最后一个座位是否空闲
if (seatNum - 1 - seat[seat_size - 1] > maxDist) {
bestSeat = seatNum - 1;
}
// 如果找到了最佳座位,将其加入数组
if (bestSeat >= 0 && seat_size < seatNum) {
seat[seat_size++] = bestSeat;
qsort(seat, seat_size, sizeof(int), cmp); // 排序座位数组
}
lastSeatIdx = bestSeat; // 更新最后一个坐下的座位号
}
}
}
printf("%d\n", lastSeatIdx); // 打印最后一个坐下的座位号
return 0;
}
scanf
读取座位总数 seatNum
。getchar
读取换行符。scanf
读取操作序列,支持 [数字,]
或 数字,
的格式。seatOrLeave
:
seat
数组中移除对应座位。0
号座位。seat
数组,并排序。lastSeatIdx
。lastSeatIdx
。C++ 和 C 代码的核心逻辑相同,都是通过动态维护已占用座位的数组,计算每次进入操作时的最佳座位,并处理离开操作更新座位状态。最终输出最后一个进入的员工的座位编号。
华为OD(Outsourcing Developer,外包开发工程师)是华为针对软件开发工程师岗位的一种招聘形式,主要包括笔试、技术面试以及综合面试等环节。尤其在笔试部分,算法题的机试至关重要。
机试是进入技术面的第一关:
华为OD机试(常被称为机考)主要考察算法和编程能力。只有通过机试,才能进入后续的技术面试环节。
技术面试需要手撕代码:
技术一面和二面通常会涉及现场编写代码或算法题。面试官会注重考察候选人的思路清晰度、代码规范性以及解决问题的能力。因此提前刷题、多练习是通过面试的重要保障。
入职后的可信考试:
入职华为后,还需要通过“可信考试”。可信考试分为三个等级:
2024年8月14日之后,华为OD机试的题库转为 E卷,由往年题库(D卷、A卷、B卷、C卷)和全新题目组成。刷题时可以参考以下策略:
关注历年真题:
适应新题目:
掌握常见算法:
华为OD考试通常涉及以下算法和数据结构:
保持编程规范:
官方参考:
加入刷题社区:
寻找系统性的教程:
刷题的过程可能会比较枯燥,但它能够显著提升编程能力和算法思维。无论是为了通过华为OD的招聘考试,还是为了未来的职业发展,这些积累都会成为重要的财富。
本地编写代码
调整心态,保持冷静
输入输出完整性
快捷键使用
Ctrl+D
,复制、粘贴和撤销分别为 Ctrl+C
,Ctrl+V
,Ctrl+Z
,这些可以正常使用。Ctrl+S
,以免触发浏览器的保存功能。浏览器要求
交卷相关
时间和分数安排
考试环境准备
技术问题处理 a
祝你考试顺利,取得理想成绩!