南大计算机博士,毕业两年多,在北京某头部大厂,接着干还是回二线老家央企
这不是选工作,这是选以后怎么过日子。
南大计算机博士,在北京大厂干底层架构,钱确实香,一年六七十个,放哪都不低。但问题也摆着:业务没啥往上冲的劲儿,晋升短期看不见,还得随时被 oncall 拎起来。强度可能没卷到吐血,但心累这玩意儿,真不是工资条能完全抵消的。
另一边呢,老家二线省会央企研究院,钱直接砍一半还多,听着肉疼。但人是本地人,女友也在那边事业编,后面还准备结婚。这个变量太大了。你一个人在北京扛,和两个人在老家把日子搭起来,完全不是一道题。
最关键是,这个入编不是口头画饼,考核也写得清楚。难点就是那两年,SCI加项目,能不能稳稳过。
老鬼觉得吧,想继续冲钱,就留北京;想把生活落地,央企这个坑真得认真想想。
这题最容易写歪的地方,是看到两个节点值一样,就急着返回 True。
比如主树里有个节点值是 4,子树根节点也是 4,看着像对上了。但左孩子、右孩子只要有一个不一样,这个 4 就不是你要找的那棵子树。
题目叫“另一棵树的子树”,判断的不是“有没有这个值”,也不是“有没有一段路径”,而是从某个节点往下,整棵结构和值都要一模一样。
我一般会拆成两个判断。
一个负责找入口:在大树里挨个找可能匹配的节点。
一个负责验货:从这个节点开始,两棵树是不是完全一样。
代码可以这样写:
classSolution:
defisSubtree(self, root, subRoot):
if subRoot isNone:
returnTrue
if root isNone:
returnFalse
if self._same_tree(root, subRoot):
returnTrue
return (
self.isSubtree(root.left, subRoot)
or self.isSubtree(root.right, subRoot)
)
def_same_tree(self, a, b):
if a isNoneand b isNone:
returnTrue
if a isNoneor b isNone:
returnFalse
if a.val != b.val:
returnFalse
return (
self._same_tree(a.left, b.left)
and self._same_tree(a.right, b.right)
)
这里我不太建议把所有逻辑揉进一个递归里。能写,但容易乱。
isSubtree 只干一件事:在大树里找位置。
_same_tree 也只干一件事:从当前位置开始,对两棵树做严格比对。
比如这棵树:
3
/ \
4 5
/ \
1 2
子树是:
4
/ \
1 2
当递归扫到值为 4 的节点时,_same_tree 开始接管。它会继续比左子树是不是 1,右子树是不是 2。都对,才算匹配成功。
但如果主树变成这样:
3
/ \
4 5
/ \
1 2
/
0
子树还是 4,1,2。
这时候根节点值、左孩子、右孩子表面上都对,但 2 下面多了一个 0。这就不是同一棵树。很多错误代码会漏在这里,因为它只判断了子树有的节点,没判断主树是不是多了东西。
所以 _same_tree 里这两句不能省:
if a isNoneand b isNone:
returnTrue
if a isNoneor b isNone:
returnFalse
第一句说明两边都走到底了,干净。
第二句说明一边还有节点,一边没了,结构已经不一样了。
复杂度上,最坏情况确实不算漂亮。大树每个节点都可能触发一次完整比对,时间复杂度大概是 O(m * n)。但这题在普通面试和刷题场景里,这个写法已经够稳。除非数据特别大,再考虑序列化加字符串匹配,或者给树做哈希。
这类树题别急着秀技巧。
先把“找入口”和“验整棵树”拆开,递归边界写严,基本就不会翻车。