Python技术迷

面试了一个某为员工,连归并排序都写不出来会 就一道leetcode中等难度的题都做不出,拜拜吧

有人说自己面了个“某为”员工,结果一道 LeetCode 中等题没做出来,归并排序也写不顺,当场就给判死刑了:拜拜吧。

我看完倒不是替谁洗,算法不会当然会扣分,面试嘛,你考啥人家就得接啥。但把“某为员工”四个字拎出来嘲,就有点意思了。大厂员工也不是统一流水线下来的,每个人做的东西不一样。有的人天天写业务、有的人搞工程落地、有的人可能几年都碰不到手撕排序。

Image

更关键的是,面试考算法没问题,但别考完一道题就觉得自己看穿人家全部水平。真干活的时候,能不能定位问题、拆需求、扛线上事故、跟一堆乱七八糟的人沟通,这些也挺要命的。

当然了,归并排序都写不出来,确实尴尬。

今日算法题

员工薪水表一查,最容易写歪的地方不是累加,是“最新月份不要算”。

这题我第一眼会先盯两个点: 每个员工单独算; 每个员工最后一个月要排除掉。

数据大概长这样:

# id, month, salary
rows = [
    (1, 1, 20),
    (1, 2, 30),
    (1, 3, 40),
    (1, 4, 60),
    (2, 1, 15),
    (2, 2, 25),
    (2, 4, 35),
]

要查的是每个员工最近三个月的累计薪水,但这里的“最近三个月”不是全公司最近三个月,而是站在员工每一条记录的 month 往前看三个月。

比如员工 1 的 4 月是最新月份,不能输出。 3 月要算 1、2、3 月:20 + 30 + 40 = 90。 2 月算 1、2 月:50。 1 月算自己:20。

这种题不要上来就双重循环。数据一多,写得很热闹,跑得很难看。

我一般会先按员工分组,再在每个员工内部按月份排序,用一个小窗口往前滑。窗口里只保留当前月份往前数 2 个月的数据。

from collections import defaultdict, deque

defquery_cumulative_salary(records):
    emp_months = defaultdict(list)

for emp_id, month, salary in records:
        emp_months[emp_id].append((month, salary))

    ans = []

for emp_id, items in emp_months.items():
        items.sort(key=lambda x: x[0])

        last_month = items[-1][0]
        window = deque()
        window_sum = 0

for month, salary in items:
            window.append((month, salary))
            window_sum += salary

while window and window[0][0] < month - 2:
                _, old_salary = window.popleft()
                window_sum -= old_salary

if month == last_month:
continue

            ans.append((emp_id, month, window_sum))

    ans.sort(key=lambda x: (x[0], -x[1]))
return ans

跑一下:

print(query_cumulative_salary(rows))

输出:

[
    (1, 3, 90),
    (1, 2, 50),
    (1, 1, 20),
    (2, 2, 40),
    (2, 1, 15)
]

这里有个坑,员工 2 没有 3 月记录,4 月又是他的最新月份,所以 4 月不输出。2 月只累加 1 月和 2 月,不要脑补一个不存在的 3 月。

窗口这段是关键:

while window and window[0][0] < month - 2:
    _, old_salary = window.popleft()
    window_sum -= old_salary

当前是 5 月,就只允许窗口里有 3、4、5 月。2 月的数据必须弹出去。 当前是 2 月,就允许 0、1、2 月,实际只有 1、2 月,那就算已有的。

这题如果放到数据库里,很多人会用自连接或者窗口函数。用 Python 写的时候,思路其实一样:先把数据按员工隔离,再按月份推进,不要让不同员工的数据串进一个窗口。

最后复杂度也比较干净。每条记录进窗口一次、出窗口一次,排序之外就是线性扫描。比那种“每一条都回头扫三个月”的写法稳得多。