程序员老鬼

上海国企的月薪,大家觉得如何?到手15k,年终8万,双边公积金6k

这还问“如何”啊?这不就是来给打工人上眼药的吗。

上海国企,一个月拿到手一万五,年底再来一笔八万奖金,关键是公积金两边加起来还能干到六千。你把这几项摊开算一下,实际含金量真不低了。

Image

很多人一看月薪一万五,可能还想说上海也就那样。但问题是,国企的稳定性、福利、年终、公积金一起算,味道就变了。外面互联网给你开三万,今天优化明天组织调整,晚上睡觉都不踏实。

这岗位最大的离谱点不是工资多夸张,而是它又稳又能存钱。公积金一个月六千,房贷压力直接少一截。年底八万一到,年货还没买,账户先回血。

打工人看完只能沉默:有些班看着不炸裂,但它是真的香。

今日面试题

链表相交这题,最容易写歪的地方不是代码,而是脑子里默认“值相等就算相交”。

不算。

两个链表相交,看的不是节点里的 value,是不是同一个节点对象。

比如下面这种:

A: 4 -> 1 \
          8 -> 4 -> 5
B: 5 -> 6 -> 1 /

A 里的 1 和 B 里的 1,值一样,但不是同一个节点。真正相交的是后面的 8,因为从这个节点开始,后面的链条被两个链表共用了。

我看到这题,第一反应不会去搞什么 HashSet。能做,但有点粗。面试里问这个题,八成就是想看你能不能把两个链表的长度差处理干净。

链表一长一短,如果直接一起往后走,肯定对不齐。要先让长链表多走几步,把两个指针对到“离尾巴一样远”的位置。

然后一起走,第一次遇到同一个节点,就是交点。

Java 代码我一般这么写,不绕:

publicclassLinkHit{

staticclassNode{
int val;
        Node next;

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

public Node findJoin(Node left, Node right){
if (left == null || right == null) {
returnnull;
        }

int leftLen = count(left);
int rightLen = count(right);

        Node longSide = leftLen >= rightLen ? left : right;
        Node shortSide = leftLen >= rightLen ? right : left;

int gap = Math.abs(leftLen - rightLen);
while (gap-- > 0) {
            longSide = longSide.next;
        }

while (longSide != null && shortSide != null) {
if (longSide == shortSide) {
return longSide;
            }

            longSide = longSide.next;
            shortSide = shortSide.next;
        }

returnnull;
    }

privateintcount(Node head){
int n = 0;
        Node p = head;
while (p != null) {
            n++;
            p = p.next;
        }
return n;
    }
}

这里有个细节要盯住:

if (longSide == shortSide)

不能写成:

if (longSide.val == shortSide.val)

这个坑太常见了。链表相交不是“数据重复”,是“引用重合”。线上排对象引用问题也是这个味道,别一看到字段一样就认亲,得看是不是同一个东西。

这段代码扫了三遍链表。

第一遍算 A 长度,第二遍算 B 长度,第三遍一起找交点。时间复杂度是 O(m + n),额外空间是 O(1)。

还有一种双指针写法更短:

public Node findJoinBySwitch(Node a, Node b){
    Node x = a;
    Node y = b;

while (x != y) {
        x = x == null ? b : x.next;
        y = y == null ? a : y.next;
    }

return x;
}

这段代码看着有点玄,其实就是让两个指针都走完 A + B 的长度。

A 指针走完自己的链表,就去走 B。 B 指针走完自己的链表,就去走 A。

如果有交点,它们会在交点碰上。 如果没有交点,最后一起变成 null,循环也会停。

面试现场我更愿意先写长度差版本,稳定,解释起来不费劲。等对方追问有没有更简洁的写法,再补双指针切换版本。

这种题别背代码,抓住一句话就够了:

两个指针必须站在离尾节点一样远的位置,再一起往后走。