vlambda博客
学习文章列表

544,剑指 Offer-平衡二叉树

Time goes on and on, never to an end but crossings.   

时间一直走,没有尽头,只有路口。

问题描述



输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的高度相差不超过1,那么它就是一棵平衡二叉树。


示例 1:

给定二叉树 [3,9,20,null,null,15,7]

 3 / \ 9 20 / \ 15 7

返回 true 。

示例 2:

给定二叉树 [1,2,2,3,3,null,null,4,4]

 1 / \ 2 2 / \ 3 3 / \ 4 4

返回 false 。


限制:

  • 0 <= 树的结点个数 <= 10000


从上到下



平衡二叉树要求的是左右子节点的高度不能超过1,所以我们可以判断树的左右两个子节点的高度只要不超过1就行,而树的高度怎么计算呢,其实很简单,代码如下

1//计算树中节点的高度
2public int depth(TreeNode root{
3    if (root == null)
4        return 0;
5    return Math.max(depth(root.left), depth(root.right)) + 1;
6}

所以这题的代码我们也很容易写出来

 1public boolean isBalanced(TreeNode root) {
2    if (root == null)
3        return true;
4    //分别计算左子树和右子树的高度
5    int left = depth(root.left);
6    int right = depth(root.right);
7    //这两个子树的高度不能超过1
8    return Math.abs(left - right) <= 1;
9}
10
11//计算树中节点的高度
12public int depth(TreeNode root) {
13    if (root == null)
14        return 0;
15    return Math.max(depth(root.left), depth(root.right)) + 1;
16}

但这里会有个问题,因为二叉平衡树的任何一棵子树也都必须是平衡的,上面我们只判断了根节点的两个子节点的高度是否小于等于1,没有判断子树是否是平衡的。


如下图所示,虽然根节点的两个子节点的高度是一样的,但很明显根节点的右子树不是平衡的,也就是说这棵树不是平衡二叉树。

所以除了判断根节点以外,还需要判断所有的子节点,具体看下视频

544,剑指 Offer-平衡二叉树

再来看下代码

 1public boolean isBalanced(TreeNode root) {
2    if (root == null)
3        return true;
4    //分别计算左子树和右子树的高度
5    int left = depth(root.left);
6    int right = depth(root.right);
7    //这两个子树的高度不能超过1,并且他的两个子树也必须是平衡二叉树
8    return Math.abs(left - right) <= 1 && isBalanced(root.left) && isBalanced(root.right);
9}
10
11//计算树中节点的高度
12public int depth(TreeNode root) {
13    if (root == null)
14        return 0;
15    return Math.max(depth(root.left), depth(root.right)) + 1;
16}


从下到上



上面的计算过程是从上往下判断的,其实我们还可以从下往上判断,就是从叶子节点开始往上,如果某一个子树不是平衡的就返回false,具体看视频

544,剑指 Offer-平衡二叉树

先判断两个子树是否是平衡的,然后再判断以当前节点为根节点的子树是否是平衡的……。来看下代码

 1//如果等于-1就表示不是平衡的
2private static final int UNBALANCED = -1;
3
4public boolean isBalanced(TreeNode root) {
5    return helper(root) != UNBALANCED;
6}
7
8public int helper(TreeNode root) {
9    if (root == null)
10        return 0;
11
12    //如果左子节点不是平衡二叉树,直接返回UNBALANCED
13    int left = helper(root.left);
14    if (left == UNBALANCED)
15        return UNBALANCED;
16
17    //如果右子节点不是平衡二叉树,直接返回UNBALANCED
18    int right = helper(root.right);
19    if (right == UNBALANCED)
20        return UNBALANCED;
21
22    //如果左右子节点都是平衡二叉树,但他们的高度相差大于1,
23    //直接返回UNBALANCED
24    if (Math.abs(left - right) > 1)
25        return UNBALANCED;
26
27    //否则就返回二叉树中节点的最大高度
28    return Math.max(left, right) + 1;
29}


总结



关于二叉树的一些常用术语我们来总结一下:


节点的度:一个节点含有的子树的个数称为该节点的度;

树的度:一棵树中,最大的节点度称为树的度;

叶节点或终端节点:度为零的节点;

非终端节点或分支节点:度不为零的节点;

父亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;

孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;

兄弟节点:具有相同父节点的节点互称为兄弟节点;

节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;

深度:对于任意节点n,n的深度为从根到n的唯一路径长,根的深度为0;

高度:对于任意节点n,n的高度为从n到一片树叶的最长路径长,所有树叶的高度为0;

堂兄弟节点:父节点在同一层的节点互为堂兄弟;

节点的祖先:从根到该节点所经分支上的所有节点;

子孙:以某节点为根的子树中任一节点都称为该节点的子孙。

森林:由m(m>=0)棵互不相交的树的集合称为森林;




你点的每个赞,我都认真当成了喜欢