部门有个同事,被架空了。 领导不给他派活,开会不叫他,邮件不抄送他
最狠的裁员,真不一定是直接开人,是把你晾那儿。
活不给,会不开,邮件也不带你,工位还给你留着,像公司供了个吉祥物。人每天按点来,电脑一开,连装忙都没素材,这种班上久了,正常人都会怀疑是不是自己空气化了。
评论区有人说这叫“软劝退”,还有人说“比骂你两句都阴”,我看都算轻的。
明面上公司啥都没干,工资照发,流程合规,实际上刀早就下来了。很多人扛不到被辞,先被那种冷处理磨没劲了。最损的地方就在这儿:它不跟你撕破脸,它让你自己怀疑、自己难受、自己递辞职
算法题:最小窗口子序列
不是所有带“窗口”两个字的题,都能把左右指针一推就完事。
“最小窗口子串”很多人刷顺手了,看到“最小窗口子序列”也想照抄模板,结果一写就歪。因为这题最别扭的地方在于:窗口内部不要求连续,但匹配顺序不能乱。这一下,普通滑动窗口那套“够了就缩,不够就扩”就不太灵了。
题目大意很简单:给你两个字符串 s1 和 s2,要在 s1 里找一个最短连续子串,使得 s2 是这个子串的子序列。
比如:
s1 = "abcdebdde"
s2 = "bde"
答案是 "bcde",不是 "bdde"。后者也能匹配,但更长。
我一般看到这题,第一反应不是上 DP,而是先顺着字符串往前扫,看看能不能先找到一个完整匹配,再想办法回头把窗口缩到最小。这个思路更像线上排查:先确认问题能复现,再做收缩。
代码可以这样写:
defmin_window_subsequence(s1: str, s2: str) -> str:
n, m = len(s1), len(s2)
best_start = -1
best_len = float('inf')
i = 0
while i < n:
if s1[i] != s2[0]:
i += 1
continue
# 先向前找,确认能不能完整覆盖 s2
j, k = i, 0
while j < n and k < m:
if s1[j] == s2[k]:
k += 1
j += 1
if k < m:
break
# 再反向收缩,把窗口压到最小
end = j - 1
k = m - 1
j = end
while k >= 0:
if s1[j] == s2[k]:
k -= 1
j -= 1
start = j + 1
if end - start + 1 < best_len:
best_len = end - start + 1
best_start = start
i = start + 1
return""if best_start == -1else s1[best_start:best_start + best_len]
这段代码的味道其实很明显:正向找终点,反向抠起点。
为什么要反向收缩?因为你第一次找到的窗口,通常只是“能用”,不一定最短。像排 SQL 一样,先看到“能跑”,不代表执行计划已经对了,还得继续抠。
拿 "abcdebdde" 和 "bde" 走一遍:
正向扫到 b 开始,往后能匹配出 b -> d -> e,先拿到一个窗口。 然后从结尾那个 e 往回倒着找,先找 e,再找 d,再找 b,这样才能把左边界卡到最小。 最后得到 "bcde"。
这题时间复杂度不是特别漂亮,最坏接近 O(n * m) 到 O(n^2) 之间,取决于字符分布。但面试里这个解法是够用的,思路也比硬背 DP 更好讲。
当然,真要继续抠性能,可以上 DP,记录 s2 每个位置在 s1 里匹配后的起点。那写法更规整,但也更容易写出一坨自己都不想复盘的代码。
所以这题我更建议先把这个版本吃透。它不花,甚至有点笨,但判断路径是对的: 先匹配,再收缩。 别一上来就把“子串”和“子序列”混成一锅。 这题坑就坑在这。