
华为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在线答疑。




















