领导的嫡系捅了个大篓子,出了严重bug,甲方追着要人背锅。领导找我谈话,说综合考虑之后决定让我来顶这个锅。
这领导算盘珠子都崩我脸上了。
嫡系捅了大篓子,严重 bug 出来,甲方开始追责,领导不去查谁写的、谁评审的、谁上线的,转头找一个没参与过需求的人谈话,说什么“综合考虑”,决定让你来背。
这哪叫综合考虑啊,这叫挑软柿子。
这种事千万别一上头就拍桌子,也别傻乎乎点头。先把边界划清楚:这个需求什么时候立项、谁开发、谁测试、谁上线、你有没有参与记录,全部拉出来。聊天记录、邮件、工单、代码提交,能留的都留。
领导私下让你认,你就别私下认。让他走正式流程,让他说清楚依据。真要你签字、写说明,更要谨慎,别写成“我负责”。可以配合排查问题,但背锅是另一回事。
帮忙可以,救火也行,但没干过的事,别认。领导脸面重要,你饭碗也不是纸糊的。
数组明明只乱了一小段,结果有人上来就把整个数组排一遍。
能过。
但我第一眼不太喜欢这个写法。因为这题问的是“最短无序连续子数组”,不是问你“排完以后长什么样”。排序再对比,等于把现场全推平了,再回头找事故范围。
题目大概是这样:
nums = [2, 6, 4, 8, 10, 9, 15]
只要把中间这段:
[6, 4, 8, 10, 9]
排好,整个数组就有序了,所以答案是 5。
这题真正要抓的东西,其实是两个边界。
左边界怎么来?
从左往右扫,正常递增数组里,当前值应该不小于前面见过的最大值。
一旦出现:
nums[i] < max_seen
说明当前位置这个数,被前面某个更大的数“压住”了,它肯定落在无序区间里。
比如扫到 4 的时候,前面最大值是 6,4 < 6,这里就不对劲。
再扫到 9 的时候,前面最大值已经是 10,9 < 10,这里也不对劲。
所以右边界会不断往后推。
右边界知道了,左边界反过来找。
从右往左扫,正常递增数组里,当前值应该不大于右边见过的最小值。
一旦出现:
nums[i] > min_seen
说明当前位置这个数太大了,挡住了右边更小的数,它也得进无序区间。
代码我一般会这么写,不花里胡哨:
defshortest_unsorted_part(nums: list[int]) -> int:
n = len(nums)
if n < 2:
return0
right = -1
max_seen = nums[0]
for i in range(1, n):
if nums[i] < max_seen:
right = i
else:
max_seen = nums[i]
if right == -1:
return0
left = 0
min_seen = nums[-1]
for i in range(n - 2, -1, -1):
if nums[i] > min_seen:
left = i
else:
min_seen = nums[i]
return right - left + 1
拿刚才那个数组跑一下:
nums = [2, 6, 4, 8, 10, 9, 15]
print(shortest_unsorted_part(nums))
输出:
5
这里有个小坑,别把边界判断写反。
从左往右扫,不是遇到下降就结束。因为后面可能还有更远的位置也被前面的最大值影响。
看这个数组:
[1, 3, 5, 4, 2, 6]
你看到 4 < 5,右边界先到 3。
但继续扫到 2,它也小于前面的最大值 5,所以右边界还得往后挪到 4。
这就是为什么代码里不是 break,而是继续扫完整个数组。
反方向也一样。
nums = [1, 3, 5, 4, 2, 6]
print(shortest_unsorted_part(nums)) # 4
需要排序的是:
[3, 5, 4, 2]
长度就是 4。
这题如果用排序对比,时间复杂度是 O(n log n)。不是不能写,面试里也不会说你错。
但这个双向扫描是 O(n),只用几个变量。更重要的是,它没有绕路。
左扫抓“被前面大数污染的位置”。
右扫抓“挡住后面小数的位置”。
两个边界一合,答案就出来了。数组本来有序时,左扫阶段 right 一直是 -1,直接返回 0,也不用额外补什么特殊逻辑。