一线城市的年轻人为了省钱,跟陌生人拼好床的帖子,我开始还以为是开玩笑,翻看之下,居然是真的
刚刷到这个帖子,我第一反应是:这年头拼车拼饭都不稀奇了,怎么连床都能拼?
一个在一线城市上班的年轻人,为了省房租,居然跟完全不认识的人合睡一张床,还分时间段。白天你睡,晚上我睡,跟网吧包夜似的。我一开始真以为是网友编段子,结果往下翻,聊天记录、价格、要求全有,居然真有人在干。
最离谱的是,发帖人还觉得挺划算,反正两个人作息不一样,床空着也是空着。可这哪是租房啊,这感觉像给自己租了个充电位。隐私、安全、卫生先不说,万一哪天加班提前回来,俩人大眼瞪小眼,谁先出去?
一线城市房租确实狠,但能把人逼到跟陌生人拼床,我看完还是有点沉默。
一道分组统计题:找出至少有 5 名学生的课程
这题代码不长,真正容易写错的是边界。
题目给出一批选课记录,每条记录包含学生和课程,要求找出学生人数不少于 5 的课程。题目标题虽然叫“超过 5 名学生的课”,但常见题面的判断条件是至少 5 名,也就是 >= 5。这里我会先盯一眼,不然后面代码写得再漂亮,测试用例照样过不了。
例如选课记录如下:
Amy Math
Bob Math
Cindy Math
David Math
Eric Math
Frank Java
Grace Java
Math 有 5 名学生,需要返回;Java 只有 2 名,不返回。
这种题没必要上复杂算法。遍历一次数据,用 Map 按课程分组,最后再筛选人数即可。
不过我不太建议直接用 Map<String, Integer> 计数。实际导入选课数据时,重复记录并不少见。同一个学生重复选中一门课,如果直接加一,人数就会被算大。
稳一点的写法是:课程作为 key,学生集合做 value。
import java.util.*;
publicclassCourseCounter{
record Enrollment(String student, String course){}
publicstatic List<String> findPopularCourses(
List<Enrollment> records, int limit){
Map<String, Set<String>> courseStudents = new HashMap<>();
for (Enrollment record : records) {
if (record == null
|| record.student() == null
|| record.course() == null) {
continue;
}
String student = record.student().trim();
String course = record.course().trim();
if (student.isEmpty() || course.isEmpty()) {
continue;
}
courseStudents
.computeIfAbsent(course, key -> new HashSet<>())
.add(student);
}
List<String> result = new ArrayList<>();
for (Map.Entry<String, Set<String>> entry
: courseStudents.entrySet()) {
if (entry.getValue().size() >= limit) {
result.add(entry.getKey());
}
}
result.sort(String::compareTo);
return result;
}
publicstaticvoidmain(String[] args){
List<Enrollment> records = List.of(
new Enrollment("Amy", "Math"),
new Enrollment("Bob", "Math"),
new Enrollment("Cindy", "Math"),
new Enrollment("David", "Math"),
new Enrollment("Eric", "Math"),
new Enrollment("Amy", "Math"),
new Enrollment("Frank", "Java")
);
System.out.println(findPopularCourses(records, 5));
}
}
输出结果:
[Math]
代码里故意放了两处处理。
一处是 HashSet 去重。Amy 的 Math 记录出现了两次,但最后仍然只算一名学生。另一处是把人数限制作为参数传入,没有把数字 5 焊死在判断里。以后业务改成“满 30 人开班”,方法不用重写。
设选课记录数量为 n。每条记录只处理一次,HashMap 和 HashSet 的平均操作复杂度都是 O(1),因此整体时间复杂度为 O(n)。额外空间取决于去重后的选课关系数量,最坏是 O(n)。
如果题目能保证一名学生不会重复选择同一门课,那么 Map 里直接存人数也能做。但我碰到这类分组统计,通常还是会保留去重。多占一点空间,总比数据重复后人数悄悄算错强。
还有最后一个边界:若题面明确要求“超过 5 名”,判断应改成:
if (entry.getValue().size() > limit)
>= 5 和 > 5 只差一个等号,却是这道题最容易丢分的地方。