Python技术迷

领导,请停止对我的侵犯!

我在网上看到个吐槽帖,开头就很顶:“领导,请停止对我的侵犯。”点进去一看,原来是晚上10点突然拉人开复盘会。

Image

有网友说得很直接:这哪是复盘,这是夜间突袭。还有人补刀:白天不开,非挑大家准备洗脸睡觉的时候,领导是把复盘当宵夜了。

我真觉得,员工反感的从来不是工作本身,是边界感被踩得嘎嘎响。复盘当然该做,成长也确实重要,可你总不能拿“负责”两个字,把别人的生活整个打包带走。成年人上班,是为了挣口饭吃,不是24小时待命当人形充电宝。

算法题:水壶问题

前几天刷题,看到一道老题:给两个容量分别为 x 和 y 的水壶,水无限,问能不能量出恰好 target 升水。

这题看着像小学奥数,真写起来,很多人会卡在两个地方: 一个是不知道怎么把“倒水”这件事抽象成程序;另一个是代码能跑,但自己也说不清为什么对。

先别急着上公式,我更喜欢先把它当成一个状态搜索题。

假设现在有两个壶,当前水量分别是 (a, b),那下一步能做的动作其实就这么几种:

# 1. 装满A
(a, b) -> (x, b)

# 2. 装满B
(a, b) -> (a, y)

# 3. 倒空A
(a, b) -> (0, b)

# 4. 倒空B
(a, b) -> (a, 0)

还有最关键的两步,互相倒水:

# A 倒给 B
move = min(a, y - b)
(a, b) -> (a - move, b + move)

# B 倒给 A
move = min(b, x - a)
(a, b) -> (a + move, b - move)

这样题目就清楚了: 从 (0, 0) 出发,看能不能走到某个状态,让 a == target,或者 b == target,或者 a + b == target。

这时候用 BFS 或 DFS 都能做。我平时更愿意写 BFS,状态一层层扩出去,不容易绕晕。

from collections import deque

defcan_measure_water(x: int, y: int, target: int) -> bool:
if target > x + y:
returnFalse
if target == 0:
returnTrue

    q = deque([(0, 0)])
    seen = {(0, 0)}

while q:
        a, b = q.popleft()
if a == target or b == target or a + b == target:
returnTrue

        nxt = []

        nxt.append((x, b))
        nxt.append((a, y))
        nxt.append((0, b))
        nxt.append((a, 0))

        move = min(a, y - b)
        nxt.append((a - move, b + move))

        move = min(b, x - a)
        nxt.append((a + move, b - move))

for state in nxt:
if state notin seen:
                seen.add(state)
                q.append(state)

returnFalse

比如 x = 3, y = 5, target = 4。 搜索路径里会出现这样一段:

(0, 0)
-> (0, 5)
-> (3, 2)
-> (0, 2)
-> (2, 0)
-> (2, 5)
-> (3, 4)

到 (3, 4) 的时候,第二个壶里正好是 4 升,答案就是 True。

不过这题还有个更像“面试官想听的答案”。

真正决定能不能凑出来的,不是搜索写得漂不漂亮,而是数学条件:target 必须不大于 x + y,并且 target 必须是 gcd(x, y) 的倍数。

代码能短很多:

import math

defcan_measure_water_math(x: int, y: int, target: int) -> bool:
if target > x + y:
returnFalse
if target == 0:
returnTrue
return target % math.gcd(x, y) == 0

这段代码短到有点不像题解,但它背后的意思很硬: 两个水壶反复装满、倒空、互倒,本质上只能拼出 gcd(x, y) 的倍数水量。

所以这题有两个解法思路:

一个适合你自己把过程想明白,拿状态搜索去推,代码也直观。 另一个适合面试里收尾,直接落到最大公约数。

真到面试现场,我一般会这么答:先说状态怎么建,再补一句这个题还能用 gcd 优化。这样既不像只会背结论,也不会显得只会暴力搜索。