上海国企的月薪,大家觉得如何?到手15k,年终8万,双边公积金6k
这还问“如何”啊?这不就是来给打工人上眼药的吗。
上海国企,一个月拿到手一万五,年底再来一笔八万奖金,关键是公积金两边加起来还能干到六千。你把这几项摊开算一下,实际含金量真不低了。
很多人一看月薪一万五,可能还想说上海也就那样。但问题是,国企的稳定性、福利、年终、公积金一起算,味道就变了。外面互联网给你开三万,今天优化明天组织调整,晚上睡觉都不踏实。
这岗位最大的离谱点不是工资多夸张,而是它又稳又能存钱。公积金一个月六千,房贷压力直接少一截。年底八万一到,年货还没买,账户先回血。
打工人看完只能沉默:有些班看着不炸裂,但它是真的香。
链表相交这题,最容易写歪的地方不是代码,而是脑子里默认“值相等就算相交”。
不算。
两个链表相交,看的不是节点里的 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,循环也会停。
面试现场我更愿意先写长度差版本,稳定,解释起来不费劲。等对方追问有没有更简洁的写法,再补双指针切换版本。
这种题别背代码,抓住一句话就够了:
两个指针必须站在离尾节点一样远的位置,再一起往后走。