[路飞]_每天刷leetcode_25(平衡二叉树 Balanced binary tree)

175 阅读2分钟

平衡二叉树

LeetCode传送门110. 平衡二叉树

题目

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

本题中,一棵高度平衡二叉树定义为:

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

Given a binary tree, determine if it is height-balanced.

For this problem, a height-balanced binary tree is defined as:

a binary tree in which the left and right subtrees of every node differ in height by no more than 1.

Example:

balance_1.jpg

Input: root = [3,9,20,null,null,15,7]
Output: true

Input: root = []
Output: true

Constraints:

The number of nodes in the tree is in the range [0, 5000].

104<=Node.val<=104-10^4 <= Node.val <= 10^4


思考线


解题思路

看到本题,我的第一思路是要递归找出左右子树的高度,然后计算是否高度差小于等于1。再递归遍历计算其高度差是否小于等于1即可。

基于上面的想法我们首先要构建一个方法来计算二叉树的深度。最容易实现的就是写一个递归函数。

递归的终止条件为

  • 当前节点为空,则返回0
  • 当前节点节点没有左右子节点,则返回1

递归过程为

  • 递归计算自己的左右子节点的长度。

返回结果为

  • 左右子节点的最长长度 +1,为当前节点的长度。

代码如下

function findDeepth(root) {
    if(!root) return 0;
    if(!root.left && !root.right) return 1;
    return Math.max(findDeepth(root.left), findDeepth(root.right)) +1;
}

有了计算二叉树高度的函数我们要找的最终解也呼之欲出了。

isBalanced函数中只要

  • 计算出左右子节点的高度,判断是否平衡,若不平衡则返回 false
  • 若平衡,则递归其左右子节点是否为平衡二叉树,若全都判定为平衡,则返回true否则为false

那么最终代码如下

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isBalanced = function(root) {
    if(!root) return true;
    const left = findDeepth(root.left)
    const right = findDeepth(root.right)
    return Math.abs(left - right) <=1 && isBalanced(root.left) && isBalanced(root.right);

};

function findDeepth(root) {
    if(!root) return 0;
    if(!root.left && !root.right) return 1;
    return Math.max(findDeepth(root.left), findDeepth(root.right)) +1;
}

对与这种解法的时间复杂度是多少呢?

复杂度分析

时间复杂度:O(n^2),其中 nn 是二叉树中的节点个数。 最坏情况下,二叉树是满二叉树,需要遍历二叉树中的所有节点,时间复杂度是 O(n)。 对于节点 p,如果它的高度是 d,则 findDeepth(p) 最多会被调用 d 次(即遍历到它的每一个祖先节点时)。对于平均的情况,一棵树的高度 hh 满足 O(h)=O(logn),因为 d ≤h,所以总时间复杂度为 O(nlogn)。对于最坏的情况,二叉树形成链式结构,高度为O(n),此时总时间复杂度为 O(n^2)。

空间复杂度:O(n),其中 n 是二叉树中的节点个数。空间复杂度主要取决于递归调用的层数,递归调用的层数不会超过 nn。

方法二

上面靠自觉做题的方法是自顶向下递归,因此对于同一个节点,计算数深度的函数findDeepth会被重复调用,导致时间复杂度较高。如果我们使用后序遍历的方法,先判断左右子节点是否平衡,则对于每个节点findDeepth只会被调用一次。

整体思路如下

  1. 后序遍历要判断的二叉树
  2. 看其左子节点是否为平衡二叉树,若平衡则再看右节点是否为平衡二叉树。若都是平衡的则当前节点也是平衡的,否则不平衡。
  3. 对于不平衡的节点我们直接返回-1,对于平衡的节点我们返回对应的深度deepth >=0
  4. 我们只需要判断最后的findDeepth返回的结果是否是-1即可。

代码如下

/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isBalanced = function(root) {
    return findDeepth2(root) !== -1;

};
function findDeepth2(root) {
    if(!root) return 0;
    if(!root.left && !root.right) return 1;
    const left = findDeepth2(root.left);
  	if(left ===-1) return -1;
    const right = findDeepth2(root.right);
    if(right === -1) return -1;
    if(Math.abs(left - right) <=1) return Math.max(left, right) +1;
    return -1;
}

这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。