高频算法面试题(三十四)- 平衡二叉树

「这是我参与11月更文挑战的第 19 天,活动详情查看:2021最后一次更文挑战

刷算法题,从来不是为了记题,而是练习把实际的问题抽象成具体的数据结构或算法模型,然后利用对应的数据结构或算法模型来进行解题。个人觉得,带着这种思维刷题,不仅能解决面试问题,也能更多的学会在日常工作中思考,如何将实际的场景抽象成相应的算法模型,从而提高代码的质量和性能

平衡二叉树

题目来源LeetCode-110. 平衡二叉树

题目描述

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

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

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

示例

示例 1

1.png

输入:root = [3,9,20,null,null,15,7]
输出:true
复制代码

示例 2

2.png

输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
复制代码

示例 3

输入:root = []
输出:true
复制代码

提示:

  • 树中的节点数在范围 [0, 5000] 内
  • 10^4 <= Node.val <= 10^4

解题

解法一:递归:自顶向下的递归

思路

其实这道题的核心就是求二叉树中任意一个结点的高度,只要知道了任意结点的高度,就可以知道这棵二叉树是否平衡

其实常规的思维,最容易想到的思路是,我求出二叉树的最大高度,然后再求出二叉树的最小高度。然后计算他们的差值,跟1进行比较就可以了。其实这样也能实现,只是求最小高度,稍微麻烦点

其实二叉树的题,最长用到递归,而递归在树中的应用往往又比较抽象,但是用递归实现,代码却很简单。刚开始可能很简单的题,都不知道怎么用递归来实现,其实个人感觉这很正常。把LeetCode的前300道算法题里边的二叉树的题都做一遍,看十几分钟没思路就看答案,然后不看答案自己实现一遍。然后做一下总结,慢慢就有感觉了

假设有一个结点p,如果它是空的,高度就是0,如果非空,那它的高度就是左右子树高度的最大值。这应该很容易想到用递归吧,除了规模在边,求解的思路没变,很容易想到用递归。要求当前结点的高度,需要先求左右子树的高度,左右子树的高度求法跟求当前结点的高度思路是一样的。终止条件是左右子树为空了,则高度是0。所以可以写出一个求高度的方法

func height(root *TreeNode) int {
	if root == nil {
		return 0
	}

	return max(height(root.Left), height(root.Right)) + 1 //每往下遍历一层就+1
}

func max(x, y int) int {
	if x > y {
		return x
	}

	return y
}
复制代码

剩余部分的实现,就像二叉树的前序遍历,遍历到当前结点,计算左右子树的高度,看左右子树高度差是否大于1。然后分别遍历左右子树,重复上边的步骤(代码很容易理解,直接看代码)

代码实现上,主要还是首先分析出递归公式

代码

//判断平衡二叉树
func isBalanced(root *TreeNode) bool {
	if root == nil {
		return true
	}

	return abs(height(root.Left) - height(root.Right)) <= 1 && isBalanced(root.Left) && isBalanced(root.Right) //先看以当前节点为根节点的树高度差,再分别判断左右子节点为根节点的左右子树的高度差
}

func height(root *TreeNode) int {
	if root == nil {
		return 0
	}

	return max(height(root.Left), height(root.Right)) + 1 //每往下遍历一层就+1
}

func max(x, y int) int {
	if x > y {
		return x
	}

	return y
}

func abs(x int) int {
	if x < 0 {
		return -1 * x
	}

	return x
}
复制代码

解法二:递归:自底向上的递归

思路

自底向上递归的做法类似于后序遍历,对于当前遍历到的节点,先递归地判断其左右子树是否平衡,

再判断以当前节点为根的子树是否平衡。如果一棵子树是平衡的,则返回其高度(高度一定是非负整

数),否则返回 -1。如果存在一棵子树不平衡,则整个二叉树一定不平衡

代码

func isBalanced2(root *TreeNode) bool {
	return height2(root) >= 0
}

func height2(root *TreeNode) int {
	if root == nil {
		return 0
	}
	leftHeight := height(root.Left)
	rightHeight := height(root.Right)
	if leftHeight == -1 || rightHeight == -1 || abs(leftHeight - rightHeight) > 1 {
		return -1
	}
	return max(leftHeight, rightHeight) + 1
}

func max(x, y int) int {
	if x > y {
		return x
	}

	return y
}

func abs(x int) int {
	if x < 0 {
		return -1 * x
	}

	return x
}
复制代码

参考

LeetCode官方题解-平衡二叉树

猜你喜欢

转载自juejin.im/post/7032068861293756424
今日推荐