题目描述:
给你两个字符串数组 positive_feedback
和 negative_feedback
,分别包含表示正面的和负面的词汇。不会 有单词同时是正面的和负面的。
一开始,每位学生分数为 0
。每个正面的单词会给学生的分数 加 3
分,每个负面的词会给学生的分数 减 1
分。
给你 n
个学生的评语,用一个下标从 0 开始的字符串数组 report
和一个下标从 0 开始的整数数组 student_id
表示,其中 student_id[i]
表示这名学生的 ID ,这名学生的评语是 report[i]
。每名学生的 ID 互不相同。
给你一个整数 k
,请你返回按照得分 从高到低 最顶尖的 k
名学生。如果有多名学生分数相同,ID 越小排名越前。
贴俩示例,便于理解。
这道题给的条件有点多,但并不复杂,仔细阅读后理一遍逻辑我们就可以开始编写我们代码了,有一个小细节需要注意注意就是我们的学生id并不是“i”,而是student_id[i],其对应的评语是report[i],这个报告信息不是我们根据传入学生id获得的,而就是“i”。
两个难点:1、赋分;2、排序。其中以排序较为复杂。
思路:
1、关于赋分:我们可以先把积极词汇与消极词汇分别用Map集合存起来,然后遍历学生,用String类的split()方法切割该学生的评语,用String数组接住,然后遍历该数组,调用Map集合的containsKey()方法,根据不同的规则进行加减分数。
2、关于排序:我们排序的依据有两个:分数和ID,我们可以通过Collections的sort方法进行排序,但是我们的需求比较复杂,且有两个指标,我的解决想法是,建一个Studen类,封装分数和ID两个成员变量,再重写sort的比较器,用List集合存学生对象,再传入sort方法中,实现自定义排序。
代码实现:
1、构建学生类
class Student{
long id;
long score;
}
2、主方法
public List<Integer> topStudents(String[] positive_feedback, String[] negative_feedback, String[] report, int[] student_id, int k) {
Map<String,Integer> pos = new HashMap<>(); // 接积极词汇
for (int i = 0; i < positive_feedback.length; i++) {
pos.put(positive_feedback[i],0);
}
Map<String,Integer> neg = new HashMap<>(); // 接消极词汇
for (int i = 0; i < negative_feedback.length; i++) {
neg.put(negative_feedback[i],0);
}
List<Integer> ans = new ArrayList<>(k); // 结果统计前k名学生
List<Student> students = new ArrayList<>(); // 用于接所有学生对象
for (int i = 0; i < student_id.length; i++) {
Student student = new Student();
int score = 0; // 初始化分数
student.id = student_id[i]; // 学号
String words = report[i]; // 该学生的评语
String[] arr = words.split(" "); // 将评语切割
for (int j = 0; j < arr.length; j++) {
// 遍历评语数组
if (pos.containsKey(arr[j])){
// 含积极词
score += 3;
}
if (neg.containsKey(arr[j])){
// 含消极词
score--;
}
}
// 统计最终分数
student.score = score;
students.add(student); // 添加学生对象到学生集合中
}
// 对学生集合排序:比较器的重写采用lambda形式
// 该比较器默认为正序排列(从小到大)
Collections.sort(students,(studentA,studentB)->{
// 若比比较对象的差值小于零则不改变原顺序
if(studentA.score != studentB.score){
// 两者分数不相等,则按照分数由高到低
// 解释:A为前者,B为后者,若(B-A) > 0,则改变原A、B的顺序编程“B、A”
// 若(B-A) < 0,说明A 大于 B,不改变原顺序。
return (int) (studentB.score - studentA.score);
}else {
// 成绩相同,根据ID从小到大排序(默认即如此)
return (int) (studentA.id - studentB.id);
}
});
// 根据需求取出前 k 项的值
for (int i = 0; i < k; i++) {
ans.add((int)students.get(i).id);
}
return ans;
}