2026华为OD面试题018:智能成绩表

题目描述

小明来到某学校当老师,需要将学生按考试总分或单科分数进行排名,你能帮帮他吗?

输入描述:

第 1 行输入两个整数,学生人数 n 和科目数量 m。0 < n < 100,0 < m < 10。

第 2 行输入 m 个科目名称,彼此之间用空格隔开。科目名称只由英文字母构成,单个长度不超过 10 个字符。科目的出现顺序和后续输入的学生成绩一一对应,不会出现重复的科目名称。

第 3 行开始的 n 行,每行包含一个学生的姓名和该生 m 个科目的成绩(空格隔开),学生不会重名。学生姓名只由英文字母构成,长度不超过 10 个字符。成绩是 0 到 100 的整数,依次对应第 2 行中输入的科目。

末尾一行,输入用作排名的科目名称。若科目不存在,则按总分进行排序。

输出描述:

输出一行,按成绩排序后的学生名字,空格隔开。成绩相同时,按姓名字典序升序排列。

原题文件在输出描述"成绩相"处截断,这里按常见题型补全为"成绩相同时,按姓名字典序升序排列"。排序方向按常见排名习惯取降序(分数高的在前)。

示例 1:

输入:

复制代码
3 2
yuwen shuxue
fangfang 95 90
xiaohong 88 95
xiaoxin 90 90
shuxue

输出:

复制代码
xiaohong fangfang xiaoxin

示例 2(科目不存在,按总分排):

输入:

复制代码
3 2
yuwen shuxue
fangfang 95 90
xiaohong 88 95
xiaoxin 90 90
english

输出:

复制代码
fangfang xiaohong xiaoxin

讲个故事:班主任老李的排名难题

老李刚接手三年级二班,校长丢来一张成绩表,让他排个名。

"按数学成绩排。"校长撂下一句话就走了。

老李一看,fangfang 和 xiaoxin 数学都考了 90,这谁排前面?挠了半天头,末尾按姓名拼音排,fangfang 在 xiaoxin 前面,搞定。

结果第二天校长又改口:"按英语排。"老李翻遍成绩表,压根没有英语这科。那咋办?按总分排呗。

说白了,这道题就是模拟老李的整个排榜过程:指定科目就按科目排,科目不存在就按总分排,同分看名字。

核心原理:一次自定义排序

整道题就一个核心动作:排序。难点全在比较器上。

比较器有两条规则,按优先级从高到低:

  1. 按排名分数降序。分数高的排前面。
  2. 分数相同时,按姓名字典序升序。名字小的排前面。

排名分数怎么定?看末尾一行输入的科目名:

  • 如果这科在科目表里,排名分数就是该科成绩
  • 如果这科不存在,排名分数就是总分(所有科目之和)

所以关键是建一张"科目名到科目下标"的映射表,查一下就知道按哪科排。查不到就退化为总分排序。

拿示例 1 走一遍。按 shuxue 排,三人数学成绩分别是 fangfang 90、xiaohong 95、xiaoxin 90。降序排,xiaohong 95 分最高,排第一。剩下两人都是 90,按名字升序,fangfang 在 xiaoxin 前面。最终输出 xiaohong fangfang xiaoxin

换成示例 2,english 这科不存在,就按总分。三人总分 fangfang 185、xiaohong 183、xiaoxin 180,降序就是 fangfang xiaohong xiaoxin

怎么实现?

  1. 读入 n、m
  2. 读入 m 个科目名,建一张"科目名到下标"的映射
  3. 读入 n 个学生,每人存姓名、各科成绩,顺手算出总分
  4. 读入排名科目名,查映射;查到用对应科目成绩,查不到用总分
  5. 自定义排序:分数降序,同分按姓名升序
  6. 输出排序后的姓名,空格隔开

代码实现

C 语言

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char name[16];
    int scores[12];
    int total;
} Student;

Student stu[105];
char subjects[12][16];
int rankIdx;  // -1 表示按总分排,否则是科目下标

int cmp(const void *a, const void *b) {
    Student *x = (Student *)a;
    Student *y = (Student *)b;
    int sx = (rankIdx == -1) ? x->total : x->scores[rankIdx];
    int sy = (rankIdx == -1) ? y->total : y->scores[rankIdx];
    if (sx != sy) return sy - sx;            // 分数降序
    return strcmp(x->name, y->name);         // 姓名升序
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++) scanf("%s", subjects[i]);
    for (int i = 0; i < n; i++) {
        scanf("%s", stu[i].name);
        stu[i].total = 0;
        for (int j = 0; j < m; j++) {
            scanf("%d", &stu[i].scores[j]);
            stu[i].total += stu[i].scores[j];
        }
    }
    char rankSub[16];
    scanf("%s", rankSub);
    rankIdx = -1;
    for (int i = 0; i < m; i++) {
        if (strcmp(rankSub, subjects[i]) == 0) { rankIdx = i; break; }
    }
    qsort(stu, n, sizeof(Student), cmp);
    for (int i = 0; i < n; i++) {
        printf("%s%c", stu[i].name, i == n - 1 ? '\n' : ' ');
    }
    return 0;
}

C++

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

struct Student {
    string name;
    vector<int> scores;
    int total;
};

int main() {
    int n, m;
    cin >> n >> m;
    vector<string> subjects(m);
    map<string, int> subIdx;
    for (int i = 0; i < m; i++) {
        cin >> subjects[i];
        subIdx[subjects[i]] = i;
    }
    vector<Student> stu(n);
    for (int i = 0; i < n; i++) {
        cin >> stu[i].name;
        stu[i].scores.resize(m);
        stu[i].total = 0;
        for (int j = 0; j < m; j++) {
            cin >> stu[i].scores[j];
            stu[i].total += stu[i].scores[j];
        }
    }
    string rankSub;
    cin >> rankSub;
    int rankIdx = subIdx.count(rankSub) ? subIdx[rankSub] : -1;

    sort(stu.begin(), stu.end(), [&](const Student &a, const Student &b) {
        int sa = (rankIdx == -1) ? a.total : a.scores[rankIdx];
        int sb = (rankIdx == -1) ? b.total : b.scores[rankIdx];
        if (sa != sb) return sa > sb;                 // 分数降序
        return a.name < b.name;                       // 姓名升序
    });

    for (int i = 0; i < n; i++) {
        cout << stu[i].name << (i == n - 1 ? "\n" : " ");
    }
    return 0;
}

Java

java 复制代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        String[] subjects = new String[m];
        Map<String, Integer> subIdx = new HashMap<>();
        for (int i = 0; i < m; i++) {
            subjects[i] = sc.next();
            subIdx.put(subjects[i], i);
        }
        String[] names = new String[n];
        int[][] scores = new int[n][m];
        int[] total = new int[n];
        for (int i = 0; i < n; i++) {
            names[i] = sc.next();
            for (int j = 0; j < m; j++) {
                scores[i][j] = sc.nextInt();
                total[i] += scores[i][j];
            }
        }
        String rankSub = sc.next();
        Integer hit = subIdx.get(rankSub);
        final int idx = (hit == null) ? -1 : hit;

        Integer[] order = new Integer[n];
        for (int i = 0; i < n; i++) order[i] = i;
        Arrays.sort(order, (a, b) -> {
            int sa = (idx == -1) ? total[a] : scores[a][idx];
            int sb = (idx == -1) ? total[b] : scores[b][idx];
            if (sa != sb) return sb - sa;              // 分数降序
            return names[a].compareTo(names[b]);       // 姓名升序
        });

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            if (i > 0) sb.append(' ');
            sb.append(names[order[i]]);
        }
        System.out.println(sb);
    }
}

JavaScript

javascript 复制代码
const readline = require('readline');
const rl = readline.createInterface({input: process.stdin});
const lines = [];
rl.on('line', (line) => lines.push(line.trim()));
rl.on('close', () => {
    const [n, m] = lines[0].split(/\s+/).map(Number);
    const subjects = lines[1].split(/\s+/);
    const subIdx = {};
    subjects.forEach((s, i) => { subIdx[s] = i; });

    const students = [];
    for (let i = 0; i < n; i++) {
        const parts = lines[2 + i].split(/\s+/);
        const name = parts[0];
        const scores = parts.slice(1, 1 + m).map(Number);
        const total = scores.reduce((a, b) => a + b, 0);
        students.push({name, scores, total});
    }

    const rankSub = lines[2 + n];
    const rankIdx = (rankSub in subIdx) ? subIdx[rankSub] : -1;

    students.sort((a, b) => {
        const sa = (rankIdx === -1) ? a.total : a.scores[rankIdx];
        const sb = (rankIdx === -1) ? b.total : b.scores[rankIdx];
        if (sa !== sb) return sb - sa;                 // 分数降序
        return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0);  // 姓名升序
    });

    console.log(students.map(s => s.name).join(' '));
});

Python

python 复制代码
n, m = map(int, input().split())
subjects = input().split()
sub_idx = {s: i for i, s in enumerate(subjects)}

students = []
for _ in range(n):
    parts = input().split()
    name = parts[0]
    scores = list(map(int, parts[1:1 + m]))
    students.append((name, scores, sum(scores)))

rank_sub = input().strip()
rank_idx = sub_idx.get(rank_sub, -1)


def key_fn(stu):
    name, scores, total = stu
    score = total if rank_idx == -1 else scores[rank_idx]
    return (-score, name)          # 分数取负实现降序,姓名默认升序


students.sort(key=key_fn)
print(' '.join(s[0] for s in students))

复杂度分析

  • 时间复杂度:O(n * log n),主要是排序。读入和算总分是 O(n * m),m < 10 可视为常数
  • 空间复杂度:O(n * m),存储所有学生成绩

n 最大不到 100,随便排。

总结一下

智能成绩表 = 自定义排序 + 科目映射查表。

核心口诀:

  • 排名科目查得到,按单科排;查不到,按总分排
  • 分数降序,同分按姓名升序
  • 建一张"科目名到下标"的映射,是切换两种模式的关键

这道题本身不难,真正容易翻车的是同分处理:忘了写姓名这一级比较器,遇到同分用例就过不去。把比较器写全,两条规则一个都不能少。

你还在哪些排序题里栽过跟头?欢迎在评论区聊聊。

相关推荐
令狐掌门8 天前
2026华为OD面试题002:路口最短时间问题
华为od·华为od面试题
令狐掌门8 天前
2026华为OD面试题001:两个字符串间的最短路径问题
华为od·华为od面试题
2601_9620725525 天前
李梦娇常识4600问|题库|打印版
sql·华为od·华为·c#·华为云·.net·harmonyos
HEADKON1 个月前
Larotretinib拉罗替尼治NTRK融合实体瘤,神经系统反应多为一过性
华为od
无限码力1 个月前
2026最新华为OD机试新系统 机考真题考点分类 + 备考策略
华为od·华为od机考·华为od机试·华为od机试新系统真题·华为od机试备考策略·华为od机考真题考点详解
TechPioneer_lp2 个月前
就业指导|中九非科班毕业,华为 OD 做 Java 后端想转 C++,能找到深度学习挂钩的岗工作吗?
java·c++·华为od·华为·就业指导·校招指导
无限码力2 个月前
华为OD机试真题 新系统-等距二进制判断(C/C++/Py/Java/Js/Go)
华为od·华为od机考·华为od机试真题·华为od机试·华为od机试题库·华为od机试新系统真题
largecode2 个月前
怎么让手机显示公司名?来电显示公司名称认证实现品牌外显
linux·ubuntu·华为od·华为·智能手机·华为云·harmonyos
无限码力2 个月前
华为OD新系统机试真题 - 日志文件异常检测
华为od·华为od机考·华为od机试真题·华为od上机考试真题·华为od机考真题·华为od新系统机试真题·华为od新系统机试