华为OD机试 2024E卷题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。
一、题目描述
新来的老师给班里的同学排一个队。
每个学生有一个影响值。
一些学生是刺头,不会听老师的话,自己选位置,剩余从听老师话的同学在剩下的位置按能力值从小到大排。
对于非刺头同学,如果发现他们前面有能力值比自己高的同学,他不满程度就增加,增加的数量等于前面能力值比他大的同学的个数。
刺头不会产生不满。
如果某个班级的总体不满程度超过k,那么老师就无法继续教这个班级了。
二、输入描述
输入有三行:
第一行为n,m,k,空格隔开,分别表示班级总人数n,刺头人数m,最大不满程度k。
第二行为刺头所在位置的下标,即排队数组的下标,比如1代表队伍中第2个同学是刺头,位置的数组也是排好序的。
第三行为n个数,空格隔开,表示老师排好的队列中每个人的能力值,其中刺头同学一定按照能力值从小到大排序的。
三、输出描述
0 表示老师可以继续教这个班级。
1 表示老师无法继续教这个班级。
备注
n 范围是 [1,100000]
m 范围是 [1,n]
k 范围是 [1,1000000000]
每位同学的能力值范围是 [1000,100000]
四、测试用例
测试用例1:
1、输入
4 2 3
0 1
1810 1809 1801 1802
2、输出
1
3、说明
刺头在0,1位置,2号同学不满程度2(前面两个刺头能力值都比他大),3号同学不满程度2,总不满程度4,大于3。输出不能教这班(1)。
测试用例2:
1、输入
4 2 4
0 1
1810 1809 1801 1802
2、输出
0
3、说明
同前,4不大于4,输出能教这个班(0)。
五、解题思路
1、数据结构和算法
(1)Fenwick 树(Binary Indexed Tree):
用途:高效地进行前缀和查询和更新操作。
原因:需要在 O(n log n) 时间内处理大量数据(n ≤ 100,000),Fenwick 树能在对数时间内完成插入和查询。
(2)坐标压缩:
用途:将能力值范围从 [1000, 100,000] 压缩到 [1, uniqueCount],以适应 Fenwick 树的索引。
原因:能力值可能很大且不连续,直接使用能力值作为索引会浪费空间。通过排序和去重,能够有效地映射能力值到连续的排名。
(3)遍历学生队列:
用途:按队列顺序处理每个学生,计算不满程度。
原因:需要根据学生在队列中的位置和能力值,动态地计算不满程度。
这种组合使得算法能够在保证效率的同时,准确地计算出总不满程度,满足题目的要求。
六、Python算法源码
# 导入必要的库
import sys
import bisect
# 定义 Fenwick 树(又称二叉索引树)类
class FenwickTree:
def __init__(self, size):
self.size = size
self.tree = [0] * (size + 1) # 初始化树,索引从1开始
# 在索引位置添加值
def update(self, index, value):
while index <= self.size:
self.tree[index] += value
index += index & -index # 移动到下一个需要更新的位置
# 查询前缀和,包含当前索引
def query(self, index):
result = 0
while index > 0:
result += self.tree[index]
index -= index & -index # 移动到父节点
return result
def main():
# 读取所有输入并分割成列表
input = sys.stdin.read().split()
ptr = 0 # 指针初始化
# 读取 n(总人数),m(刺头人数),k(最大不满程度)
n = int(input[ptr])
m = int(input[ptr + 1])
k = int(input[ptr + 2])
ptr += 3
# 初始化一个布尔列表标记刺头
rebellious = [False] * n
for _ in range(m):
idx = int(input[ptr])
rebellious[idx] = True
ptr += 1
# 读取所有学生的能力值
abilities = []
for _ in range(n):
abilities.append(int(input[ptr]))
ptr += 1
# 坐标压缩:将能力值排序并去重
sorted_abilities = sorted(list(set(abilities)))
# 为每个能力值分配一个唯一的排名
ability_to_rank = {ability: idx + 1 for idx, ability in enumerate(sorted_abilities)}
# 初始化 Fenwick 树,大小为唯一能力值的数量
fenwick = FenwickTree(len(sorted_abilities))
total_dissatisfaction = 0 # 总不满程度初始化
inserted_count = 0 # 已插入的学生数量初始化
for i in range(n):
ability = abilities[i]
rank = ability_to_rank[ability]
if not rebellious[i]:
# 计算已插入的学生中能力值大于当前学生的数量
higher_count = inserted_count - fenwick.query(rank)
total_dissatisfaction += higher_count
# 如果总不满程度超过k,提前终止
if total_dissatisfaction > k:
break
# 将当前学生的能力值插入 Fenwick 树
fenwick.update(rank, 1)
inserted_count += 1
# 根据总不满程度输出结果
if total_dissatisfaction > k:
print(1)
else:
print(0)
if __name__ == "__main__":
main()
七、JavaScript算法源码
// 定义 Fenwick 树(又称二叉索引树)类
class FenwickTree {
constructor(size) {
this.size = size;
this.tree = new Array(size + 1).fill(0); // 初始化树,索引从1开始
}
// 在索引位置添加值
update(index, value) {
while (index <= this.size) {
this.tree[index] += value;
index += index & -index; // 移动到下一个需要更新的位置
}
}
// 查询前缀和,包含当前索引
query(index) {
let result = 0;
while (index > 0) {
result += this.tree[index];
index -= index & -index; // 移动到父节点
}
return result;
}
}
// 主函数
function main() {
const fs = require('fs');
const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split(/\s+/);
let ptr = 0; // 指针初始化
// 读取 n(总人数),m(刺头人数),k(最大不满程度)
const n = parseInt(input[ptr++]);
const m = parseInt(input[ptr++]);
const k = parseInt(input[ptr++]);
// 初始化一个布尔数组标记刺头
const rebellious = Array(n).fill(false);
for (let i = 0; i < m; i++) {
const idx = parseInt(input[ptr++]);
rebellious[idx] = true;
}
// 读取所有学生的能力值
const abilities = [];
for (let i = 0; i < n; i++) {
abilities.push(parseInt(input[ptr++]));
}
// 坐标压缩:将能力值排序并去重
const sortedAbilities = Array.from(new Set(abilities)).sort((a, b) => a - b);
// 为每个能力值分配一个唯一的排名
const abilityToRank = new Map();
sortedAbilities.forEach((ability, index) => {
abilityToRank.set(ability, index + 1); // 排名从1开始
});
// 初始化 Fenwick 树,大小为唯一能力值的数量
const fenwick = new FenwickTree(sortedAbilities.length);
let totalDissatisfaction = 0; // 总不满程度初始化
let insertedCount = 0; // 已插入的学生数量初始化
for (let i = 0; i < n; i++) {
const ability = abilities[i];
const rank = abilityToRank.get(ability);
if (!rebellious[i]) {
// 计算已插入的学生中能力值大于当前学生的数量
const higherCount = insertedCount - fenwick.query(rank);
totalDissatisfaction += higherCount;
// 如果总不满程度超过k,提前终止
if (totalDissatisfaction > k) {
break;
}
}
// 将当前学生的能力值插入 Fenwick 树
fenwick.update(rank, 1);
insertedCount += 1;
}
// 根据总不满程度输出结果
if (totalDissatisfaction > k) {
console.log(1);
} else {
console.log(0);
}
}
// 调用主函数
main();
八、C算法源码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义 Fenwick 树(又称二叉索引树)结构体
typedef struct {
int size;
long long* tree;
} FenwickTree;
// 初始化 Fenwick 树
FenwickTree* createFenwickTree(int size) {
FenwickTree* ft = (FenwickTree*)malloc(sizeof(FenwickTree));
ft->size = size;
ft->tree = (long long*)calloc(size + 1, sizeof(long long)); // 初始化树,索引从1开始
return ft;
}
// 在索引位置添加值
void updateFenwickTree(FenwickTree* ft, int index, long long value) {
while (index <= ft->size) {
ft->tree[index] += value;
index += index & (-index); // 移动到下一个需要更新的位置
}
}
// 查询前缀和,包含当前索引
long long queryFenwickTree(FenwickTree* ft, int index) {
long long result = 0;
while (index > 0) {
result += ft->tree[index];
index -= index & (-index); // 移动到父节点
}
return result;
}
// 比较函数,用于qsort
int cmp(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
}
int main() {
int n, m;
long long k;
// 读取 n(总人数),m(刺头人数),k(最大不满程度)
scanf("%d %d %lld", &n, &m, &k);
// 初始化一个布尔数组标记刺头
int* rebellious = (int*)calloc(n, sizeof(int));
for(int i = 0; i < m; i++) {
int idx;
scanf("%d", &idx);
rebellious[idx] = 1;
}
// 读取所有学生的能力值
int* abilities = (int*)malloc(n * sizeof(int));
for(int i = 0; i < n; i++) {
scanf("%d", &abilities[i]);
}
// 坐标压缩:将能力值排序并去重
int* sorted = (int*)malloc(n * sizeof(int));
memcpy(sorted, abilities, n * sizeof(int));
qsort(sorted, n, sizeof(int), cmp);
// 去重并记录唯一能力值的数量
int uniqueCount = 1;
for(int i = 1; i < n; i++) {
if(sorted[i] != sorted[i - 1]) {
sorted[uniqueCount++] = sorted[i];
}
}
// 为每个能力值分配一个唯一的排名
// 使用二分查找进行映射
// 因为sorted数组已经排序且去重
// 所以可以使用二分查找来找到每个能力值的排名
// 初始化 Fenwick 树
FenwickTree* fenwick = createFenwickTree(uniqueCount);
long long totalDissatisfaction = 0; // 总不满程度初始化
long long insertedCount = 0; // 已插入的学生数量初始化
for(int i = 0; i < n; i++) {
// 使用二分查找找到当前能力值的排名
int ability = abilities[i];
int left = 0, right = uniqueCount - 1, mid, rank = 1;
while(left <= right) {
mid = left + (right - left) / 2;
if(sorted[mid] == ability) {
rank = mid + 1; // 排名从1开始
break;
}
else if(sorted[mid] < ability) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
if(!rebellious[i]) {
// 计算已插入的学生中能力值大于当前学生的数量
long long higherCount = insertedCount - queryFenwickTree(fenwick, rank);
totalDissatisfaction += higherCount;
// 如果总不满程度超过k,提前终止
if(totalDissatisfaction > k) {
break;
}
}
// 将当前学生的能力值插入 Fenwick 树
updateFenwickTree(fenwick, rank, 1);
insertedCount += 1;
}
// 根据总不满程度输出结果
if(totalDissatisfaction > k) {
printf("1\n");
}
else {
printf("0\n");
}
// 释放内存
free(rebellious);
free(abilities);
free(sorted);
free(fenwick->tree);
free(fenwick);
return 0;
}
九、C++算法源码
#include <bits/stdc++.h>
using namespace std;
// 定义 Fenwick 树(又称二叉索引树)类
class FenwickTree {
public:
int size;
vector<long long> tree;
// 构造函数,初始化树,索引从1开始
FenwickTree(int sz) {
size = sz;
tree.assign(size + 1, 0);
}
// 在索引位置添加值
void update(int index, long long value) {
while(index <= size){
tree[index] += value;
index += index & (-index); // 移动到下一个需要更新的位置
}
}
// 查询前缀和,包含当前索引
long long query(int index){
long long result = 0;
while(index > 0){
result += tree[index];
index -= index & (-index); // 移动到父节点
}
return result;
}
};
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
long long k;
cin >> n >> m >> k;
// 初始化一个布尔数组标记刺头
vector<bool> rebellious(n, false);
for(int i = 0; i < m; i++){
int idx;
cin >> idx;
rebellious[idx] = true;
}
// 读取所有学生的能力值
vector<int> abilities(n);
for(int i = 0; i < n; i++) cin >> abilities[i];
// 坐标压缩:将能力值排序并去重
vector<int> sorted = abilities;
sort(sorted.begin(), sorted.end());
sorted.erase(unique(sorted.begin(), sorted.end()), sorted.end());
// 为每个能力值分配一个唯一的排名
// 使用 lower_bound 进行映射
// 初始化 Fenwick 树
FenwickTree fenwick(sorted.size());
long long totalDissatisfaction = 0; // 总不满程度初始化
long long insertedCount = 0; // 已插入的学生数量初始化
for(int i = 0; i < n; i++){
int ability = abilities[i];
// 使用 lower_bound 找到能力值的排名
int rank = lower_bound(sorted.begin(), sorted.end(), ability) - sorted.begin() + 1; // 排名从1开始
if(!rebellious[i]){
// 计算已插入的学生中能力值大于当前学生的数量
long long higherCount = insertedCount - fenwick.query(rank);
totalDissatisfaction += higherCount;
// 如果总不满程度超过k,提前终止
if(totalDissatisfaction > k){
break;
}
}
// 将当前学生的能力值插入 Fenwick 树
fenwick.update(rank, 1);
insertedCount += 1;
}
// 根据总不满程度输出结果
if(totalDissatisfaction > k){
cout << "1\n";
}
else{
cout << "0\n";
}
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。