Python技术迷

被裁了!刚刚谈完话 有两个选择,怎么选?

刚刷到这个帖子,我第一反应是:这 HR 话术还挺熟。

人刚被裁,谈完话就丢两个选项过来。一个是你人还挂着,按点来按点走,月底再走,中间自己找工作。另一个是直接拿 N+1,钱多一点,但离职证明上会写清楚是被裁。

Image

HR 还说之前大家都选第一个,意思差不多就是:你也别搞特殊,离职证明好看点。听着像为你好,其实打工人都懂,最关键的还是钱和下一份工作怎么衔接。

现在这环境,被裁真不是什么见不得人的事。公司缩编、业务砍线、预算没了,这些面试里一说,正常公司也能听懂。反倒是少拿两个月工资,只为了一个“看起来体面”的说法,我觉得有点亏。

我会倾向选 2。钱先拿到手,别被一句“以前大家都这么选”带跑。离职证明这东西重要,但也没重要到值两个月工资吧。

今日算法题

链表相交,不是节点值一样就算相交

链表相交这题,最容易写错的地方不是算法,而是把“值相等”当成“节点相等”。

比如两个链表里都有一个 8,这不代表它们相交。真正的相交,是后面那一截链表共用了同一批节点。换句话说,判断的不是 node.val,而是两个指针是不是指向同一个对象。

这地方我一般先画两条链表:

A: 4 -> 1 -> 8 -> 4 -> 5
              ↑
B:     6 -> 1 ┘

从 8 开始,后面的 8 -> 4 -> 5 是同一段节点,不是长得一样的两段。

最笨的写法也能做:把 A 链表所有节点丢进一个集合,再扫 B 链表,扫到第一个已经出现过的节点,就说明相交了。

代码大概这样:

deffind_join_by_seen(head_a, head_b):
    seen = set()

    cur = head_a
while cur:
        seen.add(cur)
        cur = cur.next

    cur = head_b
while cur:
if cur in seen:
return cur
        cur = cur.next

returnNone

这写法没毛病,排查线上链路时我也愿意这么写,直观,不容易错。缺点也明显,多用了一个集合,空间复杂度是 O(n)。

面试题一般不想让你这么轻松过,它多半会追问:不用额外空间行不行?

可以。

这个题的关键不是“谁先走到交点”,而是让两个指针走过的总路程一样。

假设 A 链表长一点,B 链表短一点。两个指针同时走,A 走到头以后切到 B,B 走到头以后切到 A。这样一来,它们都走了 A长度 + B长度。如果有交点,第二轮一定会在交点撞上;如果没有交点,最后都会变成 None。

这块别想太玄,代码反而很短:

classListNode:
def__init__(self, val=0):
        self.val = val
        self.next = None


defget_intersection_node(head_a, head_b):
if head_a isNoneor head_b isNone:
returnNone

    p = head_a
    q = head_b

while p isnot q:
        p = p.next if p else head_b
        q = q.next if q else head_a

return p

注意这里我用的是:

while p isnot q:

不是:

while p.val != q.val:

这个差别很要命。

is 判断的是不是同一个节点对象,val 只能说明值一样。链表题里,只要题目说“相交”,十有八九判断的都是节点引用。

再看两个边界情况。

一个是根本不相交:

A: 1 -> 2 -> 3
B: 4 -> 5

两个指针来回切一次以后,最后都会走到 None,循环停掉,返回 None。

另一个是一上来就相交:

A: 7 -> 9
B: 7 -> 9

如果 head_a 和 head_b 本来就是同一个节点,第一次判断 p is q 就成立,直接返回头节点。

这题我不建议上来就背公式。先记住一句话:两个人各走一遍对方的路,路程就被抹平了。

长链表多出来的那一截,会在切换链表后被短链表指针补回来。等长度差被抵消以后,如果后面真共用一段节点,它们自然会碰到。

这题代码短,但坑不小。尤其是 Python 里,== 可能被类重写,写链表引用判断时,我更愿意用 is。这不是洁癖,是少给自己埋一个看不见的雷。