算法通关村——轻松搞定树的深度和高度问题

树中的深度和高度问题

1、树的深度和高度的定义

  • 节点ni的深度:从根节点到ni的唯一路径长。即,节点ni所在的层次(根节点为0层),树的深度=树中节点的最大层次

  • 节点ni的高度:从ni到一片树叶的最长路径长。即,叶子节点的高度为0,树的高度 = 根的高度。

    注意,在高度与深度的计算中,leetcode中都是以节点为1度,但是维基百科上是以边为1度,本篇以leetcode为准,用节点数来计算树的深度与高度。

图示如下:

二叉树的深度和高度

2、最大深度问题

​ LeetCode104. 给定一个二叉树,找出其最大深度。

​ 我们先来看一个简单情况:

921a584ac5b9fca176bdaef9356cab43

​ 对于node(3),最大深度自然是左右子节点+1,左右子节点有的可能为空,只要有一个,树的最大高度就是1+1=2。

​ 然后再增加几个节点:

c2be44491ec656bc3e5708ea4817fb80

​ 很显然相对于node(20),最大深度自然是左右子节点+1,左右子节点有的可能为空,只要有一个,树的最大高度就是1+1=2,用代码表示就是:

int depth = 1 + max(leftDepth,rightDepth)

​ 而对于3,则是左右子树深度最大的那个然后再+1,具体谁更大,则不必关心。所以对于node(3)的判断逻辑是:

int leftDepth = getDepth(node.left);  //左
int rightDepth = getDepth(node.right);//右
int depth = 1 + max(leftDepth, rightDepth); //中

​ 那什么时候结束呢,这里仍然是root == null返回0就行了,组合在一起就是下面的代码:

public int maxDepth(TreeNode root) {
	int (root == null){
        return 0;
    }
    int leftHeight = maxDepth(root.left);
    int rightHeight = maxDepth(root.right);
    return Math.max(leftHeight, rightHeight) + 1;
}

3、判断平衡树

​ LeetCode110. 判断平衡二叉树:给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。

​ 仍然从最简单的情况来分析:

921a584ac5b9fca176bdaef9356cab43

​ 很显然只有两层的时候一定是平衡的,因为对于node(3),左右孩子如果只有一个,那高度差就是1;如果左右子孩子都有或者都没有,则高度差为0。再来看看增加一层的情况:

c2be44491ec656bc3e5708ea4817fb80

​ 对于node(3),需要同时知道自己左右子树的最大高度差是否小于2。

​ 当节点root 左/右子树的高度差<2,则返回节点root的左右子树中最大高度加1。

​ 当节点root 左/右子树的高度差>2,则返回-1,代表此子树不是平衡树。

​ 也就是:

int left = recur(root.left);
int right = recur(root.right);
return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1;

​ 假如子树已经不平衡了,则不需要再递归了直接返回就行,比如这个树中节点4

10b973084aff566ed37d896847ced818

​ 具体的代码如下:

class Solution {
	public boolean isBalanced(TreeNode root) {
		return height(root) >= 0;
	}
    
    public int height(TreeNode root){
        if (root == null) {
            return 0;
        }
        int leftHeight = height(root.left);
        int rightHeight = height(root.right);
        if(leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {
            return -1;
        } else {
            return Math.max(leftHeight, rightHeight) + 1;
        }
    }   
}

4、最小深度

​ LeetCode111. 给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量,例如下面的例子返回结果为2。

​ **说明:**叶子节点是指没有子节点的节点

6e9e10a3fe93b337199835f139226a9f

​ 这题的关键是最小深度的一层必须有叶子节点,因此不能直接将前两题的Max改成Min,要重新分析终止条件

​ 如果左子树为空,右子树不为空,说明最小深度是1+右子树的深度

​ 反之,右子树为空,左子树不为空,说明最小深度是1+左子树的深度

​ 最后如果左右子树都不为空,返回左右子树深度最小值+1。

​ 具体代码如下:

public int minDepth(TreeNode root){
    if (root == null){
        return 0;
    }
    
    if (root.left == null && root.right == null){
        return 1;
    }
    
    int min_depth = Integer.MAX_VALUE;
    if (root.left != null) {
        min_depth = Math.min(minDepth(root.left), min_depth);
    }
    if (root.right != null) {
        min_depth = Math.min(minDepth(root.right), min_depth);
    }
    
    return min_depth + 1;
}
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 卫兵布置问题是指在一个 $n\times m$ 的矩阵中,放置若干个卫兵,使得每行和每列都至少有一个卫兵,并且卫兵之间不能相互攻击,即同行、同列或同一对角线上不能有两个及以上的卫兵。求解放置卫兵的方案数。 这个问题可以用搜索算法来解决。我们可以用一个二维数组 $board$ 来表示矩阵,其中 $board_{i,j}=1$ 表示该位置已经放置了卫兵,$board_{i,j}=0$ 表示该位置还没有放置卫兵。我们可以从第一行开始,枚举每个位置放置卫兵或不放置卫兵,然后递归到下一行,直到最后一行。如果在最后一行放置了卫兵,那么我们就找到了一个合法的方案;否则,我们就需要回溯到上一行,重新枚举该行的下一个位置。 具体实现细节可以参考下面的代码: ### 回答2: 卫兵布置问题是一个典型的算法程序设计问题,通常是在一定区域内布置一定数量的卫兵,使得每个区域都能够被卫兵所覆盖。 首先,我们可以采用贪心算法来解决这个问题。贪心算法的基本思想是,每次都选择当前情况下最优解,以期望得到全局最优解。 具体实现上,可以按照以下步骤进行: 1. 将要布置的区域按照一定的规则排序,比如按照面积从大到小排序。 2. 选择第一个区域进行布置,将一个卫兵放置在这个区域的中心位置。 3. 从第二个区域开始,遍历每个区域,如果该区域与已布置的卫兵的覆盖区域没有交集,则在该区域的中心位置再放置一个卫兵。 4. 不断循环3,直至所有的区域都被遍历完毕。 贪心算法的时间复杂度为O(nlogn),其中n为区域的个数。该算法保证了每个区域都能够被卫兵覆盖,但并不能保证卫兵的数量最少。 如果需要保证卫兵的数量最少,我们可以使用更复杂的算法,比如动态规划算法。动态规划算法通常包含以下几个步骤: 1. 定义状态:设f(i)表示前i个区域所需要的最少卫兵数量。 2. 初始化状态:f(1)为1,即第一个区域需要一个卫兵。 3. 状态转移方程:f(i) = min{f(j) + 1},其中j < i且第j个区域的覆盖范围可以覆盖第i个区域。 4. 求解最优解:最后返回f(n)即为最终结果。 动态规划算法的时间复杂度为O(n^2),需要使用一个数组来保存中间结果。这种算法能够保证卫兵的数量最少,但相对于贪心算法来说更加复杂一些。 综上所述,卫兵布置问题算法程序设计中可以采用贪心算法或动态规划算法来求解,具体的选择取决于问题的要求和时间复杂度的需求。 ### 回答3: 卫兵布置问题是指如何在给定的一组区域中,安排卫兵的位置,以实现最佳的防御效果。 解决卫兵布置问题算法程序设计可以采用以下步骤: 首先,需要分析给定的区域,了解每个区域的特点和可能的入侵路径。可以将区域抽象为一个二维矩阵,每个位置表示一个区域。 其次,确定卫兵的数量和他们的限制条件。这包括卫兵的总数目、布置的范围以及相邻卫兵之间的最小距离等。 接下来,根据防御策略设计相应的算法。一种常见的算法是贪婪算法,即每次选择一个最优的位置来布置卫兵,直到卫兵数量达到要求或不能再继续放置为止。该算法可以根据区域的特点和入侵路线来选择最佳的位置。另一种常用的算法是回溯算法,通过递归地尝试不同的布置方式,找到最佳的卫兵布置方案。 最后,实现并测试设计好的算法。可以根据给定区域的大小和要求的卫兵数量来生成测试样例,并通过结果验证算法的正确性和有效性。 总之,卫兵布置问题是一种优化问题,需要通过谨慎的分析和设计来找到最佳的解决方案。算法程序设计可以通过贪婪算法、回溯算法等方法来解决此类问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Molche

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值