华为OD机试真题---选修课

华为OD机试真题中的“选修课”题目,主要考察的是对数据的处理能力和排序算法的理解。以下是对该题目的详细解析:

一、题目描述

现有两门选修课,每门选修课都有一部分学生选修,每个学生都有选修课的成绩。要求找出同时选修了两门选修课的学生,并按照以下规则进行排序和输出:

  1. 先按照班级进行划分,班级编号小的先输出。
  2. 每个班级内,按照两门选修课成绩和的降序排序。
  3. 成绩相同时,按照学生的学号升序排序。

二、输入输出

输入

  • 第一行为第一门选修课学生的成绩,
  • 第二行为第二门选修课学生的成绩,每行数据中学生之间以英文分号分隔,每个学生的学号和成绩以英文逗号分隔,
  • 学生学号的格式为 8 位数字(2 位院系编号+入学年份后2 位+院系内部1位专业编号+所在班级3位学号),
  • 学生成绩的取值范围为「8,100]之间的整数,
  • 两门选修课选修学生数的取值范围为[1-2000]之间的整数。

输出

  • 同时选修了两门选修课的学生的学号,如果没有同时选修两门选修课的学生输出NULL否则,
  • 先按照班级划分,班级编号小的先输出,
  • 每个班级先输出班级编号(学号前五位),然后另起一行输出这个班级同时选修两门选修课的学生学号,
  • 学号按照要求排序(按照两门选修课成绩和的降序,
  • 成绩和相同时按照学号升序学生之间以英文分号分隔。

三、解题思路

  1. 数据读取与存储:首先读取输入的两行数据,分别存储到两个列表中。每个列表中的元素是一个包含班级编号、学号和成绩的字符串,可以通过分割字符串来获取这些信息。
  2. 找出同时选修两门课程的学生:遍历两个列表,通过比较班级编号和学号来找出同时选修了两门课程的学生。可以将这些信息存储到一个字典中,字典的键是班级编号+学号,值是两门课程的成绩。
  3. 排序:根据题目要求,先按照班级编号排序,然后按照两门课成绩和的降序排序,如果成绩和相同,则按照学号升序排序。可以使用Java的sorted函数和自定义排序规则来实现。
  4. 输出:按照排序后的顺序输出学生的班级编号和学号。

四、代码参考

以下是一个可能的代码实现:



import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.stream.Collectors;

class Student {
    String studentId; // 学号
    String classId;   // 班级编号(学号前五位)
    int score1;       // 第一门课成绩
    int score2;       // 第二门课成绩

    public Student(String studentId, String classId, int score1, int score2) {
        this.studentId = studentId;
        this.classId = classId;
        this.score1 = score1;
        this.score2 = score2;
    }

    // 用于排序的比较器
    public static Comparator<Student> getComparator() {
        return Comparator.comparing(Student::getClassId)
                .thenComparingInt(s -> -(s.score1 + s.score2)) // 降序,所以取负值
                .thenComparing(Student::getStudentId);
    }

    // Getter 方法
    public String getStudentId() {
        return studentId;
    }

    public String getClassId() {
        return classId;
    }
}

public class ElectiveCourses {

    public static void main(String[] args) {
        // 创建Scanner对象读取输入
        Scanner scanner = new Scanner(System.in);

        // 读取第一行输入,并分割成数组
        String[] input1 = scanner.nextLine().split(";");
        // 读取第二行输入,并分割成数组
        String[] input2 = scanner.nextLine().split(";");

        // 创建存储学生信息的Map,键为学号,值为Student对象
        Map<String, Student> students = new HashMap<>();

        // 处理第一行输入,初始化学生信息
        for (String item : input1) {
            String[] parts = item.split(",");
            String studentId = parts[0];
            String classId = studentId.substring(0, 5); // 提取班级编号
            int score1 = Integer.parseInt(parts[1]);
            students.put(studentId, new Student(studentId, classId, score1, 0));
        }

        // 处理第二行输入,更新学生的第二门课成绩
        for (String item : input2) {
            String[] parts = item.split(",");
            String studentId = parts[0];
            int score2 = Integer.parseInt(parts[1]);
            if (students.containsKey(studentId)) {
                students.get(studentId).score2 = score2;
            }
        }

        // 筛选出同时选修了两门课的学生
        List<Student> enrolledStudents = students.values().stream()
                .filter(s -> s.score2 != 0) // 假设初始化为0表示未选修第二门课
                .collect(Collectors.toList());

        // 如果没有同时选修两门选修课的学生,输出NULL并结束程序
        if (enrolledStudents.isEmpty()) {
            System.out.println("NULL");
            scanner.close();
            return;
        }

        // 对学生进行排序
        enrolledStudents.sort(Student.getComparator());

        // 输出结果
        Map<String, List<String>> resultMap = new TreeMap<>();
        for (Student student : enrolledStudents) {
            resultMap.computeIfAbsent(student.getClassId(), k -> new ArrayList<>()).add(student.getStudentId());
        }

        // 遍历结果Map,输出班级编号和对应的学生学号
        for (Map.Entry<String, List<String>> entry : resultMap.entrySet()) {
            System.out.println(entry.getKey());
            String studentIds = String.join(";", entry.getValue());
            System.out.println(studentIds);
        }

        // 关闭Scanner
        scanner.close();
    }
}

注意:上述代码是一个简化的示例,用于说明解题思路。在实际应用中,可能需要根据具体的输入格式和要求进行适当的调整。例如,如果输入数据中的班级编号和学号不是固定的长度,或者存在其他特殊情况,需要相应地修改代码来处理这些情况。

五、运行解析

输入示例
01234001,90;01234002,85;05678001,95;01234003,88
01234001,92;01234003,89;05679001,78
解析步骤

1、读取输入:

  • 第一行输入:01234001,90;01234002,85;05678001,95;01234003,88
  • 第二行输入:01234001,92;01234003,89;05679001,78

2、处理第一行输入:

  • 01234001,90 -> 学号: 01234001, 班级编号: 01234, 成绩1: 90
  • 01234002,85 -> 学号: 01234002, 班级编号: 01234, 成绩1: 85
  • 05678001,95 -> 学号: 05678001, 班级编号: 05678, 成绩1: 95
  • 01234003,88 -> 学号: 01234003, 班级编号: 01234, 成绩1: 88

3、处理第二行输入:

  • 01234001,92 -> 更新学号: 01234001 的成绩2为 92
  • 01234003,89 -> 更新学号: 01234003 的成绩2为 89
  • 05679001,78 -> 学号: 05679001 没有在第一行输入中出现,因此不会被处理

4、筛选同时选修两门课程的学生:

  • 01234001 -> 成绩1: 90, 成绩2: 92
  • 01234003 -> 成绩1: 88, 成绩2: 89

5、排序:

  • 根据班级编号、总成绩(降序)和学号排序:
    • 01234001 -> 班级编号: 01234, 总成绩: 182
    • 01234003 -> 班级编号: 01234, 总成绩: 177

6、输出结果:

  • 班级编号: 01234
  • 学号: 01234001;01234003
输出结果
01234
01234001;01234003

懒得在控制台输入的话:

// 模拟输入数据  
        String inputData = "01234001,90;01234002,85;05678001,95;01234003,88\n" +  
                           "01234001,92;01234003,89;05679001,78";  
  
        // 使用ByteArrayInputStream来模拟标准输入  
        ByteArrayInputStream in = new ByteArrayInputStream(inputData.getBytes());  
        System.setIn(in);  
  
        Scanner scanner = new Scanner(System.in);  

总的来说,这道题目主要考察了数据处理和排序算法的应用,需要细心地处理输入数据,并按照题目要求进行排序和输出。

上一篇:apache


下一篇:C++文字识别接口介绍-翔云-通用文字识别API接口