某东员工:干了一年,几乎天天10点下班,年底给了个B+,以为会涨薪,结果一分没有,从此以后早点走,!
某东有员工说,自己这一年基本没怎么准点走过,晚上十点下班都快成默认设置了。人嘛,一开始还挺天真,觉得我这么扛,年底怎么也得有点表示吧。
结果绩效出来,B+。
他还以为涨薪稳了,结果一问,好家伙,一分钱没动。那一刻估计人直接清醒了。
这就很职场。你以为加班是在攒功劳,老板那边可能只是在记录:这个人挺能熬,下次继续用。
所以他后面也想明白了,到点差不多就撤。不是突然摆烂,是终于知道了,有些公司嘴上讲奋斗,发钱的时候又开始讲预算。
B+不涨薪,十点下班也不涨薪,那早点回家吃饭,好像也挺合理的。
面试题:1 比特与 2 比特字符
bits = [1, 1, 1, 0] 这个用例,很多人第一眼会判错。
最后一位确实是 0,但它不一定就是一个独立字符。
这题坑就坑在这里:不是看最后一位长什么样,而是看前面的解析有没有把它吃掉。
题目叫 1 比特与 2 比特字符。规则很少:
0 表示一个 1 比特字符。
10 或 11 表示一个 2 比特字符。
给你一个只包含 0 和 1 的数组,并且数组最后一位一定是 0,问最后这个 0 是不是一个单独的 1 比特字符。
别急着从后往前看。
我一般遇到这种编码解析题,第一反应不是找数学规律,而是按协议解析一遍。因为协议这东西,前面怎么读,会直接影响后面的位置。你不能盯着最后一个字节说它是不是独立的,得看指针最后是不是刚好落到它身上。
比如这个:
[1, 0, 0]
从第 0 位开始看:
1 0 -> 一个 2 比特字符
0 -> 一个 1 比特字符
最后这个 0 是独立的。
再看这个:
[1, 1, 1, 0]
解析过程是:
1 1 -> 一个 2 比特字符
1 0 -> 一个 2 比特字符
最后这个 0 被前面的 1 带走了,不是独立字符。
这地方如果只写一句“最后一个 0 前面有几个连续的 1”,当然也能做,但我不太喜欢一上来就这么写。面试题还好,线上协议解析你敢这么写,后面改规则的时候大概率把自己坑进去。
直接模拟,反而最稳。
代码可以这样写:
publicclassBitCharChecker{
publicbooleanisLastSingleBit(int[] bits){
if (bits == null || bits.length == 0) {
returnfalse;
}
int pos = 0;
int last = bits.length - 1;
while (pos < last) {
if (bits[pos] == 0) {
pos += 1;
} else {
pos += 2;
}
}
return pos == last;
}
}
这段代码就干一件事:从头解析,别越过最后一位。
pos < last 这个条件要注意。
这里不是 pos < bits.length。
因为我们只关心最后一位有没有被单独解析到。只要指针还在最后一位前面,就继续按规则往后跳。
最后有两种情况:
pos == last
说明前面的字符都解析完了,指针刚好停在最后这个 0 上,那它就是单独的 1 比特字符。
pos > last
说明最后这个 0 已经被前面的 1 组成了 2 比特字符,不能单独算。
拿几个用例跑一下,别只看脑子里的感觉:
publicclassBitCharDemo{
publicstaticvoidmain(String[] args){
BitCharChecker checker = new BitCharChecker();
int[][] cases = {
{0},
{1, 0, 0},
{1, 1, 1, 0},
{1, 1, 0},
{0, 0},
{1, 0}
};
for (int[] bits : cases) {
System.out.println(format(bits) + " -> " + checker.isLastSingleBit(bits));
}
}
privatestatic String format(int[] bits){
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < bits.length; i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(bits[i]);
}
return sb.append("]").toString();
}
}
输出大概是这样:
[0] -> true
[1, 0, 0] -> true
[1, 1, 1, 0] -> false
[1, 1, 0] -> true
[0, 0] -> true
[1, 0] -> false
其中 [1, 1, 0] 也容易误判。
它的解析是:
1 1 -> 2 比特字符
0 -> 1 比特字符
所以返回 true。
而 [1, 0] 是:
1 0 -> 2 比特字符
最后这个 0 就不是独立的。
这题的复杂度没什么花头,时间复杂度 O(n),空间复杂度 O(1)。
但真正容易错的不是复杂度,是边界。
尤其是这种写法:
while (pos < bits.length) {
if (bits[pos] == 0) {
pos++;
} else {
pos += 2;
}
}
return pos == bits.length - 1;
这代码看着像那么回事,实际已经晚了。
因为它会把最后一位也解析掉。假设输入是:
[0]
循环进去后 pos 从 0 变成 1,最后判断 pos == 0,直接返回 false。
这就是典型的指针边界没想清楚。
这类题不要急着压缩成一行,也不要为了显得聪明去背结论。按编码规则走一遍,指针停在哪,答案就在哪。规则题最怕猜,猜对一次没用,换个用例就露馅。