您的当前位置:首页正文

华为OD机试真题---智能成绩表

2024-11-20 来源:个人技术集锦

题目描述

小明来到某学校当老师,需要将学生按考试总分或单科分数进行排名。输入包括学生人数、科目数量、科目名称、每个学生的姓名和对应科目的成绩,最后输入一个用作排名的科目名称。如果输入的排名科目不存在,则按总分进行排序。输出一行,按成绩排序后的学生名字,名字之间用空格隔开。成绩相同的按照学生姓名字典顺序排序。

输入描述

输出描述

输出一行,按成绩排序后的学生名字,名字之间用空格隔开。

示例

示例1

  • 输入:
3 2
yuwen shuxue
fangfang 95 90
xiaohua 88 95
minmin 100 82
shuxue
  • 输出:
xiaohua fangfang minmin

说明:按shuxue成绩排名,依次是xiaohua、fangfang、minmin。

示例2

  • 输入:
3 2
yuwen shuxue
fangfang 95 90
xiaohua 88 95
minmin 90 95
zongfen
  • 输出:
fangfang minmin xiaohua

说明:排序科目不存在,按总分排序,fangfang和minmin总分相同,按姓名的字典顺序,fangfang排在前面。

解题思路

  1. 读取输入:首先读取学生人数、科目数量、科目名称、每个学生的姓名和对应科目的成绩,以及用作排名的科目名称。
  2. 处理数据
    • 创建一个学生数据结构(如结构体或类),包含学生姓名、各科成绩和总分。
    • 读取数据时,计算每个学生的总分,并存储在相应的数据结构中。
  3. 确定排序规则
    • 检查用作排名的科目名称是否存在于输入的科目列表中。
    • 如果存在,则按该科目成绩进行排序;如果不存在,则按总分进行排序。
  4. 排序:使用合适的排序算法(如快速排序、归并排序等)对学生数组进行排序。如果成绩相同,则按姓名的字典顺序排序。
  5. 输出:按排序后的顺序输出学生的名字。

注意事项

  • 在处理输入时,要注意数据的有效性和边界情况,如输入数据的格式是否正确、是否有非法字符等。
  • 在计算总分和排序时,要注意整数溢出的问题。
  • 在编写代码时,要注意代码的健壮性和可读性,尽量使用简洁明了的代码结构。

代码实现


import lombok.Data;
import lombok.Getter;

import java.io.Serializable;

@Data
public class Student implements Serializable {
    // 获取学生姓名的方法
    @Getter
    private String name;
    private int[] scores;

    // 假设有一个构造函数来初始化这些字段
    public Student(String name, int[] scores) {
        this.name = name;
        this.scores = scores;
    }

    // 获取科目成绩的方法
    public int getScores(int index) {
        return scores[index];
    }

    // 如果需要,可以添加计算总分的方法
    public int getTotalScore() {
        int total = 0;
        for (int score : scores) {
            total += score;
        }
        return total;
    }
    public Student getStudent() {
        return new Student(name, scores);
    }
}

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;

public class SmartGradeSheet {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt(); // 学生人数
        int m = scanner.nextInt(); // 科目数量
        scanner.nextLine(); // 跳过行尾

        String[] subjects = scanner.nextLine().split("\\s+"); // 读取科目名称

        List<Student> students = new ArrayList<>();

        for (int i = 0; i < n; i++) {
            String[] inputs = scanner.nextLine().split("\\s+");
            String name = inputs[0];
            int[] scores = new int[m];
            for (int j = 1; j <= m; j++) {
                scores[j - 1] = Integer.parseInt(inputs[j]);
            }
            students.add(new Student(name, scores));
        }

        String rankingSubject = scanner.nextLine(); // 读取用作排名的科目名称

        Comparator<Student> comparator = null;
        if (contains(subjects, rankingSubject)) {
            // 按指定科目成绩排序
            int subjectIndex = getIndex(subjects, rankingSubject);

            comparator = Comparator.comparingInt( (**Student student**) -> student.getScores(subjectIndex))
                    .thenComparing(Student::getName, Comparator.naturalOrder());
        } else {
            // 按总分排序
            comparator = Comparator.comparingInt(Student::getTotalScore)
                    .thenComparing(Student::getName);
        }

        students.sort(comparator);

        // 输出结果
        for (int i = 0; i < students.size(); i++) {
            if (i > 0) System.out.print(" ");
            System.out.print(students.get(i).getName());
        }
        System.out.println();

        scanner.close();
    }

    // 辅助方法:检查科目名称是否存在于数组中
    private static boolean contains(String[] array, String target) {
        for (String item : array) {
            if (item.equals(target)) {
                return true;
            }
        }
        return false;
    }

    // 辅助方法:获取科目名称在数组中的索引
    private static int getIndex(String[] array, String target) {
        for (int i = 0; i < array.length; i++) {
            if (array[i].equals(target)) {
                return i;
            }
        }
        throw new IllegalArgumentException("Subject not found: " + target);
    }

    // 注意:这里需要给Student类添加getTotalScore()方法,但为了简洁,我直接在构造函数中计算了总分
    // 如果需要,可以添加如下方法到Student类中
    // public int getTotalScore() {
    //     return totalScore;
    // }

}

记一下写代码过程中提示的报错:

最先:
comparator = Comparator.comparingInt( student -> student.getScores(subjectIndex))

SmartGradeSheet.java:41:68 java: 找不到符号 符号: 方法 getScores(int) 位置: 类型为java.lang.Object的变量 student。 网上查了说这种是因为 Student类缺少了getScores(int subjectIndex)方法,但实际是有的。 继续排查说:Comparator 中的 student 被隐式地当作 java.lang.Object 类型处理,而不是 Student 类型,但实际早就定义为了Comparator<Student>,所以问题不在这里。 最后发现: 应该使用 (Student student) -> student.getScores(subjectIndex) 明确指定 student 的类型为 Student


为什么要这样使用呢?

在 Java 中,Lambda 表达式的参数类型可以通过类型推断来确定。然而,在某些情况下,类型推断可能会出现问题,导致编译器无法正确识别参数类型。以下是一些具体的原因和解释:

  1. 类型推断问题
    当编译器无法准确推断 Lambda 参数的类型时,需要显式指定类型。例如,在以下情况下,编译器可能无法正确推断类型:
    Comparator comparator = (student) -> student.getScores(subjectIndex);
    如果编译器无法从上下文中推断出 student 的类型,就会将其视为 Object 类型,从而导致找不到 getScores 方法。
  2. 显式类型声明提高代码可读性和可维护性
    显式指定类型可以提高代码的可读性和可维护性。例如:
    Comparator comparator = (Student student) -> student.getScores(subjectIndex);
显示全文