晋升答辩那天,我准备了20页PPT,把过去一年的成就讲得天花乱坠,结果..后来才发现,晋升名单其实早就在答辩前定好了
刚看到个贴子,说一位网友晋升答辩,整了20页PPT把一年业绩夸夸其谈,结果评委只问了一句:“你在这个项目里的不可替代性在哪?”他当场愣住,后来才发现晋升名单早就定好了,答辩纯属走过场。
我觉得这事吧,有两层。第一,很多公司晋升确实有“预设答案”,别把一场答辩当成命运大转盘,心态要现实点。第二,就算是走过场,那句“不可替代性”也问得挺扎心:你到底凭什么站在那张台子上?
从我的角度看,“不可替代性”,就是你能解决别人解决不了的问题,能扛别人不愿扛的事。晋升不一定公平,但想清楚这一点,对谁都是刚需。剩下的,就当练本事,别把希望全押在一场PPT上。
面试题:拆分二叉搜索树
昨天晚上十一点多吧,我在公司楼下抽烟呢,手机群里有人突然甩了个算法题,说“拆分二叉搜索树”,我第一反应还以为是那种把树砍两半的暴力活……后来一想不对,这玩意其实特别像线上做灰度:一棵 BST,给你个阈值 V,你得把它拆成两棵树,一棵全是 <= V,另一棵全是 > V,而且还得保持 BST 结构不乱,节点也不能丢。
你们知道 BST 那个味儿吧,左边都小,右边都大,所以拆的时候千万别去全树扫描,那就跟线上全量扫库一样,迟早出事。正确姿势是顺着“阈值”这条线走:
如果当前节点 root.val <= V,那它肯定应该留在“小树”里;但它的右子树里可能有一部分跑到“大树”去,所以只需要去拆右子树。拆完以后,小树这边的root.right接回“右子树拆出来的小半边”,大树那半边单独返回。反过来如果 root.val > V,这个节点就得留在“大树”里;但它左子树里可能有一些其实<= V,所以去拆左子树。拆完以后,大树这边的root.left接回“左子树拆出来的大半边”,小树那半边返回。
说白了就是递归一路下去,每次只动一条边,复杂度基本就是树高,平衡树接近 O(log n),最坏退化成链表才 O(n),但也比你傻乎乎全遍历强太多了。
代码我就按工程里最常见的写法来,返回一个长度为 2 的数组:res[0] 是小树根,res[1] 是大树根。对了,别用什么 Pair 啊三方包啊,面试官看了容易皱眉,直接数组最省事。
publicclassSplitBST{
staticclassTreeNode{
int val;
TreeNode left, right;
TreeNode(int v) { this.val = v; }
}
// 返回结果:res[0] = <= V 的BST根,res[1] = > V 的BST根
publicstatic TreeNode[] splitBST(TreeNode root, int V) {
if (root == null) returnnew TreeNode[]{null, null};
if (root.val <= V) {
// root 属于小树,去拆右子树
TreeNode[] rightSplit = splitBST(root.right, V);
root.right = rightSplit[0]; // 右子树里 <=V 的部分接回小树
returnnew TreeNode[]{root, rightSplit[1]}; // >V 的部分就是大树
} else {
// root 属于大树,去拆左子树
TreeNode[] leftSplit = splitBST(root.left, V);
root.left = leftSplit[1]; // 左子树里 >V 的部分接回大树
returnnew TreeNode[]{leftSplit[0], root}; // <=V 的部分就是小树
}
}
// 随手写个小测试,别太在意输出格式,主要看结构不乱、节点不丢
publicstaticvoidmain(String[] args){
/*
4
/ \
2 6
/ \ / \
1 3 5 7
*/
TreeNode root = new TreeNode(4);
root.left = new TreeNode(2);
root.right = new TreeNode(6);
root.left.left = new TreeNode(1);
root.left.right = new TreeNode(3);
root.right.left = new TreeNode(5);
root.right.right = new TreeNode(7);
TreeNode[] res = splitBST(root, 2);
// res[0] 应该包含 1,2;res[1] 应该包含 3,4,5,6,7(并保持BST)
System.out.println(res[0].val); // 大概率是2
System.out.println(res[1].val); // 大概率是4
}
}
你要是把这个思路带到日常写业务,其实挺像“按条件把一坨数据拆成两条链路”,关键点就是:别乱动不该动的部分,只沿着可能跨界的那条边去处理。昨天群里还有人问“能不能迭代写”,能写啊,但递归其实更像你脑子里那棵树的形状,写错概率更低……哎我先不说了,刚有人 @我 说线上又有个慢 SQL,要去看下日志了。