二叉树的应用问题

LeeCode 222: 完全二叉树的节点个数

题目描述

给你一棵 完全二叉树 的根节点 root,求出该树的节点个数。

完全二叉树的定义

  • 除最底层节点可能没填满外,其余每层节点树都达到最大值。
  • 且最底层的节点都集中在该层最左边的若干位置。

满二叉树的定义

  • 每一层的节点数都达到最大值。
  • 所以满二叉树是完全二叉树的一种。

建立模型

  1. 计算当前节点的左子树和右子树的高度
  2. 若相等,则说明以当前节点为根的数是一棵满二叉树,直接得到该数的节点数返回
  3. 若不相等,则递归计算当前节点的左子树和右子树
  4. 时间复杂度: \(O(log_2N)\) ,即从根节点到叶子节点的长度

代码实现

// Java 代码实现
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
} int left = 0, right = 0;
TreeNode node1 = root.left;
TreeNode node2 = root.right; // 因为是完全二叉树,所有最底层肯定存在左边的节点
while (node1 != null) {
left += 1;
node1 = node1.left;
} // 因为是完全二叉树,所有最底层可能不存在右边的节点
while (node2 != null) {
right += 1;
node2 = node2.right;
} // 若左右子树高度相等,则返回
if (left == right) {
return (1 << (left + 1)) - 1;
} // 若左右子树高度不想打,则递归计算
return countNodes(root.left) + countNodes(root.right) + 1;
}

LeeCode 110: 平衡二叉树

题目描述

给定一棵二叉树,判断它是否是高度平衡的二叉树。

一棵高度平衡二叉树的定义

二叉树每个节点的左右两个子树的高度差绝对值不超过1。

建立模型

自顶向下搜索

  1. 从根节点开始判断,左右子树的高度差
  2. 若符合,则递归判断左子节点和右子节点
  3. 若不符合,则返回 false
  4. 直至遍历完所有节点

自底向上传播

  1. 从叶子节点开始判断,左右子树的高度差
  2. 若符合,则向父节点传播当前节点的高度
  3. 如不符合,则向父节点传播 false
  4. 直至根节点

相较于自底向上的方法,自顶向下的过程中,存在大量的重复计算,时间复杂度较高。

代码实现

// 自顶向下, 最差情况可能需要对一个节点判断 logN 次
public boolean isBalanced(TreeNode root) {
if (root == null) {
return true;
} boolean flag = Math.abs(getHeight(root.left) - getHeight(root.right)) <= 1;
return flag && isBalanced(root.left) && isBalanced(root.right);
} // 计算以当前节点为根的树的高度
public int getHeight(TreeNode root) {
if (root == null) {
return 0;
} return Math.max(getHeight(root.left), getHeight(root.right)) + 1;
}
// 自底向上实现
public boolean isBalanced(TreeNode root) {
return recursive(root) != -1;
} public int recursive(TreeNode root) {
if (root == null) {
return 0;
} int left = recursive(root.left);
if (left == -1) {
return -1;
} int right = recursive(root.right);
if (right == -1) {
return -1;
} if (Math.abs(left - right) <= 1) {
return Matn.max(left, right) + 1;
} return -1;
}

LeeCode 113: 路径总和II

题目描述

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标的路径。

建立模型

  1. 这是一个回溯类型的问题
  2. 采用深度优先搜索的方式遍历二叉树
  3. 若遍历到叶子节点且路径和等于目标和,则添加该路径
  4. 若遍历到叶子节点但路径和不等于目标和,则不符合要求
  5. 直至遍历完整棵树

代码实现

public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) {
return res;
} List<Integer> temp = new ArrayList<>();
pathSumImpl(root, targetSum, temp, res);
return res;
} public void pathSumImpl(TreeNode root, int target, List<Integer> temp, List<List<Integer>> res) {
if (root.left == null && root.right == null) {
if (root.val == target) {
temp.add(root.val);
res.add(new ArrayList<>(temp));
temp.remove(temp.size() - 1);
} return;
} // 向左子树搜索
if (root.left != null) {
temp.add(root.val);
pathSumImpl(root.left, target - root.val, temp, res);
temp.remove(temp.size() - 1);
} // 向右子树搜索
if (root.right != null) {
temp.add(root.val);
pathSumImpl(root.right, target - root.val, temp, res);
temp.remove(temp.size() - 1);
} return;
}

LeeCode 617: 合并二叉树

题目描述

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

建立模型

  1. 从根节点开始合并,然后递归地合并左右子节点
  2. 若树1当前节点和树2当前节点均不为空,则返回一个新的节点,节点值相加
  3. 若树1当前节点为空,树2当前节点不为空,则返回树2当前节点
  4. 若树1当前节点不为空,树2当前节点为空,则返回树1当前节点
  5. 若树1当前节点和树2当前节点均为空,则返回 null (该情况可以合并到3,4中)

代码实现

public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) {
return root2;
} if (root2 == null) {
return root1;
} TreeNode root = new TreeNode(root1.val + root2.val);
root.left = mergeTrees(root1.left, roo2.left);
root.right = mergeTrees(root1.right, roo2.right); return root;
}

LeeCode 236: 二叉树的最近公共祖先

题目描述

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

p,q 均存在于给定的二叉树中。

建立模型

  1. 自底向上寻找p,q节点
  2. 若当前节点等于 p 或 q,则向父节点返回当前节点
  3. 若当前节点包含 p 或 q,则向父节点返回当前节点

代码实现

public TreeNode lowestCommonAncestor(TreeNode root) {
if (root == null || root == p || root == q) {
return root;
} TreeNode left = lowestCommonAncestor(root.left);
TreeNode right = lowestCommonAncestor(root.right); // left == null, 则p,q均位于当前root的右侧
if (left == null) {
return right;
} // right == null, 则p,q均位于当前root的左侧
if (right == null) {
return left;
} // left != null, right != null,则p,q位于当前root的两侧
return root;
}

LeeCode 二叉树问题(三)的更多相关文章

  1. 数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

    树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构.    a.树是n ...

  2. PTA 二叉树的三种遍历(先序、中序和后序)

    6-5 二叉树的三种遍历(先序.中序和后序) (6 分)   本题要求实现给定的二叉树的三种遍历. 函数接口定义: void Preorder(BiTree T); void Inorder(BiTr ...

  3. leecode第二百三十六题(二叉树的最近公共祖先)

    /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...

  4. 基于Java的二叉树的三种遍历方式的递归与非递归实现

    二叉树的遍历方式包括前序遍历.中序遍历和后序遍历,其实现方式包括递归实现和非递归实现. 前序遍历:根节点 | 左子树 | 右子树 中序遍历:左子树 | 根节点 | 右子树 后序遍历:左子树 | 右子树 ...

  5. C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)

    树 利用顺序存储和链式存储的特点,可以实现树的存储结构的表示,具体表示法有很多种. 1)双亲表示法:在每个结点中,附设一个指示器指示其双亲结点在数组中的位置. 2)孩子表示法:把每个结点的孩子排列起来 ...

  6. 非递归实现二叉树的三种遍历操作,C++描述

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  7. 二叉树学习三:AVL树

    1.AVL树: 1)其左子树(TL)与右子树(TR)是AVL树: 2)|HL-HR|<=1,其中HL和HR是TL和TR的高度: 3)高度为h的AVL树,结点数2*h-1. AVL树查找,插入,删 ...

  8. leecode第二百三十八题(除自身以外数组的乘积)

    class Solution { public: vector<int> productExceptSelf(vector<int>& nums) { int len= ...

  9. leecode第二百三十七题(删除链表中的节点)

    /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode ...

  10. leecode第二百三十五题(二叉搜索树的最近公共祖先)

    /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...

随机推荐

  1. React中的CSS模块

    CSS模块       使用步骤:         1.新建一个XXX.moudle.css文件         2.在组件中引入css           impor classes(变量) fro ...

  2. Nginx 代理解决跨域问题分析

    Nginx 代理解决跨域问题分析   当你遇到跨域问题,不要立刻就选择复制去尝试.请详细看完这篇文章再处理 .我相信它能帮到你. 分析前准备: 前端网站地址:http://localhost:8080 ...

  3. jetson TX2 + opencv3.4 + python3 + 双目 +人脸检测

    淘宝看到一款很便宜的双目,150元,就买了.想着用它学习一下opencv,好换个工作.当然,也想着能否用它做一些好玩的,比如三维重建之类高大上的东西.先用便宜的入个门,等以后眼界高了再看是不是买那些更 ...

  4. 各种系统名词解释:MIS 、ERP、CRM、OA

    MIS :信息系统.针对企业使用的软件,都可以叫做MIS系统. (管理信息系统--Management Information System)系统 ,是一个由人.计算机及其他外围设备等组成的能进行信息 ...

  5. How to Change Reset Retrieve the WebLogic Server Administrator Password on WLS 10.3.6 or earlier

    To change the Administrator password on WLS 10.3.6 or earlier, perform the following steps depending ...

  6. unity踩坑集锦

    1.AB包加载,如果项目没有这个tag,那么就匹配不上,和代码一样.2.unity打包安卓topbar想显示出来怎么做?:不渲染安全区域外  3. unity编辑器报错 : Expanding inv ...

  7. supervisor 使用中遇到的问题

    supervisor 配置完毕,使用supervisorctl reload 和supervisorctl update 启动时候报错 解决方法使用下面命令启动 /usr/bin/python2 /u ...

  8. python调用adb shell

    最近在用python做一个小工具,自动执行一些adb shell命令,使用subprocess.Popen来实现. 不过遇到个问题就是执行adb shell后就无法执行后面adb shell里的命令了 ...

  9. c++中文编码格式

    c++程序中涉及到中文字符的输入输出以及其他操作经常会出现乱码.乱码主要是由于程序的源文件编码.可执行文件编码以及程序运行环境的编码不匹配导致.比如,c++源程序文件编码为GB18030, 在源程序中 ...

  10. 《程序员的自我修养》学习笔记——ELF 文件结构介绍【第二弹】

    ELF 文件结构介绍 文件头 以 ELF 文件64位版本为例: e_ident [ELF魔数 16byte] 1-4字节:ELF 文件都必须相同的标识码,分别为 0x7F,0x45,0x4C,0x46 ...