【数据结构二叉树OJ系列】6、平衡二叉树

 【数据结构二叉树OJ系列】6、平衡二叉树_第1张图片

目录

题述:

思路:

 正确代码如下:

时间复杂度分析:

现让你把代码优化时间复杂度为O(N)

思路:


题述:

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

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

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

示例1:

【数据结构二叉树OJ系列】6、平衡二叉树_第2张图片

输入:root = 【3,9,20,NULL,NULL,15,7】

输出:true

 题中已给:

struct TreeNode
{
	int val;
	struct TreeNode* left;
	struct TreeNode* right;
};

bool isBalanced(struct TreeNode* root)

思路:

利用之前讲过的求树的深度的函数TreeDepth来求解这道题,根,左子树,右子树不断往下遍历,左子树又分为根,左子树,右子树,右子树又分为根,左子树,右子树直到遇到空树,对于每一个树都求一下左右子树的深度,然后判断一下树的高度差的绝对值是否>1,>1则不满足,<1则继续递归遍历,直到整棵树判断完毕,才可确定是平衡二叉树整体思路类似于根左右,即先判断当前树,再判断左子树,再判断右子树

 正确代码如下:


int TreeDepth(struct TreeNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	int leftDepth = TreeDepth(root->left);
	int rightDepth = TreeDepth(root->right);

	return leftDepth > rightDepth ? leftDepth + 1
		: rightDepth + 1;
}

bool isBalanced(struct TreeNode* root)
{
    //空树满足平衡二叉树的定义
	if (root == NULL)
	{
		return true;
	}
    
    //先判断当前树是否满足
	int gap = TreeDepth(root->left) - TreeDepth(root->right);
	gap = abs(gap);//取绝对值

	if (gap > 1)
	{
		return false;
	}
    //再判断左右子树是否满足
	return isBalanced(root->left)
		&& isBalanced(root->right);
}

时间复杂度分析:

假设该二叉树有N个结点。

TreeDepth函数是把整个二叉树遍历了一遍,故时间复杂度:O(N)

对于isBalanced函数,它的遍历是根左右,下面给个二叉树方便说明这个问题

【数据结构二叉树OJ系列】6、平衡二叉树_第3张图片

①、先会判断当前树(以3为根节点的树)左右深度的差的绝对值,这一次就遍历了一遍树,

②、再判断3的左子树(以9为根节点的树)左右深度的差的绝对值,即以9为根节点的左右子树的高度要再求一遍,为什么是“再”?求以3为根节点的左子树的深度时,已算过以9为根结点的树的深度了,故用先序遍历存在重复的深度计算。

时间复杂度以3为根节点为N次,以其它节点为根节点均为N-常数次,总的时间复杂度加起来大概可以构成等差数列(N+N-常数+N-常数...而N-常数的他们一组合,我们可近似为等差数列),由等差数列前n项和公式:

N(N+N-常数) / 2 = O(N*N)

现让你把代码优化时间复杂度为O(N)

思路:

上一种思路就慢在树的深度的重复计算,我们只要让树的深度算一遍就可以使时间复杂度优化到O(N)了,怎么做到深度只算一遍?即利用后序遍历:左右根,先判断左子树再判断右子树最后再判断当前树。我们不调用TreeDepth函数(你要调用它还会跟上面思路一样的时间消耗),而是每次在判断是否是平衡二叉树的同时,返回当前树的深度给上层(递归往回返的过程)。那就意味着深度和是否为平衡二叉树(返回真假)每次都要返回,法一:考虑返回结构体,结构体包含这两个。法二:参数传深度的地址,每次调用在需要改的时候改,函数返回真假。

大体思路:

1、深度和判断是否为平衡二叉树同时进行

2、先判断是否为平衡二叉树,满足才会计算深度,求的是当前树的深度,对于左右子树,是来判断是否为平衡二叉树

3、不满足就直接return false

bool isBalanced(struct TreeNode* root, int * depth)
{
	//如果为空树
	if (root == NULL)
	{
		*depth = 0;
		return true;
	}

	//先判断左子树
	int leftdepth = 0;
	if (isBalanced(root->left, &leftdepth) == false)
		return false;
	int rightdepth = 0;
	if (isBalanced(root->right, &rightdepth) == false)
		return false;
	//再判断当前树,当前树是否满足平衡二叉树,看左右子树高度差的绝对值是否>1
	if (abs(leftdepth - rightdepth) > 1)
		return false;
	//左右子树,当前树都满足平衡二叉树的前提下才计算深度并返回true
	*depth = leftdepth > rightdepth ? leftdepth + 1
		: rightdepth + 1;
	return true;

}

 【数据结构二叉树OJ系列】6、平衡二叉树_第4张图片

 以此二叉树为例,上述代码的执行过程如下:

①、root=3时,判断左子树,转为root=9,判断左子树,左子树为NULL,故9的左子树深度为0,return true,同理9的右子树深度为0,return true。再判断以9为根节点的当前树,深度差不>1,故高度为0+1=1,return true,至此算出以9为根节点的深度为1,并判断为满足平衡二叉树。

②、再判断root=3时的右子树,转为root=20,判断左子树,转为root=15,判断它的左子树, 为NULL,故15的左子树深度为0,return true,同理,15的右子树的深度为0,return true。再判断以15为根节点的当前树,深度差不>1,故高度为0+1=1,return true,至此算出以15为根节点的深度为1,并判断为满足平衡二叉树。

③、再判断20的右子树,同理上面,以7为根节点的深度为1,并判断为满足平衡二叉树。至此,20的左右子树判断完毕,再判断以20为根节点的当前树,深度差不>1,故深度为1+1=2,return true,至此算出以20为根节点的深度为2,并判断为满足平衡二叉树。

④、至此3的左右子树判断完毕,再判断以3为根节点的当前树,深度差不>1,故深度为2+1=3,return true,至此算出以3为根节点的深度为3,并判断整棵树满足平衡二叉树。

你可能感兴趣的:(【数据结构】知识篇+代码讲解,数据结构,算法)