Python技术迷

一线城市的年轻人为了省钱,跟陌生人拼好床的帖子,我开始还以为是开玩笑,翻看之下,居然是真的。我真的震惊了!

刚刷到这个帖子,我第一反应就是:这也能拼?

一线城市房租贵,大家合租我能理解,客厅打地铺我都见怪不怪了。结果这次不是拼房,也不是拼卧室,是直接跟陌生人拼一张床。两个人错开时间睡,谁先下班谁先躺,另一个回来再换班,床单被子都不一定分得清。

Image

我一开始还以为是网友编段子,往下翻才发现,人家真这么住。理由也很简单,一个月能省不少钱。

省钱省到这份上,已经不是吃不吃外卖的问题了。打工人白天在公司抢工位,晚上回家还得抢床位,房东看完估计都要研究新户型了:两平米,睡眠共享版。

今日算法题

一道看着像 SQL 的题,用 Python 写其实就是一次计数

数据一进来,目标很明确:找出选课人数不少于 5 人的课程。

原始记录大概长这样:

student    class
A          Math
B          English
C          Math
D          Biology
E          Math
F          Computer
G          Math
H          Math

最后应该留下 Math,因为它刚好有 5 名学生。

这题第一眼看过去,很容易写成“两层循环”:拿出一门课,再把所有记录扫一遍,数有多少学生选了它。数据少的时候没问题,数据一大就有点难看了。

假设一共有 n 条选课记录,课程种类也接近 n,两层循环最差要跑到 O(n²)。这种代码能过小样例,我一般也不会留在项目里。

Python 里直接用字典计数更稳。

deffind_popular_classes(enrollments):
    class_count = {}

for record in enrollments:
        course = record["class"]
        class_count[course] = class_count.get(course, 0) + 1

    result = []
for course, student_total in class_count.items():
if student_total >= 5:
            result.append(course)

return result

测试数据:

records = [
    {"student": "A", "class": "Math"},
    {"student": "B", "class": "English"},
    {"student": "C", "class": "Math"},
    {"student": "D", "class": "Biology"},
    {"student": "E", "class": "Math"},
    {"student": "F", "class": "Computer"},
    {"student": "G", "class": "Math"},
    {"student": "H", "class": "Math"},
]

print(find_popular_classes(records))

输出:

['Math']

这段代码只扫了两遍数据。第一遍统计课程人数,第二遍过滤人数不少于 5 的课程,时间复杂度是 O(n),额外空间取决于课程数量。

不过这里还有个容易被忽略的问题:同一名学生可能重复提交同一门课。

比如数据里出现两条:

{"student": "A", "class": "Math"}
{"student": "A", "class": "Math"}

直接计数会把 A 算两次。题目如果保证记录唯一,前面的写法够用;要是不保证,我会先按“学生加课程”去重,再统计。

deffind_popular_classes(enrollments):
    valid_records = set()

for record in enrollments:
        student = record["student"]
        course = record["class"]
        valid_records.add((student, course))

    class_count = {}

for _, course in valid_records:
        class_count[course] = class_count.get(course, 0) + 1

return [
        course
for course, student_total in class_count.items()
if student_total >= 5
    ]

这里用集合保存 (student, course),相同学生重复选择同一门课,只会保留一份。

题目本身不复杂,真正要判断的是“统计记录数”还是“统计不同学生数”。这两个需求只差一个去重,结果可能完全不一样。

碰到计数题,我一般先确认统计对象,再决定字典的键怎么设计。键选错了,后面写得再漂亮也只是稳定地算错。