阿翰 剑指offer 之 Day 18 搜索与回溯算法 中等

本文详细介绍了两种计算二叉树深度的方法——深度优先搜索(DFS)和广度优先搜索(BFS),并给出了具体的Java实现。同时,针对平衡二叉树的深度计算,讨论了自顶向下和自底向上的递归策略,分析了时间与空间复杂度。这些算法对于理解和解决二叉树问题至关重要。
摘要由CSDN通过智能技术生成

目录

搜索与回溯算法

1 二叉树的深度

1.  DFS

1.2 递归改进(DFS)

2. BFS

 2 平衡二叉树的深度

1. 自顶向下的递归

2. 自底向上的递归


搜索与回溯算法

1 二叉树的深度

剑指 Offer 55 - I. 二叉树的深度https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/

1.  DFS

class Solution {
    int depth = 0;
    int res = Integer.MIN_VALUE;
    public int maxDepth(TreeNode root) {
        if(root == null)    return 0;
        depth++;
        maxDepth(root.left);
        res = Math.max(depth, res);
        maxDepth(root.right);
        depth--;
        return res;
    }
}

1.2 递归改进(DFS)

class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null)
            return 0;
        else
            return Math.max(maxDepth(root.left), maxDepth(root.right))+1;
    }
}

复杂度分析:

  • 时间复杂度 O(N) : N 为树的节点数量,计算树的深度需要遍历所有节点。
  • 空间复杂度 O(N) : 最差情况下(当树退化为链表时),递归深度可达到 N 。

2. BFS

  • 树的层序遍历 / 广度优先搜索往往利用 队列 实现。

  • 关键点: 每遍历一层,则计数器 +1+1 ,直到遍历完成,则可得到树的深度。

class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) return 0;
        List<TreeNode> queue = new LinkedList<TreeNode>() {{ add(root); }}, tmp;
        int res = 0;
        while(!queue.isEmpty()) {
            tmp = new LinkedList<>();
            for(TreeNode node : queue) {
                if(node.left != null) tmp.add(node.left);
                if(node.right != null) tmp.add(node.right);
            }
            queue = tmp;
            res++;
        }
        return res;
    }
}

复杂度分析:

  • 时间复杂度 O(N): N 为树的节点数量,计算树的深度需要遍历所有节点。
  • 空间复杂度 O(N): 最差情况下(当树平衡时),队列 queue 同时存储 N/2 个节点。

 2 平衡二叉树的深度

剑指 Offer 55 - II. 平衡二叉树https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof/

1. 自顶向下的递归

定义函数 height,用于计算二叉树中的任意一个节点的高度.

判断二叉树是否平衡。具体做法类似于二叉树的前序遍历,即对于当前遍历到的节点,首先计算左右子树的高度,如果左右子树的高度差是否不超过 1,再分别递归地遍历左右子节点,并判断左子树和右子树是否平衡。这是一个自顶向下的递归的过程。 

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

2. 自底向上的递归

方法一由于是自顶向下递归,因此对于同一个节点,函数 height 会被重复调用,导致时间复杂度较高。如果使用自底向上的做法,则对于每个节点,函数 \texttt{height}height 只会被调用一次。

自底向上递归的做法类似于后序遍历,对于当前遍历到的节点,先递归地判断其左右子树是否平衡,再判断以当前节点为根的子树是否平衡。如果一棵子树是平衡的,则返回其高度(高度一定是非负整数),否则返回 -1−1。如果存在一棵子树不平衡,则整个二叉树一定不平衡。 

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;
        }
    }
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是二叉树中的节点个数。使用自底向上的递归,每个节点的计算高度和判断是否平衡都只需要处理一次,最坏情况下需要遍历二叉树中的所有节点,因此时间复杂度是 O(n)。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值