程序员老鬼

公司领导他爸生病住院,行政挨个工位来收“自愿捐款”,说“表达一下心意”,然后拿着本子登记,最低100块~

领导他爸住院,最先住进病房的不是孝心,是公司行政那本捐款登记册。嘴上说“自愿”,脚下已经挨个工位堵你了,最低100,搞得跟团建AA似的,不掏都显得你人品有问题。

Image

最烦这种场面。钱没到领导爸手里,压力先精准投送到打工人脸上。你不捐,行政那个表情,活像你刚把企业文化踩了一脚。捐了吧,又觉得自己不是献爱心,是交“懂事税”。

有网友说得挺准:真想表达心意,领导自己家亲戚朋友先上,别拿下属练忠诚。还有人说这不叫自愿,这叫带表格的道德绑架。

说白了,大家烦的不是那100块,是那种“你最好识相”的眼神。班已经够难上了,连善意都得按公司流程走,真是味儿太冲。

面试题:破解保险箱

四个拨轮,10 个数字,起点 0000,目标给你一个字符串,再塞一堆死亡密码 deadends。这题看着像枚举,真上手一顿拧,很快就会把自己绕晕。

这种题我一般不先想“怎么把目标拧出来”,而是先看它像不像图。每个密码是一层节点,拨一下某一位,就是往相邻节点走一步。问最少旋转次数,本质上就是在一张隐式图里找最短路。边权都一样,这时候还去上 DFS,基本就是给自己找麻烦,BFS 才是顺手的解法。

先把几个坑摆出来:

  • 0000 如果本身就在死亡列表里,直接没得玩。
  • 目标就是 0000,那一步都不用走。
  • 每一位不是简单加减 1,9 往上要回到 0,0 往下要回到 9,这个地方现场写错的人不少。

这题真正麻烦的不是思路,是邻居节点怎么生成得又短又不容易错。我不喜欢一上来拼一堆 substring,太碎。直接转成字符数组改一位,再还原,干净很多。

import java.util.*;

publicclassSolution{
publicintopenLock(String[] deadends, String target){
        Set<String> dead = new HashSet<>(Arrays.asList(deadends));
if (dead.contains("0000")) {
return -1;
        }
if ("0000".equals(target)) {
return0;
        }

        Queue<String> queue = new LinkedList<>();
        Set<String> visited = new HashSet<>();
        queue.offer("0000");
        visited.add("0000");

int step = 0;
while (!queue.isEmpty()) {
int size = queue.size();
            step++;

for (int i = 0; i < size; i++) {
                String cur = queue.poll();
for (String next : neighbors(cur)) {
if (dead.contains(next) || visited.contains(next)) {
continue;
                    }
if (target.equals(next)) {
return step;
                    }
                    queue.offer(next);
                    visited.add(next);
                }
            }
        }
return -1;
    }

private List<String> neighbors(String s){
        List<String> list = new ArrayList<>(8);
char[] arr = s.toCharArray();

for (int i = 0; i < 4; i++) {
char old = arr[i];

            arr[i] = old == '9' ? '0' : (char) (old + 1);
            list.add(new String(arr));

            arr[i] = old == '0' ? '9' : (char) (old - 1);
            list.add(new String(arr));

            arr[i] = old;
        }
return list;
    }
}

为什么这套能过?因为 BFS 是一层一层扩散。第一次碰到目标时,走的步数一定最少,不需要再证太多。每个状态最多进队一次,总状态上限也就 10000 个,时间复杂度差不多是 O(10000 * 8),这题规模下很稳。

还有个细节,很多人喜欢在出队时再判断是否访问过,这种写法不是不行,但会让队列里塞进去不少重复状态。我更习惯在入队前就拦掉,省空间,也省后面反复判断。