2026华为OD面试题018:智能成绩表
2026/7/12 19:49:16 网站建设 项目流程

题目描述

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

输入描述:

第 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 语言

#include<stdio.h>#include<stdlib.h>#include<string.h>typedefstruct{charname[16];intscores[12];inttotal;}Student;Student stu[105];charsubjects[12][16];intrankIdx;// -1 表示按总分排,否则是科目下标intcmp(constvoid*a,constvoid*b){Student*x=(Student*)a;Student*y=(Student*)b;intsx=(rankIdx==-1)?x->total:x->scores[rankIdx];intsy=(rankIdx==-1)?y->total:y->scores[rankIdx];if(sx!=sy)returnsy-sx;// 分数降序returnstrcmp(x->name,y->name);// 姓名升序}intmain(){intn,m;scanf("%d %d",&n,&m);for(inti=0;i<m;i++)scanf("%s",subjects[i]);for(inti=0;i<n;i++){scanf("%s",stu[i].name);stu[i].total=0;for(intj=0;j<m;j++){scanf("%d",&stu[i].scores[j]);stu[i].total+=stu[i].scores[j];}}charrankSub[16];scanf("%s",rankSub);rankIdx=-1;for(inti=0;i<m;i++){if(strcmp(rankSub,subjects[i])==0){rankIdx=i;break;}}qsort(stu,n,sizeof(Student),cmp);for(inti=0;i<n;i++){printf("%s%c",stu[i].name,i==n-1?'\n':' ');}return0;}

C++

#include<bits/stdc++.h>usingnamespacestd;structStudent{string name;vector<int>scores;inttotal;};intmain(){intn,m;cin>>n>>m;vector<string>subjects(m);map<string,int>subIdx;for(inti=0;i<m;i++){cin>>subjects[i];subIdx[subjects[i]]=i;}vector<Student>stu(n);for(inti=0;i<n;i++){cin>>stu[i].name;stu[i].scores.resize(m);stu[i].total=0;for(intj=0;j<m;j++){cin>>stu[i].scores[j];stu[i].total+=stu[i].scores[j];}}string rankSub;cin>>rankSub;intrankIdx=subIdx.count(rankSub)?subIdx[rankSub]:-1;sort(stu.begin(),stu.end(),[&](constStudent&a,constStudent&b){intsa=(rankIdx==-1)?a.total:a.scores[rankIdx];intsb=(rankIdx==-1)?b.total:b.scores[rankIdx];if(sa!=sb)returnsa>sb;// 分数降序returna.name<b.name;// 姓名升序});for(inti=0;i<n;i++){cout<<stu[i].name<<(i==n-1?"\n":" ");}return0;}

Java

importjava.util.*;publicclassMain{publicstaticvoidmain(String[]args){Scannersc=newScanner(System.in);intn=sc.nextInt();intm=sc.nextInt();String[]subjects=newString[m];Map<String,Integer>subIdx=newHashMap<>();for(inti=0;i<m;i++){subjects[i]=sc.next();subIdx.put(subjects[i],i);}String[]names=newString[n];int[][]scores=newint[n][m];int[]total=newint[n];for(inti=0;i<n;i++){names[i]=sc.next();for(intj=0;j<m;j++){scores[i][j]=sc.nextInt();total[i]+=scores[i][j];}}StringrankSub=sc.next();Integerhit=subIdx.get(rankSub);finalintidx=(hit==null)?-1:hit;Integer[]order=newInteger[n];for(inti=0;i<n;i++)order[i]=i;Arrays.sort(order,(a,b)->{intsa=(idx==-1)?total[a]:scores[a][idx];intsb=(idx==-1)?total[b]:scores[b][idx];if(sa!=sb)returnsb-sa;// 分数降序returnnames[a].compareTo(names[b]);// 姓名升序});StringBuildersb=newStringBuilder();for(inti=0;i<n;i++){if(i>0)sb.append(' ');sb.append(names[order[i]]);}System.out.println(sb);}}

JavaScript

constreadline=require('readline');constrl=readline.createInterface({input:process.stdin});constlines=[];rl.on('line',(line)=>lines.push(line.trim()));rl.on('close',()=>{const[n,m]=lines[0].split(/\s+/).map(Number);constsubjects=lines[1].split(/\s+/);constsubIdx={};subjects.forEach((s,i)=>{subIdx[s]=i;});conststudents=[];for(leti=0;i<n;i++){constparts=lines[2+i].split(/\s+/);constname=parts[0];constscores=parts.slice(1,1+m).map(Number);consttotal=scores.reduce((a,b)=>a+b,0);students.push({name,scores,total});}constrankSub=lines[2+n];constrankIdx=(rankSubinsubIdx)?subIdx[rankSub]:-1;students.sort((a,b)=>{constsa=(rankIdx===-1)?a.total:a.scores[rankIdx];constsb=(rankIdx===-1)?b.total:b.scores[rankIdx];if(sa!==sb)returnsb-sa;// 分数降序returna.name<b.name?-1:(a.name>b.name?1:0);// 姓名升序});console.log(students.map(s=>s.name).join(' '));});

Python

n,m=map(int,input().split())subjects=input().split()sub_idx={s:ifori,sinenumerate(subjects)}students=[]for_inrange(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)defkey_fn(stu):name,scores,total=stu score=totalifrank_idx==-1elsescores[rank_idx]return(-score,name)# 分数取负实现降序,姓名默认升序students.sort(key=key_fn)print(' '.join(s[0]forsinstudents))

复杂度分析

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

n 最大不到 100,随便排。

总结一下

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

核心口诀:

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

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询