程序员老鬼

组里有个P7,为了防止被裁,把核心计费模块的代码写得晦涩难懂,还加了自定义的混淆逻辑,甚至不提交 Git, 结果CTO直接招了个外包团队~

刚看到个吐槽:有个大厂P7,为了防裁员,把计费核心捏在手里,代码写得天书一样,还拒绝提交流程,只留一份在服务器上,自以为成了“不可替代的人”。结果公司直接找外包重写模块,验证无误当天就把他辞了,还因为他私自操作生产环境,赔偿都按最低来。

Image

我觉得这事吧,很典型:把公司当对手,早晚会输得很难看。网友有的骂他活该,有的说是身不由己,我部分同情,但真站在管理角度看,你破坏的是团队的安全感和信任。

职场最该护的是自己的能力和口碑,而不是一坨没人看得懂的代码。想要安全感,最好的办法从来不是“绑架公司”,而是让谁拿走代码都离不开你这个人。

面试题:在 LR 字符串中交换相邻字符

昨晚十一点多吧,我在公司楼下抽烟…不是我爱抽啊,是那个线上小李又把一个很“像字符串题”的 bug 提上来了,说用户配置里有个状态串,里面就三个字符:L、R、X,然后问我“哥,这玩意到底能不能从 A 变成 B”。我一听就知道八成是那道老题:在 LR 字符串里交换相邻字符。

规则就很怪但又很像真实系统的约束:你只能做两种相邻交换——XL -> LX(等于 L 往左挪一格)和 RX -> XR(等于 R 往右挪一格)。别的都不许,比如 LX 你是换不动的,XR 你也换不动。说白了就是:L 只能往左走,R 只能往右走,X 就是空位。你把它当成停车位也行,反正就是那个…占位符。

我当时第一反应是:别模拟,模拟肯定超时还容易写崩。你想啊,每次交换都改变字符串,最坏情况一堆 X 来回挪,写着写着就开始“哎我怎么又漏了边界”。所以我跟小李说,咱直接看“骨架”,把所有 X 去掉,只看 L 和 R 的相对顺序。

这里有个很硬的结论: 1)把 start 和 end 里的 X 全删掉,剩下的序列必须一模一样,比如都是 RLRL,否则你怎么换都不可能凭空造出一个 L 或 R。 2)再看位置约束:

  • 对每一个 L:它只能往左挪,所以它在 start 里的下标 必须 >= 它在 end 里的下标(不然等于往右走了,犯规)。
  • 对每一个 R:它只能往右挪,所以它在 start 里的下标 必须 <= 它在 end 里的下标(不然等于往左走了,也犯规)。

这个思路写出来就很“像架构里做约束校验”:先校验结构一致性(序列),再校验方向性(位置单调)。你看,算法题也能贴地气一点对吧。

Java 代码我给你写个能直接跑的,没花里胡哨的:

publicclassSwapAdjacentInLRString{

publicstaticbooleancanTransform(String start, String end){
if (start == null || end == null) returnfalse;
if (start.length() != end.length()) returnfalse;

// 1) 骨架一致:去掉 X 后,L/R 序列必须相同
        String s1 = start.replace("X", "");
        String s2 = end.replace("X", "");
if (!s1.equals(s2)) returnfalse;

// 2) 双指针同步扫,拿到每个 L/R 的原位置与目标位置
int i = 0, j = 0;
int n = start.length();

while (i < n || j < n) {
while (i < n && start.charAt(i) == 'X') i++;
while (j < n && end.charAt(j) == 'X') j++;

if (i == n || j == n) break; // 都到头了就结束

char c = start.charAt(i); // 此时 start[i] 一定是 L 或 R,且等于 end[j]
if (c == 'L') {
// L 只能左移:start 位置不能小于 end 位置
if (i < j) returnfalse;
            } elseif (c == 'R') {
// R 只能右移:start 位置不能大于 end 位置
if (i > j) returnfalse;
            }
            i++;
            j++;
        }

returntrue;
    }

// 随手写个小测试,免得你复制过去没安全感
publicstaticvoidmain(String[] args){
        System.out.println(canTransform("RXXLRXRXL", "XRLXXRRLX")); // true
        System.out.println(canTransform("XLLR", "LXLX"));           // false(骨架都不一样)
        System.out.println(canTransform("XL", "LX"));               // true(L 左移)
        System.out.println(canTransform("RX", "XR"));               // true(R 右移)
        System.out.println(canTransform("LX", "XL"));               // false(L 不能右移)
    }
}

你看这段代码,其实就干了一件事:把每个非 X 的字符当成“事件”,对齐以后检查它是不是在合法方向移动。复杂度就是 O(n),内存也就几个指针,线上跑这种校验,怎么折腾都稳。

对了我当时还跟小李吐槽一句:这种题特别像你做分布式消息顺序校验——消息体(L/R 序列)必须一致,偏移量(下标)还得满足单调方向,不然就是“逆序消费”。他听完点点头,然后…又跑去改他那堆 if else 了,哎算了,我先去把咖啡续上,要不一会儿又有人 @ 我说“东哥我的单测咋不过”…

-END-