给定一个二叉树,根节点为第1层,深度为 1。在其第 d 层追加一行值为 v 的节点。

添加规则:给定一个深度值 d (正整数),针对深度为 d-1 层的每一非空节点 N,为 N 创建两个值为 v 的左子树和右子树。

将 N 原先的左子树,连接为新节点 v 的左子树;将 N 原先的右子树,连接为新节点 v 的右子树。

如果 d 的值为 1,深度 d - 1 不存在,则创建一个新的根节点 v,原先的整棵树将作为 v 的左子树。

  1. 示例 1:
  2. 输入:
  3. 二叉树如下所示:
  4. 4
  5. / \
  6. 2 6
  7. / \ /
  8. 3 1 5
  9. v = 1
  10. d = 2
  11. 输出:
  12. 4
  13. / \
  14. 1 1
  15. / \
  16. 2 6
  17. / \ /
  18. 3 1 5
  1. 示例 2:
  2. 输入:
  3. 二叉树如下所示:
  4. 4
  5. /
  6. 2
  7. / \
  8. 3 1
  9. v = 1
  10. d = 3
  11. 输出:
  12. 4
  13. /
  14. 2
  15. / \
  16. 1 1
  17. / \
  18. 3 1

注意:

输入的深度值 d 的范围是:[1,二叉树最大深度 + 1]。

输入的二叉树至少有一个节点。

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/add-one-row-to-tree

这道题让我们给二叉树增加一行,给了需要增加的值,还有需要增加的位置深度,题目中给的例子也比较能清晰的说明问题。但是漏了一种情况,那就是当d=1时,这该怎么加?这时候就需要替换根结点了。其他情况的处理方法都一样,这里博主第一映像觉得应该用层序遍历来做,每遍历完一层,d自减1,当d==1时,需要对于当前层的每一个结点,先用临时变量保存其原有的左右子结点,然后新建值为v的左右子结点,将原有的左子结点连到新建的左子结点的左子结点上,将原有的右子结点连到新建的右子结点的右子结点,是不是很绕-.-|||。如果d不为1,那么就是层序遍历原有的排入队列操作,记得当检测到d为0时,直接返回,因为添加操作已经完成,没有必要遍历完剩下的结点,参见代码如下:

解法一:

  1. class Solution {
  2. public:
  3. TreeNode* addOneRow(TreeNode* root, int v, int d) {
  4. if (!root) return NULL;
  5. if (d == 1) {
  6. TreeNode *newRoot = new TreeNode(v);
  7. newRoot->left = root;
  8. return newRoot;
  9. }
  10. queue<TreeNode*> q{{root}};
  11. while (!q.empty()) {
  12. if (--d == 0) return root;
  13. int n = q.size();
  14. for (int i = 0; i < n; ++i) {
  15. auto t = q.front(); q.pop();
  16. if (d == 1) {
  17. TreeNode *left = t->left;
  18. TreeNode *right = t->right;
  19. t->left = new TreeNode(v);
  20. t->right = new TreeNode(v);
  21. t->left->left = left;
  22. t->right->right = right;
  23. } else {
  24. if (t->left) q.push(t->left);
  25. if (t->right) q.push(t->right);
  26. }
  27. }
  28. }
  29. return root;
  30. }
  31. };

虽然博主一贯的理念是二叉树问题肯定首选递归来解,但是这道题博主刚开始以为递归没法解,结果看了大神们的帖子,才发现自己还是图样图森破,难道二叉树的问题皆可递归?反正这道题是可以的,而且写法 so 简洁,乍一看上去,会有疑问,题目中明明d的范围是从1开始的,为何要考虑d为0的情况,后来读懂了整个解法后,才为原作者的聪慧叹服。这里d的0和1,其实相当于一种 flag,如果d为1的话,那么将 root 连到新建的结点的左子结点上;反之如果d为0,那么将 root 连到新建的结点的右子结点上,然后返回新建的结点。如果 root 存在且d大于1的话,那么对 root 的左子结点调用递归函数,注意此时若d的值正好为2,那么就不能直接减1,而是根据左右子结点的情况分别赋值1和0,这样才能起到 flag 的作用嘛,叼的飞起,参见代码如下:

解法二:

  1. class Solution {
  2. public:
  3. TreeNode* addOneRow(TreeNode* root, int v, int d) {
  4. if (d == 0 || d == 1) {
  5. TreeNode *newRoot = new TreeNode(v);
  6. (d ? newRoot->left : newRoot->right) = root;
  7. return newRoot;
  8. }
  9. if (root && d > 1) {
  10. root->left = addOneRow(root->left, v, d > 2 ? d - 1 : 1);
  11. root->right = addOneRow(root->right, v, d > 2 ? d - 1 : 0);
  12. }
  13. return root;
  14. }
  15. };

方法一:深度优先搜索(递归)

如果 d 的值为 1,我们就添加一个节点,并将整棵树作为新节点的左子树。否则我们可以使用深度优先搜索找出所有 d 层的节点并进行操作。在搜索时,我们需要记录当前节点的深度 depth,如果此时 depth == d - 1,那么我们需要在当前节点的左右孩子各增加一个节点。如果当前节点的左右孩子已经有节点,我们就将这些节点存储到临时变量中,在增加新节点后再把左右孩子作为新节点的左子树或右子树,并结束递归。如果 depth != d - 1,我们就需要对当前节点的子节点进行递归搜索。

java

  1. public class Solution {
  2. public TreeNode addOneRow(TreeNode t, int v, int d) {
  3. if (d == 1) {
  4. TreeNode n = new TreeNode(v);
  5. n.left = t;
  6. return n;
  7. }
  8. insert(v, t, 1, d);
  9. return t;
  10. }
  11. public void insert(int val, TreeNode node, int depth, int n) {
  12. if (node == null)
  13. return;
  14. if (depth == n - 1) {
  15. TreeNode t = node.left;
  16. node.left = new TreeNode(val);
  17. node.left.left = t;
  18. t = node.right;
  19. node.right = new TreeNode(val);
  20. node.right.right = t;
  21. } else {
  22. insert(val, node.left, depth + 1, n);
  23. insert(val, node.right, depth + 1, n);
  24. }
  25. }
  26. }

复杂度分析

时间复杂度:O(N),其中 N 是二叉树的节点个数。我们最多会遍历 N 个节点。

空间复杂度:O(N)。在最坏情况下,需要递归 N 层,用到 O(N) 的栈空间。

方法二:深度优先搜索(非递归)

我们可以直接用栈来模拟递归,实现深度优先搜索的非递归版本。

我们首先将根节点入栈,随后每次栈顶的元素即为当前搜索到的结点,我们取出这个节点,根据 depth 和 d - 1 的关系为当前节点增加新的子节点,或者将当前节点的子节点全部入栈,继续搜索。

java

  1. public class Solution {
  2. class Node{
  3. Node(TreeNode n,int d){
  4. node=n;
  5. depth=d;
  6. }
  7. TreeNode node;
  8. int depth;
  9. }
  10. public TreeNode addOneRow(TreeNode t, int v, int d) {
  11. if (d == 1) {
  12. TreeNode n = new TreeNode(v);
  13. n.left = t;
  14. return n;
  15. }
  16. Stack<Node> stack=new Stack<>();
  17. stack.push(new Node(t,1));
  18. while(!stack.isEmpty())
  19. {
  20. Node n=stack.pop();
  21. if(n.node==null)
  22. continue;
  23. if (n.depth == d - 1 ) {
  24. TreeNode temp = n.node.left;
  25. n.node.left = new TreeNode(v);
  26. n.node.left.left = temp;
  27. temp = n.node.right;
  28. n.node.right = new TreeNode(v);
  29. n.node.right.right = temp;
  30. } else{
  31. stack.push(new Node(n.node.left, n.depth + 1));
  32. stack.push(new Node(n.node.right, n.depth + 1));
  33. }
  34. }
  35. return t;
  36. }
  37. }

复杂度分析

时间复杂度:O(N),其中 N 是二叉树的节点个数。我们最多会遍历 N 个节点。

空间复杂度:O(N)。

方法三:广度优先搜索

我们同样可以使用广度优先搜索解决这个问题,并且广度优先搜索是最容易理解且最直观的一种方法。

我们将根节点放入队列 queue。在每一轮搜索中,如果 queue 中节点的深度为 d - 1(显然 queue 中所有的节点都在同一深度),我们就退出搜索,并为 queue 中所有节点添加新的子节点;否则我们将 queue 中所有节点的子节点放入新的队列 temp 中,再用 temp 替代 queue。

java

  1. public class Solution {
  2. public TreeNode addOneRow(TreeNode t, int v, int d) {
  3. if (d == 1) {
  4. TreeNode n = new TreeNode(v);
  5. n.left = t;
  6. return n;
  7. }
  8. Queue < TreeNode > queue = new LinkedList < > ();
  9. queue.add(t);
  10. int depth = 1;
  11. while (depth < d - 1) {
  12. Queue < TreeNode > temp = new LinkedList < > ();
  13. while (!queue.isEmpty()) {
  14. TreeNode node = queue.remove();
  15. if (node.left != null) temp.add(node.left);
  16. if (node.right != null) temp.add(node.right);
  17. }
  18. queue = temp;
  19. depth++;
  20. }
  21. while (!queue.isEmpty()) {
  22. TreeNode node = queue.remove();
  23. TreeNode temp = node.left;
  24. node.left = new TreeNode(v);
  25. node.left.left = temp;
  26. temp = node.right;
  27. node.right = new TreeNode(v);
  28. node.right.right = temp;
  29. }
  30. return t;
  31. }
  32. }

复杂度分析

时间复杂度:O(N),其中 NN 是二叉树的节点个数。我们最多会遍历 N 个节点。

空间复杂度:O(N)。

按层递归遍历到目标层的前一层按规则直接改树,注意第一层是边界,需要单独输出。

python

  1. class Solution:
  2. def addOneRow(self, root: TreeNode, v: int, d: int) -> TreeNode:
  3. if d == 1:
  4. r = TreeNode(v)
  5. r.left = root
  6. return r
  7. def f(r, i):
  8. if r:
  9. if i < d-1:
  10. f(r.left, i + 1)
  11. f(r.right, i + 1)
  12. else:
  13. t = TreeNode(v)
  14. t.left = r.left
  15. r.left = t
  16. t = TreeNode(v)
  17. t.right = r.right
  18. r.right = t
  19. f(root, 1)
  20. return root

LeetCode——623.在二叉树中增加一行的更多相关文章

  1. Java实现 LeetCode 623 在二叉树中增加一行(遍历树)

    623. 在二叉树中增加一行 给定一个二叉树,根节点为第1层,深度为 1.在其第 d 层追加一行值为 v 的节点. 添加规则:给定一个深度值 d (正整数),针对深度为 d-1 层的每一非空节点 N, ...

  2. Leetcode 623.在二叉树中增加一行

    在二叉树中增加一行 给定一个二叉树,根节点为第1层,深度为 1.在其第 d 层追加一行值为 v 的节点. 添加规则:给定一个深度值 d (正整数),针对深度为 d-1 层的每一非空节点 N,为 N 创 ...

  3. [LeetCode] 623. Add One Row to Tree 二叉树中增加一行

    Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value ...

  4. [LeetCode] Add One Row to Tree 二叉树中增加一行

    Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value ...

  5. [Swift]LeetCode623. 在二叉树中增加一行 | Add One Row to Tree

    Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value ...

  6. ASP.net中GridView中增加一行记录并默认显示为编辑状态

    //添加 protected void Button1_Click(object sender, EventArgs e) { DataSet ds = (DataSet)pa.GetDataSet( ...

  7. 【Leetcode】查找二叉树中任意结点的最近公共祖先(LCA问题)

    寻找最近公共祖先,示例如下: 1 /           \ 2           3 /    \        /    \ 4    5      6    7 /    \          ...

  8. leetcode:124. 二叉树中的最大路径和

    题目描述: 给定一个非空二叉树,返回其最大路径和. 本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列.该路径至少包含一个节点,且不一定经过根节点. 示例 1: 输入: [1,2,3] 1 ...

  9. PHP实现单击“添加”按钮增加一行表单项,并将所有内容插入到数据库中

    PHP实现单击“添加”按钮增加一行表单项,并将所有内容插入到数据库中 效果图: html+jquery: <html> <head> <meta http-equiv=& ...

随机推荐

  1. python基础笔记:判断与循环

    判断: #根据身高为1.75,体重为65的小明的bmi输出小明的身材 h=1.75 w=65 bmi=w/(h*h) if bmi<18.5: print('过轻') elif bmi<= ...

  2. oracle开机启动

    第一步 修改oratab (root用户执行) /etc/oratab的配置格式如下: $ORACLE_SID:$ORACLE_HOME:Y 例如:orclqdgw:/var/app/oracle/p ...

  3. JDBC面试知识点整理(温习用)

    要面试,所以把之前的笔记整理一遍,嘻嘻,加油 JDBC编程 使用JDBC,java程序可以轻松地操作各种主流数据库,Oracle,MySQL,等,使用JDBC编写的程序不仅可以实现跨数据库,还具有跨平 ...

  4. 十二、Sap的压缩类型p的使用方法

    一.代码如下 二.我们查看输出结果 三.如果位数超出了会怎样呢?我们试试 四.提示如下

  5. HZNU-ACM寒假集训Day12小结 数论入门

    符号说明 a|b      a整除b (a,b)    a与b的最大公因数 [a,b]     a与b的最小公倍数 pα||a    pα|a但pα+1∤a a≡b(mod m) a与b对模m同余 a ...

  6. javaweb利用ajax使登录窗口不跳转页面实现对账号密码的判断

    和上一篇判断用户名是否被占用不跳转页面类似!利用ajax实现跳转,要导入jquery文件库!具体代码我会贴出来,注释在里面!!可以观摩一手!(代码我也留下链接,如果失效,评论补发,代码可能导入也无法使 ...

  7. Spring 框架介绍

    Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of Control – I ...

  8. mysql多表关联更新

    update 表A inner join 表B on 表A.关联字段 = 表B.关联字段 set 表a.待更新字段01 = 表B.字段01 , 表a.待更新字段021 = 表B.字段02 where ...

  9. POJ 3627:Bookshelf

    Bookshelf Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7758   Accepted: 3906 Descrip ...

  10. 从华硕裁员、分拆业务看传统PC企业转型到底有多难?

    近段时间,华硕的处境可谓"冰火两重天".一方面,华硕正式发布ROG游戏手机.这款手机以超强性能和华丽外观,让游戏玩家群体为之沸腾.即使最高售价高达12999元,还是有不少玩家趋之若 ...