跟一个年薪100万的技术总监吃饭,聊到年底绩效评级,他说决定谁拿A+、谁升职,从来不看这人加了多少班,只看这人的“静音能力”。
刚看到个贴子,说网友跟一个年薪百万的技术总监吃饭,聊到年底绩效。那位总监说,谁拿A+、谁升职,他不看谁加班多,就看一个指标:静音能力,听完确实有点背凉。
网友回帖大概两派:一派骂这是要求员工“闭嘴干活、少提要求”;另一派觉得,情绪稳定、少抱怨,本来就是职场稀缺能力。
我觉得这事吧,关键在于怎么理解“静音”。如果是被压榨也不能吭声,那就是PUA;但如果指的是,遇事不先甩情绪、先把问题搞定,再有理有据地反馈,那就是成熟。
静音能力应该是“情绪自控+高效做事”,而不是“闭嘴忍耐”。一边把事做好,一边少发无效牢骚、敢提有效诉求,这样的静音,才不会把自己静成背景板。
算法题:最大间距
说这个题之前,先给你画个小画面啊:
某天晚上快下班,你 leader 突然甩过来一句——“有个最大间距你写一下,时间复杂度要 O(n) 哦”,然后人就没影了。你一搜发现,排序一把梭就能做,可是 O(n log n) 又不达标,是不是有点烦。
什么是“最大间距”
题意一般是这样的(经典 LeetCode 那个):
给你一个无序的数组 nums,你把它升序排序之后,看看相邻两个数之间的差值,这些差值里最大的那个,就是“最大间距”。
比如:
nums = [3, 6, 9, 1]排序后是 [1, 3, 6, 9]间距是: 3-1=2, 6-3=3, 9-6=3最大间距 = 3
要求:
时间复杂度 **尽量 O(n)**(理想情况) 不能直接用 sort 当答案(面试官会嫌弃)
当然,如果你在刷题平台上,写个排序版通过一下没问题,先来个最朴素的写法热热身。
先来个“老实人”解法:排序搞定
思路就一句话:
先排序 再扫一遍,记录相邻差值最大值
Python 写起来非常顺手:
defmaximum_gap_sort(nums):
if len(nums) < 2:
return0
nums.sort()
ans = 0
for i in range(1, len(nums)):
ans = max(ans, nums[i] - nums[i - 1])
return ans
这个没啥可说的,逻辑很直白,时间复杂度 O(n log n),面试要是没特别卡复杂度,这个都够用。
但题目既然点名了 O(n),那就得上点“技巧活”了。
为啥可以做到 O(n)?——桶的直觉
关键有个抽屉原理的小结论:
假设数组长度是 n,最小值是min_v,最大值是max_v把这 n个数排好序以后,一共会有n - 1个间距整体跨度是 max_v - min_v那么至少有一个间距,大于等于:
[ \text{gap_min} = \lceil \frac{\text{max_v} - \text{min_v}}{n - 1} \rceil ]
直白点说:你把 [min, max] 这一整段区间均匀切成 n-1 小段,真实的数据不可能所有间距都比这“平均值”还小,总有一个≥它。
有了这个“理论下限”之后,我们就可以干一件事:
与其真的把所有数排好序,不如把区间切成若干“桶”, 每个桶只记录:这一段里出现过的最小值和最大值。
为啥只存桶内的 min / max 就够?
真正的“最大间距”,不会发生在同一个桶里面(因为桶大小是按上面的最小间距设计的)
只会发生在相邻非空桶之间:
后一个桶的最小值 减去前一个桶的最大值
这样我们就不用真的排序,只是在桶之间跳着看,就能找出最大间距。
把桶法拆开说一下步骤
来,稍微系统一点说(但我尽量不搞得太教科书):
特判:如果
len(nums) < 2,答案直接是 0,没间距可算。扫一遍数组,求出
min_v和max_v。
如果 min_v == max_v,说明所有数都一样,最大间距也是 0。
算一个合理的桶大小:
import math
bucket_size = math.ceil((max_v - min_v) / (len(nums) - 1))
算桶的个数:
bucket_count = (max_v - min_v) // bucket_size + 1
为每个桶准备两个数组:
bucket_min[i]:第 i 个桶目前看到的最小值bucket_max[i]:第 i 个桶目前看到的最大值 以及一个bucket_used[i]记这个桶有没有被用过。
再扫一遍数组,把每个数放进对应桶:
桶编号: idx = (num - min_v) // bucket_size更新这个桶的 min/max。
最后一次遍历所有桶:
当前桶最小值减前一个桶最大值 = 一个候选间距 不断更新答案
用一个变量
prev_max记录上一个非空桶的最大值对每个非空桶:
注意几个小坑:
min_v和max_v自己也会被放进桶,不需要特判扔掉一定要跳过空桶 桶大小算的时候要用天花板(向上取整),不然可能漏解
直接上完整代码,你可以对着上面的步骤看:
import math
from typing import List
defmaximum_gap(nums: List[int]) -> int:
n = len(nums)
if n < 2:
return0
min_v = min(nums)
max_v = max(nums)
if min_v == max_v:
return0
# 1. 计算桶大小和桶数量
bucket_size = math.ceil((max_v - min_v) / (n - 1))
bucket_count = (max_v - min_v) // bucket_size + 1
# 2. 初始化桶
bucket_min = [None] * bucket_count
bucket_max = [None] * bucket_count
bucket_used = [False] * bucket_count
# 3. 把每个数丢进桶里
for num in nums:
idx = (num - min_v) // bucket_size
ifnot bucket_used[idx]:
bucket_min[idx] = num
bucket_max[idx] = num
bucket_used[idx] = True
else:
if num < bucket_min[idx]:
bucket_min[idx] = num
if num > bucket_max[idx]:
bucket_max[idx] = num
# 4. 扫桶,找最大间距
prev_max = None
ans = 0
for i in range(bucket_count):
ifnot bucket_used[i]:
continue
if prev_max isnotNone:
ans = max(ans, bucket_min[i] - prev_max)
prev_max = bucket_max[i]
return ans
这个解法的几个点你可以顺便记一下:
时间复杂度:
找 min/max 一遍 分桶一遍 扫桶一遍 总体就是 O(n)空间复杂度:
bucket_count大致也是O(n)级别
如果真的在面试里,你可以先写排序版的,保证先 AC; 面试官要你优化,再把上面这套桶的思路慢慢说出来,一步步改代码。
差不多就这样,我去喝口水,你有别的算法题也可以丢过来一起整。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB