Python技术迷

同事被炒鱿鱼了,结果人家动作快得跟闪电似的,东西一会儿就收拾走了,工作群退,联系人一删,干净利落

真给我看乐了。

同事上午刚被通知不用来了,结果人家一点没拖泥带水。电脑关了,杯子拿走,抽屉清空,工作群退掉,微信该删的删,一套动作下来比公司走流程还快。

最搞笑的是中午领导还想找他问点事,翻半天发现人没了,聊天框也没了,自己还躺在删除名单里。那一刻领导估计也懵:不是,我还没发完最后一波指令呢?

Image

但说真的,这事还挺打工人的。平时公司讲效率,裁人的时候也挺效率,那人家离场效率高一点,也没啥毛病。都被炒了,还指望人家继续在线待命,随叫随到,顺便保持体面?

成年人职场就是这样,关系到点就断。别谈什么情怀,工资结清,东西带走,江湖不见。

算法题:统计特殊四元组

四层 for 一写出来,这题基本就没味了。

不是不能过,n 小的时候确实能混过去。但面试或者刷题时,我一般不太信这种写法。因为题目叫“统计特殊四元组”,真正要看的不是你会不会枚举,而是你能不能把等式拆开。

题目要求找这样的下标:

i < j < k < l
nums[i] + nums[j] + nums[k] == nums[l]

第一眼看,四个下标都要管,很烦。

但这个式子稍微挪一下:

nums[i] + nums[j] == nums[l] - nums[k]

这地方就能下手了。

左边是前面的两个数之和,右边是后面的两个数之差。只要保证下标顺序没乱,统计次数就行。

最笨的写法大概是这样:

defcount_quadruplets(nums):
    n = len(nums)
    ans = 0

for i in range(n):
for j in range(i + 1, n):
for k in range(j + 1, n):
for l in range(k + 1, n):
if nums[i] + nums[j] + nums[k] == nums[l]:
                        ans += 1

return ans

这段代码没毛病,就是太直。四层循环一套,时间复杂度 O(n^4)。数据一大就开始难看。

我更愿意从右往左扫 j。

为什么扫 j?

因为一旦固定了 j,左边只需要枚举 i < j,右边的 k、l 可以提前放到哈希表里。

哈希表里存什么?

存:

nums[l] - nums[k]

也就是右边能凑出来的差值出现了几次。

代码可以这样写:

from collections import defaultdict

defcount_quadruplets(nums):
    n = len(nums)
    right_diff = defaultdict(int)
    total = 0

# j 至少从 n - 3 开始,后面要留 k 和 l
for j in range(n - 3, 0, -1):
        k = j + 1

# 把当前 k 和它后面的 l 组成差值,丢进右侧统计表
for l in range(k + 1, n):
            right_diff[nums[l] - nums[k]] += 1

# 再枚举左边的 i,看 nums[i] + nums[j] 有没有出现过
for i in range(j):
            need = nums[i] + nums[j]
            total += right_diff[need]

return total

这段代码最容易看错的地方在这里:

k = j + 1

每次 j 往左挪一格,就把新的 k 加进右侧哈希表。

这样哈希表里维护的永远是:

j < k < l

左边枚举的是:

i < j

两边一合,顺序自然就是:

i < j < k < l

不需要额外判断下标。

拿个数组过一下:

nums = [1, 2, 3, 6]

当 j = 1 时,左边有 i = 0,右边有 k = 2, l = 3。

右边差值是:

6 - 3 = 3

左边和值是:

1 + 2 = 3

对上了,答案加 1。

这题如果只写暴力,像是在验题;用哈希拆等式,才像是在解题。

复杂度从 O(n^4) 压到 O(n^2),空间复杂度是 O(n^2) 级别,存的是右侧差值次数。实际代码不长,关键是别把哈希表维护早了或者晚了,下标顺序一乱,答案就会多算。