程序员老鬼

擦,这是真牛马呀,某老板:工资5到6千,不是5千到6千

刚刷到这个,直接给我看笑了,这老板玩文字游戏是真有一套。

网友说工资5到6千,听着像区间,结果老板出来一句:不是5千到6千,是‘5到6千’,但实际核实工资3000,顺带补一句入职就说过了。 

Image

这事最骚的是,一个标点差不多能改成两个世界,一个以为是区间,一个是精确到‘最低保障都没有’的版本,打工人还得自己领悟语义学。评论区已经开始对‘5到6千’做语文阅读理解了。最离谱的是老板还觉得自己解释得很清楚。打工人:嗯,好,学会了,以后要学会读‘老板语法’。

这波属于合同前的语言艺术课。看完沉默。

今日面试题

链表翻转这题,最容易写出一个“看着对、跑起来断链”的版本。

尤其是这句:

cur.next = pre;

你只要在它前面没把下一个节点存住,后面的链表就没了。不是慢,也不是边界问题,是直接把路掐断。

比如原链表是:

1 -> 2 -> 3 -> 4 -> null

翻完之后要变成:

4 -> 3 -> 2 -> 1 -> null

这题我一般不先想什么递归,不划复杂图。就盯住三个指针:

pre:已经翻好的那一段
cur:当前正在处理的节点
next:先把后面的路记下来

关键代码就这么几行:

classNode{
int val;
    Node next;

    Node(int val) {
this.val = val;
    }
}

publicclassLinkReverse{

public Node reverse(Node head){
        Node pre = null;
        Node cur = head;

while (cur != null) {
            Node next = cur.next;  // 先把后面的节点留住,不然后面就断了
            cur.next = pre;        // 当前节点回头指
            pre = cur;             // 已翻转链表往前挪
            cur = next;            // 继续处理原链表后面的节点
        }

return pre;
    }
}

这段代码里面最不能省的是 next。

有些人第一次写会这样:

cur.next = pre;
cur = cur.next;

这代码我第一眼就不太信。因为 cur.next 已经被你改成 pre 了,这时候再往下走,走的不是原链表后面的节点,而是已经翻过的那段。轻则死循环,重则结果乱掉。

可以拿三个节点手算一下。

刚开始:

pre = null
cur = 1

第一次循环:

next = 2
1.next = null
pre = 1
cur = 2

此时链表被拆成了两段:

1 -> null
2 -> 3 -> 4 -> null

第二次循环:

next = 3
2.next = 1
pre = 2
cur = 3

变成:

2 -> 1 -> null
3 -> 4 -> null

一直这么挪,最后 cur 走到 null,说明原链表处理完了。这个时候 pre 正好站在新链表的头节点,也就是 4。

边界也顺手过一下。

空链表:

reverse(null);

不会进 while,直接返回 null。

只有一个节点:

7 -> null

循环一次,7.next 指向 null,返回 7,也没问题。

这题还有递归写法,但我平时面试或者写业务工具代码,优先写迭代。原因很简单,指针变化都摆在眼前,不靠调用栈猜。

递归版也可以写:

public Node reverseByCall(Node head){
if (head == null || head.next == null) {
return head;
    }

    Node newHead = reverseByCall(head.next);
    head.next.next = head;
    head.next = null;

return newHead;
}

递归这段最绕的是:

head.next.next = head;

它的意思不是“当前节点指向下一个”,而是让下一个节点反过来指向当前节点。

比如递归已经把:

2 -> 3 -> 4

翻成了:

4 -> 3 -> 2

这时候当前 head 是 1,只需要让 2 指回 1:

head.next.next = head;

再把 1 的 next 断掉:

head.next = null;

不然 1 和 2 会互相指,链表直接绕圈。

所以翻转链表这题,别背代码。就记一件事:改指针之前,先保存现场。链表题大部分 bug,不是算法多难,是你把后路改没了。