(B卷,100分)- 选修课(Java & JS & Python)

题目描述

现有两门选修课,每门选修课都有一部分学生选修,每个学生都有选修课的成绩,需要你找出同时选修了两门选修课的学生,先按照班级进行划分,班级编号小的先输出,每个班级按照两门选修课成绩和的降序排序,成绩相同时按照学生的学号升序排序。

输入描述

第一行为第一门选修课学生的成绩,

第二行为第二门选修课学生的成绩,

每行数据中学生之间以英文分号分隔,每个学生的学号和成绩以英文逗号分隔,

学生学号的格式为8位数字

2位院系编号+入学年份后2位+院系内部1位专业编号+所在班级3位学号

学生成绩的取值范围为[0,100]之间的整数,

两门选修课选修学生数的取值范围为[1-2000]之间的整数。

输出描述

同时选修了两门选修课的学生的学号,如果没有同时选修两门选修课的学生输出NULL,

否则,先按照班级划分,班级编号小的先输出,每个班级先输出班级编号(学号前五位),

然后另起一行输出这个班级同时选修两门选修课的学生学号,学号按照要求排序(按照两门选修课成绩和的降序,成绩和相同时按照学号升序学生之间以英文分号分隔。

用例

输入 01202021,75;01201033,95;01202008,80;01203006,90;01203088,100
01202008,70;01203088,85;01202111,80;01202021,75;01201100,88
输出 01202
01202008;01202021
01203
01203088
说明

同时选修了两选修课的学生01202021、01202008、01203088,这三个学生两门选修课的成绩和分别为150、150、185,

01202021、01202008属于01202班的学生,按照成绩和降序,成绩相同时按学号升序输出的结果为01202008;01202021,

01203088属于01203班的学生,按照成绩和降序,成绩相同时按学号升序输出的结果为01203088,

01202的班级编号小于01203的班级编号,需要先输出。

输入 01201022,75;01202033,95;01202018,80;01203006,90;01202066,100
01202008,70;01203102,85;01202111,80;01201021,75;01201100,88
输出 NULL
说明 没有同时选修了两门选修课的学生,输出NULL.

题目解析

本题主要考察:字符串,数组,集合的操作,考察多条件排序。

本题的逻辑如下:

  1. 从输入的两行中,解析出学生信息(学号,班号,课程一得分,课程二得分)
  2. 过滤出两门课程都有得分的学生
  3. 将学生按照班号进行分别统计
  4. 按照班号进行升序,然后打印班号,再将该班号下的学生按照:总分进行降序,总分相同,则继续按照学号升序,然后以“;”拼接同班学生的学号,进行打印

难点主要在于第一步,如何从两行输入解析中得到一个完整学生的信息,这里我选用了字典结构,key为学生学号,value为学生信息,解析第二行输入时,可以检查字典是否已存在对应学号的key,若存在则再对应value下补充课程二得分。

Java算法源码

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.util.StringJoiner;

public class Main {
  // 学生类
  static class Student {
    String sid; // 学号
    String cid; // 班号
    int score1 = -1; // 课程一 得分
    int score2 = -1; // 课程二 得分

    // 总分
    public int getSumScore() {
      return this.score1 + this.score2;
    }
  }

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

    String s1 = sc.nextLine();
    String s2 = sc.nextLine();

    getResult(s1, s2);
  }

  public static void getResult(String s1, String s2) {
    // key是学号,value是学生对象
    HashMap<String, Student> students = new HashMap<>();

    // 解析学生信息
    divide(s1, 1, students);
    divide(s2, 2, students);

    // 过滤出有两个课程得分的学生
    Student[] suits =
        students.values().stream()
            .filter(stu -> stu.score1 != -1 && stu.score2 != -1)
            .toArray(Student[]::new);

    // 如果不存在这样的学生,则返回NULL
    if (suits.length == 0) {
      System.out.println("NULL");
      return;
    }

    // key是班号,value是该班级的学生集合
    HashMap<String, ArrayList<Student>> ans = new HashMap<>();
    for (Student stu : suits) {
      ans.putIfAbsent(stu.cid, new ArrayList<>());
      ans.get(stu.cid).add(stu);
    }

    ans.keySet().stream()
        .sorted(String::compareTo) // 按照班号升序
        .forEach(
            cid -> {
              System.out.println(cid); // 打印班号

              ArrayList<Student> studs = ans.get(cid);
              studs.sort(
                  (a, b) ->
                      a.getSumScore() != b.getSumScore()
                          ? b.getSumScore() - a.getSumScore()
                          : a.sid.compareTo(b.sid)); // 同一班的学生按照总分降序,总分相同,则按照学号升序

              // 打印同一班的学号,以分号分隔
              StringJoiner sj = new StringJoiner(";");
              for (Student stud : studs) sj.add(stud.sid);
              System.out.println(sj);
            });
  }

  public static void divide(String str, int courseId, HashMap<String, Student> students) {
    for (String sub : str.split(";")) {
      String[] tmp = sub.split(",");

      String sid = tmp[0]; // 学号
      String cid = sid.substring(0, 5); // 班号
      int score = Integer.parseInt(tmp[1]); // 课程得分

      students.putIfAbsent(sid, new Student()); // 是否已记录过该学生,若没有则生成对应学生对象

      // 初始化学生对象
      Student stu = students.get(sid);

      stu.sid = sid;
      stu.cid = cid;

      if (courseId == 1) stu.score1 = score;
      else stu.score2 = score;
    }
  }
}

JS算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines = [];
rl.on("line", (line) => {
  lines.push(line);

  if (lines.length == 2) {
    getResult(lines[0], lines[1]);
    lines.length = 0;
  }
});

function getResult(s1, s2) {
  // key是学号,value是学生对象
  const students = {};

  // 解析学生信息
  devide(s1, 1, students);
  devide(s2, 2, students);

  // 过滤出有两个课程得分的学生
  const suits = Object.values(students).filter(
    (stu) => stu.score1 !== undefined && stu.score2 !== undefined
  );

  // 如果不存在这样的学生,则返回NULL
  if (suits.length == 0) {
    console.log("NULL");
    return;
  }

  // key是班号,value是该班级的学生集合
  const ans = {};
  for (let stu of suits) {
    const cid = stu.cid;
    if (!ans[cid]) ans[cid] = [];
    ans[cid].push(stu);
  }

  Object.keys(ans)
    .sort((a, b) => strCmp(a, b)) // 按照班号升序
    .forEach((cid) => {
      // 打印班号
      console.log(cid);

      // 打印同一班的学生学号,以分号分隔, 同一班的学生按照总分降序,总分相同,则按照学号升序
      console.log(
        ans[cid]
          .sort((a, b) =>
            a.getSumScore() - b.getSumScore()
              ? b.getSumScore() - a.getSumScore()
              : strCmp(a.sid, b.sid)
          )
          .map((a) => a.sid)
          .join(";")
      );
    });
}

function devide(str, courseId, students) {
  str.split(";").forEach((sub) => {
    let [sid, score] = sub.split(",");
    score = Number(score);
    const cid = sid.slice(0, 5);

    if (!students[sid]) {
      students[sid] = new Student(); // 是否已记录过该学生,若没有则生成对应学生对象
    }

    const stu = students[sid];
    stu.sid = sid; // 学号
    stu.cid = cid; // 班号
    courseId == 1 ? (stu.score1 = score) : (stu.score2 = score); // 课程得分
  });
}

// 字符串比较大小
function strCmp(a, b) {
  return a == b ? 0 : a > b ? 1 : -1;
}

// 学生类
class Student {
  constructor(sid, cid, score1, score2) {
    this.sid = sid; // 学号
    this.cid = cid; // 班号
    this.score1 = score1; // 课程一 得分
    this.score2 = score2; // 课程二 得分
  }

  // 总分
  getSumScore() {
    return this.score1 + this.score2;
  }
}

Python算法源码

# 输入获取
s1 = input()
s2 = input()


class Student:
    def __init__(self, sid, cid, score1, score2):
        self.sid = sid  # 学号
        self.cid = cid  # 班号
        self.score1 = score1  # 课程一 得分
        self.score2 = score2  # 课程二 得分

    # 总分
    def getSumScore(self):
        return self.score1 + self.score2


def divide(s, courseId, students):
    for sub in s.split(";"):
        sid, score = sub.split(",")
        score = int(score)
        cid = sid[:5]

        # 是否已记录过该学生,若没有则生成对应学生对象
        if students.get(sid) is None:
            students[sid] = Student(sid, cid, -1, -1)

        if courseId == 1:
            students[sid].score1 = score
        else:
            students[sid].score2 = score


# 算法入口
def getResult():
    # key是学号,value是学生对象
    students = {}

    # 解析学生信息
    divide(s1, 1, students)
    divide(s2, 2, students)

    # 过滤出有两个课程得分的学生
    suits = list(filter(lambda stu: stu.score1 != -1 and stu.score2 != -1, students.values()))

    # 如果不存在这样的学生,则返回NULL
    if len(suits) == 0:
        print("NULL")
        return

    # key是班号,value是该班级的学生集合
    ans = {}
    for stu in suits:
        cid = stu.cid
        if ans.get(cid) is None:
            ans[cid] = []
        ans[cid].append(stu)

    tmp = list(ans.keys())
    tmp.sort()  # 按照班号升序

    for cid in tmp:
        # 打印班号
        print(cid)

        # 同一班的学生按照总分降序,总分相同,则按照学号升序
        ans[cid].sort(key=lambda x: (-x.getSumScore(), x.sid))
        # 打印同一班的学生学号,以分号分隔
        print(";".join(map(lambda x: x.sid, ans[cid])))


# 算法调用
getResult()

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?