华为OD机试 - N个选手比赛前三名、比赛(Python/JS/C/C++ 2024 E卷 100分)
华为OD机试 2024E卷题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。
一、题目描述
一个有N个选手参加的比赛,选手编号为1~N(3 <= N <= 100),有M(3 <= M <= 10)个评委对选手进行打分。
打分规则为每个评委对选手打分,最高为10分,最低为1分。
请计算得分最多的3位选手的编号。
如果得分相同,得分高分值最多的选手排名靠前。
(10分数量相同,则比较9分的数量,以此类推,用例中不会出现多个选手得分完全相同的情况。)
二、输入描述
第一行为半角逗号分割的两个正整数,第一个数字表示M(3 <= M <= 10)个评委,第二个数字表示N(3 <= N <= 100)个选手。
第2到M+1行为半角逗号分割的整数数组,表示评委对每个选手的打分,0号下标数字表示1号选手分数,1号下标数字表示2号选手分数,依次类推。
三、输出描述
选手前3名的编号。
注意:
若输入为异常,输出-1,如M、N、打分不在生范围内。
四、测试用例
测试用例1:
1、输入
4,5
10,6,9,7,6
9,10,6,7,5
8,10,6,5,10
9,10,8,4,9
2、输出
2,1,5
3、说明
第一行代表有4个评委,5个选手参加比赛 矩阵代表是4*5,每个数字是选手的编号,每一行代表一个评委对选手的打分排序, 2号选手得分36分排第1,1号选手36分排第2,5号选手30分(2号10分值有3个,1号10分值只有1个,所以2号排第一)
测试用例2:
1、输入
2,5
7,3,5,4,2
8,5,4,4,3
2、输出
-1
3、说明
只有2个评委,要求最少为3个评委
五、解题思路
- 遍历每个评委的打分,将每个选手的分数累加到 totalScore 中,并更新相应的 scoreCounts。
- 总得分从高到低。
- 若总得分相同,比较10分的数量,数量多的排名靠前;若10分数量相同,比较9分的数量,以此类推。
- 取排序后的前3个选手的 id,用逗号分隔输出。
- 如果输入不满足题目要求的格式或范围,直接输出 -1。
六、Python算法源码
import sys# 定义选手类,包含编号、总得分和分数分布
class Contestant:def __init__(self, id):self.id = id # 选手编号self.totalScore = 0 # 总得分self.scoreCounts = [0] * 10 # 分数分布,scoreCounts[0]表示10分的数量,scoreCounts[9]表示1分的数量# 方法:添加一个分数def add_score(self, score):self.totalScore += score # 累加总得分if 1 <= score <= 10:self.scoreCounts[10 - score] += 1 # 更新对应分数的数量def main():try:# 读取所有输入行lines = sys.stdin.read().strip().split('\n')if len(lines) < 1:print("-1")return# 读取第一行并解析M和Nfirst_line = lines[0].strip()mn = first_line.split(',')if len(mn) != 2:print("-1")returnM = int(mn[0].strip()) # 评委数量N = int(mn[1].strip()) # 选手数量# 验证M和N的范围if not (3 <= M <= 10) or not (3 <= N <= 100):print("-1")return# 检查是否有足够的打分行if len(lines) != M + 1:print("-1")return# 初始化选手列表contestants = [Contestant(i+1) for i in range(N)]# 读取M行打分for i in range(1, M+1):score_line = lines[i].strip()scores_str = score_line.split(',')if len(scores_str) != N:print("-1")returnfor j in range(N):try:score = int(scores_str[j].strip())except:print("-1")return# 验证分数范围if not (1 <= score <= 10):print("-1")returncontestants[j].add_score(score) # 为对应选手添加分数# 排序选手# 主要依据:总得分降序# 次要依据:分数分布降序(10分多的优先,依此类推)contestants_sorted = sorted(contestants, key=lambda c: (-c.totalScore, -c.scoreCounts[0], -c.scoreCounts[1],-c.scoreCounts[2], -c.scoreCounts[3],-c.scoreCounts[4], -c.scoreCounts[5],-c.scoreCounts[6], -c.scoreCounts[7],-c.scoreCounts[8], -c.scoreCounts[9]))# 取前3名top3 = contestants_sorted[:3]# 输出结果,用逗号分隔output = ','.join(str(contestant.id) for contestant in top3)print(output)except:# 捕获任何异常,输出-1print("-1")if __name__ == "__main__":main()
七、JavaScript算法源码
// 定义选手类,包含编号、总得分和分数分布
class Contestant {constructor(id) {this.id = id; // 选手编号this.totalScore = 0; // 总得分this.scoreCounts = new Array(10).fill(0); // 分数分布,scoreCounts[0]表示10分的数量,scoreCounts[9]表示1分的数量}// 方法:添加一个分数addScore(score) {this.totalScore += score; // 累加总得分if (score >= 1 && score <= 10) {this.scoreCounts[10 - score] += 1; // 更新对应分数的数量}}
}// 主函数
function main() {const fs = require('fs'); // 引入文件系统模块const input = fs.readFileSync('/dev/stdin', 'utf8'); // 读取标准输入const lines = input.trim().split('\n'); // 按行分割输入try {if (lines.length < 1) { // 如果没有输入console.log("-1");return;}// 读取第一行并解析M和Nconst firstLine = lines[0].trim();const mn = firstLine.split(',');if (mn.length !== 2) { // 确保有两个数字console.log("-1");return;}const M = parseInt(mn[0].trim()); // 评委数量const N = parseInt(mn[1].trim()); // 选手数量// 验证M和N的范围if (isNaN(M) || isNaN(N) || M < 3 || M > 10 || N < 3 || N > 100) {console.log("-1");return;}// 检查是否有足够的打分行if (lines.length !== M + 1) {console.log("-1");return;}// 初始化选手列表const contestants = [];for (let i = 1; i <= N; i++) {contestants.push(new Contestant(i));}// 读取M行打分for (let i = 1; i <= M; i++) {const scoreLine = lines[i].trim();const scoresStr = scoreLine.split(',');if (scoresStr.length !== N) { // 每行必须有N个分数console.log("-1");return;}for (let j = 0; j < N; j++) {const score = parseInt(scoresStr[j].trim());// 验证分数范围if (isNaN(score) || score < 1 || score > 10) {console.log("-1");return;}contestants[j].addScore(score); // 为对应选手添加分数}}// 排序选手contestants.sort((c1, c2) => {if (c2.totalScore !== c1.totalScore) {return c2.totalScore - c1.totalScore; // 总得分降序}// 如果总得分相同,比较分数分布for (let i = 0; i < 10; i++) { // 从10分到1分if (c2.scoreCounts[i] !== c1.scoreCounts[i]) {return c2.scoreCounts[i] - c1.scoreCounts[i]; // 分数数量降序}}return 0; // 如果完全相同,保持原有顺序(题目保证不会有完全相同的情况)});// 取前3名const top3 = contestants.slice(0, 3).map(contestant => contestant.id);// 输出结果,用逗号分隔console.log(top3.join(','));} catch (e) {// 捕获任何异常,输出-1console.log("-1");}
}// 执行主函数
main();
八、C算法源码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定义选手结构体,包含编号、总得分和分数分布
typedef struct {int id; // 选手编号int totalScore; // 总得分int scoreCounts[10]; // 分数分布,scoreCounts[0]表示10分的数量,scoreCounts[9]表示1分的数量
} Contestant;// 函数声明
int compareContestants(const void* a, const void* b);int main() {char buffer[10000]; // 用于读取输入的缓冲区// 读取第一行并解析M和Nif (fgets(buffer, sizeof(buffer), stdin) == NULL) {printf("-1\n");return 0;}// 去除换行符buffer[strcspn(buffer, "\n")] = 0;// 分割M和Nchar* token = strtok(buffer, ",");if (token == NULL) {printf("-1\n");return 0;}int M = atoi(token); // 评委数量token = strtok(NULL, ",");if (token == NULL) {printf("-1\n");return 0;}int N = atoi(token); // 选手数量// 验证M和N的范围if (M < 3 || M > 10 || N < 3 || N > 100) {printf("-1\n");return 0;}// 初始化选手数组Contestant* contestants = (Contestant*)malloc(sizeof(Contestant) * N);for (int i = 0; i < N; i++) {contestants[i].id = i + 1; // 选手编号从1开始contestants[i].totalScore = 0; // 初始化总得分为0for (int j = 0; j < 10; j++) {contestants[i].scoreCounts[j] = 0; // 初始化分数分布为0}}// 读取M行打分for (int i = 0; i < M; i++) {if (fgets(buffer, sizeof(buffer), stdin) == NULL) { // 如果打分行不足M行printf("-1\n");free(contestants);return 0;}// 去除换行符buffer[strcspn(buffer, "\n")] = 0;// 分割分数char* scoreToken = strtok(buffer, ",");int scoreCount = 0;while (scoreToken != NULL && scoreCount < N) {int score = atoi(scoreToken);// 验证分数范围if (score < 1 || score > 10) {printf("-1\n");free(contestants);return 0;}// 更新选手的总得分和分数分布contestants[scoreCount].totalScore += score;contestants[scoreCount].scoreCounts[10 - score] += 1;scoreCount++;scoreToken = strtok(NULL, ",");}if (scoreCount != N) { // 每行必须有N个分数printf("-1\n");free(contestants);return 0;}}// 排序选手qsort(contestants, N, sizeof(Contestant), compareContestants);// 取前3名if (N < 3) {printf("-1\n"); // 选手不足3人free(contestants);return 0;}printf("%d,%d,%d\n", contestants[0].id, contestants[1].id, contestants[2].id);// 释放内存free(contestants);return 0;
}// 比较函数,用于qsort排序
int compareContestants(const void* a, const void* b) {Contestant* c1 = (Contestant*)a;Contestant* c2 = (Contestant*)b;// 首先比较总得分,降序if (c2->totalScore != c1->totalScore) {return c2->totalScore - c1->totalScore;}// 如果总得分相同,比较分数分布for (int i = 0; i < 10; i++) { // 从10分到1分if (c2->scoreCounts[i] != c1->scoreCounts[i]) {return c2->scoreCounts[i] - c1->scoreCounts[i];}}return 0; // 如果完全相同,保持原有顺序
}
九、C++算法源码
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>using namespace std;// 定义选手类,包含编号、总得分和分数分布
class Contestant {
public:int id; // 选手编号int totalScore; // 总得分int scoreCounts[10]; // 分数分布,scoreCounts[0]表示10分的数量,scoreCounts[9]表示1分的数量// 构造函数Contestant(int id_) {id = id_;totalScore = 0;for(int i = 0; i < 10; i++) {scoreCounts[i] = 0; // 初始化分数分布为0}}// 方法:添加一个分数void addScore(int score) {totalScore += score; // 累加总得分if(score >=1 && score <=10) {scoreCounts[10 - score] +=1; // 更新对应分数的数量}}
};// 比较函数,用于排序
bool compareContestants(const Contestant& c1, const Contestant& c2) {if(c1.totalScore != c2.totalScore) {return c1.totalScore > c2.totalScore; // 总得分降序}// 如果总得分相同,比较分数分布for(int i =0; i <10; i++) { // 从10分到1分if(c1.scoreCounts[i] != c2.scoreCounts[i]) {return c1.scoreCounts[i] > c2.scoreCounts[i]; // 分数数量降序}}return false; // 如果完全相同,保持原有顺序
}int main(){ios::sync_with_stdio(false); // 关闭同步,提高IO效率cin.tie(0); // 取消cin的绑定string firstLine;// 读取第一行并解析M和Nif(!getline(cin, firstLine)) {cout << "-1\n";return 0;}// 分割M和Nsize_t commaPos = firstLine.find(',');if(commaPos == string::npos) { // 没有找到逗号cout << "-1\n";return 0;}string mStr = firstLine.substr(0, commaPos);string nStr = firstLine.substr(commaPos +1);int M, N;try {M = stoi(mStr);N = stoi(nStr);}catch(...) { // 解析失败cout << "-1\n";return 0;}// 验证M和N的范围if(M <3 || M >10 || N <3 || N >100) {cout << "-1\n";return 0;}// 初始化选手列表vector<Contestant> contestants;for(int i =1; i<=N; i++) {contestants.emplace_back(i);}// 读取M行打分string scoreLine;for(int i=0; i<M; i++) {if(!getline(cin, scoreLine)) { // 如果打分行不足M行cout << "-1\n";return 0;}// 分割分数vector<int> scores;stringstream ss(scoreLine);string scoreStr;while(getline(ss, scoreStr, ',')) {try {int score = stoi(scoreStr);scores.push_back(score);}catch(...) {cout << "-1\n";return 0;}}if(scores.size() != N) { // 每行必须有N个分数cout << "-1\n";return 0;}// 更新选手的得分for(int j=0; j<N; j++) {int score = scores[j];if(score <1 || score >10) { // 验证分数范围cout << "-1\n";return 0;}contestants[j].addScore(score);}}// 排序选手sort(contestants.begin(), contestants.end(), compareContestants);// 取前3名if(contestants.size() <3) {cout << "-1\n"; // 选手不足3人return 0;}// 输出结果,用逗号分隔cout << contestants[0].id << "," << contestants[1].id << "," << contestants[2].id << "\n";return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。