Python技术迷

如果遇到裁员,切记不要傻乎乎签字拿n加 1,和公司谈,可以拿到n加 3

这话听着爽,但真别照着无脑冲。

裁员这事,很多人一听到“N+1”就慌了,HR把纸往面前一推,脑子一热就签了。签完回家才发现,同组有人多谈了两个月,血压当场上来。

Image

但网上说什么“死赖着不走就能N+3”,也别太当真。公司不是傻子,你手里有没有筹码,得看岗位、合同、绩效、裁员流程合不合规,还有公司急不急着把名额清掉。

能谈是真的,别秒签也是真的。至少先把补偿、离职日期、社保、公积金、年假、期权这些问清楚。该录音录音,该留邮件留邮件。别一上来就拍桌子,也别被HR两句话吓住。

打工人最怕的不是被裁,是稀里糊涂把自己卖便宜了。

算法题:一手顺子

hand = [1,2,3,6,2,3,4,7,8],groupSize = 3。

这牌能不能拆成顺子?

一眼看过去像是:

1 2 3
2 3 4
6 7 8

可以。

但我见过不少人写这题,第一反应是把数组排序,然后每次从里面抠一段连续的。这个写法不是不能做,就是代码会很别扭,删元素还容易把复杂度搞上去。

这种题我一般不真的“移动牌”,只记每张牌还剩几张。

比如这把牌统计后是:

1:1
2:2
3:2
4:1
6:1
7:1
8:1

关键点在最小的牌。

如果当前最小还没用完,比如 1 还剩 1 张,那它没得选,只能作为某个顺子的开头。因为没有 0、-1 能把它接进去。

所以看到 1,就必须拿走:

1 2 3

然后 2 和 3 的数量各减 1。

继续看下一个还没用完的最小牌,变成 2,那就必须拿:

2 3 4

再往后就是 6 7 8。

这个贪心很硬,不是拍脑袋。小牌如果不先处理,后面一定没人救它。

代码我会这么写:

from collections import Counter

defis_straight_hand(hand, group_size):
if len(hand) % group_size != 0:
returnFalse

    left = Counter(hand)

for start in sorted(left):
        need = left[start]
if need == 0:
continue

for card in range(start, start + group_size):
if left[card] < need:
returnFalse
            left[card] -= need

returnTrue

这里有个地方容易写错。

不是每次只减 1,而是减 need。

比如:

hand = [1,1,2,2,3,3]
groupSize = 3

1 有两张,那就说明必须开两组:

1 2 3
1 2 3

如果你每次只减一张,代码也许能跑过一些样例,但碰到重复牌多的用例,就开始写一堆 while 补救。补救越多,越像没想清楚。

再看一个会失败的:

print(is_straight_hand([1,2,3,4,5], 4))

长度都不能被 4 整除,直接返回 False。这个判断要放最前面,别后面排了半天才发现组不起来。

再比如:

print(is_straight_hand([1,2,3,4,6,7,8,9], 4))

它能拆:

1 2 3 4
6 7 8 9

返回 True。

这题真正要抓住的是一句话:当前最小的剩余牌,只能当顺子的开头。

只要这个判断站得住,后面的代码就很短。

时间复杂度主要花在排序上,O(n log n)。计数表遍历时,每张牌最多被处理到固定长度范围里,整体不会太离谱。

别用列表反复 remove。那东西写起来像在模拟打牌,跑起来像在拖地。