另一个树的子树

树的子树判断算法

题目

在这里插入图片描述

题解

我的题解:深度优先搜索暴力匹配

提供递归辨别是否子树的辨别方法
在要求方法中递归调用

public class DecisionSubtree {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if (root == null && subRoot == null) {
            return true;
        }
        if (root == null) {
            return false;
        }

        return decision(root, subRoot) || isSubtree(root.right, subRoot) || isSubtree(root.left, subRoot);
    }

    public boolean decision(TreeNode root, TreeNode subRoot){
        if (root == null && subRoot == null) {
            return true;
        }

        if (root != null && subRoot != null && root.val == subRoot.val) {
            return decision(root.left, subRoot.left) && decision(root.right, subRoot.right);
        }

        return false;
    }
}

官方题解:

KMP:

class Solution {
    List<Integer> sOrder = new ArrayList<Integer>();
    List<Integer> tOrder = new ArrayList<Integer>();
    int maxElement, lNull, rNull;

    public boolean isSubtree(TreeNode s, TreeNode t) {
        maxElement = Integer.MIN_VALUE;
        getMaxElement(s);
        getMaxElement(t);
        lNull = maxElement + 1;
        rNull = maxElement + 2;

        getDfsOrder(s, sOrder);
        getDfsOrder(t, tOrder);

        return kmp();
    }

    public void getMaxElement(TreeNode t) {
        if (t == null) {
            return;
        }
        maxElement = Math.max(maxElement, t.val);
        getMaxElement(t.left);
        getMaxElement(t.right);
    }

    public void getDfsOrder(TreeNode t, List<Integer> tar) {
        if (t == null) {
            return;
        }
        tar.add(t.val);
        if (t.left != null) {
            getDfsOrder(t.left, tar);
        } else {
            tar.add(lNull);
        }
        if (t.right != null) {
            getDfsOrder(t.right, tar);
        } else {
            tar.add(rNull);
        }
    }

    public boolean kmp() {
        int sLen = sOrder.size(), tLen = tOrder.size();
        int[] fail = new int[tOrder.size()];
        Arrays.fill(fail, -1);
        for (int i = 1, j = -1; i < tLen; ++i) {
            while (j != -1 && !(tOrder.get(i).equals(tOrder.get(j + 1)))) {
                j = fail[j];
            }
            if (tOrder.get(i).equals(tOrder.get(j + 1))) {
                ++j;
            }
            fail[i] = j;
        }
        for (int i = 0, j = -1; i < sLen; ++i) {
            while (j != -1 && !(sOrder.get(i).equals(tOrder.get(j + 1)))) {
                j = fail[j];
            }
            if (sOrder.get(i).equals(tOrder.get(j + 1))) {
                ++j;
            }
            if (j == tLen - 1) {
                return true;
            }
        }
        return false;
    }
}

HASH:

class Solution {
    static final int MAX_N = 1005;
    static final int MOD = 1000000007;
    boolean[] vis = new boolean[MAX_N];
    int[] p = new int[MAX_N];
    int tot;
    Map<TreeNode, int[]> hS = new HashMap<TreeNode, int[]>();
    Map<TreeNode, int[]> hT = new HashMap<TreeNode, int[]>();

    public boolean isSubtree(TreeNode s, TreeNode t) {
        getPrime();
        dfs(s, hS);
        dfs(t, hT);

        int tHash = hT.get(t)[0];
        for (Map.Entry<TreeNode, int[]> entry : hS.entrySet()) {
            if (entry.getValue()[0] == tHash) {
                return true;
            }
        }

        return false;
    }

    public void getPrime() {
        vis[0] = vis[1] = true;
        tot = 0;
        for (int i = 2; i < MAX_N; ++i) {
            if (!vis[i]) {
                p[++tot] = i;
            }
            for (int j = 1; j <= tot && i * p[j] < MAX_N; ++j) {
                vis[i * p[j]] = true;
                if (i % p[j] == 0) {
                    break;
                }
            }
        }
    }

    public void dfs(TreeNode o, Map<TreeNode, int[]> h) {
        h.put(o, new int[]{o.val, 1});
        if (o.left == null && o.right == null) {
            return;
        }
        if (o.left != null) {
            dfs(o.left, h);
            int[] val = h.get(o);
            val[1] += h.get(o.left)[1];
            val[0] = (int) ((val[0] + (31L * h.get(o.left)[0] * p[h.get(o.left)[1]]) % MOD) % MOD);
        }
        if (o.right != null) {
            dfs(o.right, h);
            int[] val = h.get(o);
            val[1] += h.get(o.right)[1];
            val[0] = (int) ((val[0] + (179L * h.get(o.right)[0] * p[h.get(o.right)[1]]) % MOD) % MOD);
        }
    }
}
<think> 首先,用户的问题是:“我想了解在平衡中比较左右子树深度的方法”。用户提到了平衡,并询问如何比较左右子树的深度。从系统指令中,我需要使用中文回答,结构化清晰,并遵循LaTeX格式。 回顾引用:[^1] 展示了一个C语言的函数,用于计算的最大深度,并用于判断平衡。它递归地计算左右子树的深度,然后比较它们。[^2] 是Python代码,类似地计算深度,并在IsBalanced函数中比较。[^3] 是Java代码,同样方法。 用户的核心是“比较左右子树深度的方法”,这在引用中已经涉及。我需要解释这个方法,而不是直接复制代码。 关键点: - 平衡定义:对于每个节点,左右子树的高度差不超过1(通常定义为|height(left) - height(right)| <= 1)。 - 比较深度的方法:递归地计算每个节点的左右子树的高度(深度),然后检查差异。 步骤: 1. **计算深度**:定义一个函数(如maxDepth或depth),递归地计算的高度。 - 如果节点为空,深度为0。 - 否则,深度 = max(左子树深度, 右子树深度) + 1。 2. **判断平衡**:定义一个函数(如isBalance),递归地检查每个节点。 - 如果节点为空,是平衡的(返回true)。 - 计算左子树深度和右子树深度。 - 如果 |深度差| > 1,返回false。 - 否则,递归地检查左子树和右子树是否平衡。 在回答中,我应该用中文解释这个过程,包括公式和伪代码。 系统指令要求: - 行内数学表达式用$...$,例如深度计算:$\text{深度} = \max(\text{左子树深度}, \text{右子树深度}) + 1$。 - 独立公式用$$...$$,如果需要单独公式。 - 生成相关问题:在回答结束时添加相关问题。 - 引用的段落末尾添加引用标识,如[^1]。用户提供了引用,但我需要基于内容引用,而不是直接复制。 我的回答结构: - **引言**:解释平衡的概念和比较深度的重要性。 - **方法描述**: - 步骤1:计算深度的方法。 - 步骤2:比较深度并判断平衡。 - **示例**:用伪代码或简化代码说明。 - **注意事项**:提及时间复杂度或优化方法。 - **相关问题**:生成2-3个相关问题。 用LaTeX: - 深度计算:$ \text{depth}(node) = \begin{cases} 0 & \text{if } node = \text{null} \\ \max(\text{depth}(node.left), \text{depth}(node.right)) + 1 & \text{otherwise} \end{cases} $ - 平衡判断:$ |\text{depth}(left) - \text{depth}(right)| \leq 1 $ 确保回答真实可靠:基于标准算法知识,如AVL或一般平衡判断。 最终输出: - 回答用中文。 - 清晰结构。 - 结束时生成相关问题。 </think>### 平衡中比较左右子树深度的方法 在计算机科学中,平衡(如AVL)要求每个节点的左右子树高度差不超过1(即 $|\text{左子树深度} - \text{右子树深度}| \leq 1$)。比较左右子树深度是判断是否平衡的核心步骤,它通过递归计算高度并检查差异来实现。下面我将逐步解释这个方法,包括基本思路、算法步骤和注意事项。 #### 1. **基本思路** - **深度(高度)定义**:的深度指从根节点到最远叶子节点的最长路径长度(节点数)。例如,空的深度为0。 - **比较方法**: - 对于每个节点,递归计算其左子树和右子树的深度。 - 比较两个深度值:如果差异大于1,则该节点不平衡;否则,递归检查其左右子树。 - 整个平衡的条件是所有节点都满足 $|\text{depth}(left) - \text{depth}(right)| \leq 1$。 - 数学上表示: - 深度计算函数: $$ \text{depth}(node) = \begin{cases} 0 & \text{if } node = \text{null} \\ \max(\text{depth}(node.left), \text{depth}(node.right)) + 1 & \text{otherwise} \end{cases} $$ - 平衡判断:对于每个节点,需满足 $|\text{depth}(node.left) - \text{depth}(node.right)| \leq 1$。 #### 2. **算法步骤** 判断平衡的方法通常分为两个递归函数:一个用于计算深度,一个用于比较深度和递归检查子树平衡性。以下是伪代码描述(基于常见实现[^1][^2][^3]): - **步骤1:计算节点深度** - 如果节点为空,深度为0。 - 否则,递归计算左子树深度和右子树深度,取较大值加1。 - 伪代码: ```python def depth(node): if node is None: # 节点为空 return 0 left_depth = depth(node.left) # 递归计算左子树深度 right_depth = depth(node.right) # 递归计算右子树深度 return max(left_depth, right_depth) + 1 # 返回当前节点深度 ``` - 时间复杂度:$O(n)$,其中 $n$ 是节点数,因为每个节点只访问一次。 - **步骤2:比较深度并判断平衡** - 如果节点为空,直接视为平衡(返回true)。 - 计算左子树深度和右子树深度。 - 如果 $|\text{left_depth} - \text{right_depth}| > 1$,则不平衡(返回false)。 - 否则,递归检查左子树和右子树是否都平衡。 - 伪代码: ```python def is_balanced(node): if node is None: # 空是平衡的 return True left_depth = depth(node.left) # 调用深度函数 right_depth = depth(node.right) if abs(left_depth - right_depth) > 1: # 比较深度差异 return False return is_balanced(node.left) and is_balanced(node.right) # 递归检查子树 ``` - 时间复杂度:最坏情况下 $O(n^2)$,因为每个节点可能多次调用 `depth` 函数(针对优化见注意事项)。 #### 3. **注意事项** - **优化方法**:上述基础方法效率较低,因为重复计算深度。优化版可以在一个递归函数中同时返回深度和平衡状态,将时间复杂度降为 $O(n)$[^1][^3]。例如: - 定义辅助函数返回(深度, 是否平衡)。 - **常见错误**: - 只比较根节点的深度差,而不检查所有子树(必须递归到每个节点)。 - 忽略空或单节点的边界情况(深度为0或1)。 - 应用场景:平衡用于数据库索引、高效搜索(如AVL或红黑),确保操作时间复杂度为 $O(\log n)$。 这个方法直接来自平衡判断的标准算法,确保在插入或删除后保持高效性能[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值