堂弟 45岁,今年被裁员了,赔偿金18万,被裁后他找了半年的工作,都嫌弃他年龄大,工资比以前少大半,不够养家~
刚看到个贴子,说堂弟45岁被裁,拿了18万赔偿金,半年找工作处处碰壁,最后想拿家里凑的40万自己做小生意。
我觉得这事吧,关键不在“靠不靠谱”,而在心态和方向。网友们有人劝稳,有人让他创业一搏,我看了看,嗯…都不算错,但都不够全面。45岁再就业确实难,这不是个人问题,是大环境摆在这儿。但创业也不是“有钱就能成”,40万说多不多,说少也够折腾没两下。
从我角度看,如果真要干,小本轻资产、试错成本低的生意更靠谱,千万别一上来就梭哈。另外家里一定要能稳住基本盘,不然创业的压力会把人压垮。
路是能走通的,但别盲目,稳住心态,一步一步来。未来不一定差。【备注:文末可领最新资料】
面试题:在二叉树中增加一行
昨天晚上快十一点了我还在公司,准备关电脑走人,结果我们组那个小李突然在工位后面冒一句:东哥东哥,你帮我看看这个“在二叉树中增加一行”的题咋写呀,用 Java 的那种。人都已经半只脚踏进下班了,你说气不气人…但谁让咱是老背锅的呢,对吧。
先说下题目大概啥意思哈,就是有一棵二叉树,给你一个 val 和一个 depth。你要在这棵树的第 depth 层,整整加出一行新的节点,这一行上每个新节点的值都是 val。然后原来这一层下面的孩子不能丢,要挂到新加的这一层下面去: 原来左孩子要挂到新左节点的左边,右孩子挂到新右节点的右边。depth == 1 的时候比较特别,相当于整个树头上再套一层,新的根节点值是 val,原来的整棵树变成它的左子树。
我当时给小李比喻了一下,说你就想象这树是一个老小区,现在领导说:在第 k 层统一加个架空层平台。那你要做的事其实就两步: 先找到所有“原来的第 k-1 层的住户”,然后在他们家楼下各加一层,把下面的原住户再塞到新加的这一层下面去。听着有点绕,实际写代码还挺顺。
思路就一个字:找。 稍微正常一点的写法,就是用层序遍历,拿个队列一层一层往下扫。我们只关心两件事:
如果 depth == 1,那就简单粗暴:新建一个节点当根,newRoot.left = oldRoot,返回新根就完事。其他情况就用 BFS,从根开始算当前层数 curDepth,当走到curDepth == depth - 1的时候,队列里的这些节点,就是你要“在它们下面加一行”的那批爸爸节点了。
到了这一层,动作有点像做外科手术: 对队列里的每个节点 node,先把原来的 node.left 和 node.right 暂存一下,别弄丢了。然后:
node.left = new TreeNode(val);node.right = new TreeNode(val);新左节点的左孩子指回老左: node.left.left = oldLeft;新右节点的右孩子指回老右: node.right.right = oldRight;
注意是左接左、右接右,中间那一层完全是新加出来的那“行”。有的节点本来就没有左孩子或者右孩子,那 oldLeft / oldRight 就是 null,挂上去也没事,空就空了,不用特判。
小李那会儿最容易犯错的地方就是:他一边改 node.left 一边还想从 node.left 往下递归,结果把原来的孩子指针覆盖掉了,想再用就找不着了。这个一定要先备份,再改指针,不然就跟搬家的时候先把房门拆了,再想进去拿东西一样,进不去了…
我当时直接给他写了个 Java 版本,你可以直接拿去用,假设 LeetCode 那种标准的 TreeNode 定义:
// 二叉树节点定义,一般题目都会给
publicclassTreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
classSolution{
public TreeNode addOneRow(TreeNode root, int val, int depth){
// 特殊情况:在第 1 层加一行,相当于换根节点
if (depth == 1) {
TreeNode newRoot = new TreeNode(val);
newRoot.left = root;
return newRoot;
}
java.util.Queue<TreeNode> queue = new java.util.LinkedList<>();
queue.offer(root);
int curDepth = 1;
while (!queue.isEmpty()) {
int size = queue.size();
// 到达目标上一层:当前是 depth - 1
if (curDepth == depth - 1) {
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (node == null) continue;
TreeNode oldLeft = node.left;
TreeNode oldRight = node.right;
// 在 node 下方加一行新节点
node.left = new TreeNode(val);
node.right = new TreeNode(val);
// 老的子树重新挂回去
node.left.left = oldLeft;
node.right.right = oldRight;
}
// 加完这一行就可以直接退出了
break;
} else {
// 正常往下一层扩散
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
curDepth++;
}
}
return root;
}
}
这段代码的时间复杂度你随便一算就知道,最多也就是把树扫一遍,节点数是 N 的话,大概就是 O(N)。空间上主要是队列这一坨,最坏也就是某一层的节点全塞进去,也是 O(N),不过一般题目不会给你搞成特别变态的树,业务里也够用了。
如果你更习惯递归,其实也能写 DFS 版本,大概的想法是:传当前深度下去,当 curDepth == depth - 1 的时候,对这个节点直接做加一行的操作,然后就不用再往更深递了。不过递归写容易一上来就绕晕,很多人会漏掉 depth == 1 这个开头的特殊情况。
还有个小建议,写完可以自己手画一棵小树,比如只有三层那种,随便模拟一下: 原来根是 1,下面 2 和 3,再下面 4、5、6 这种,找一个 depth = 3,让代码跑一遍,看看 4、5、6 最后挂到哪儿去。手上验证一遍,比你对着代码干看靠谱多了。
行了,我这会儿打字打到手酸了,先去给自己冲杯咖啡,你要是想顺带再搞个“删除一行”“翻转一层”之类的变种,可以再丢给我,我骂两句还是会给你写的…
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html