【剑指Offer】树的子结构

本文介绍了一种判断一棵二叉树是否为另一棵二叉树的子结构的方法。通过输入两棵树的前序和中序遍历序列,构建二叉树并进行子结构判断。文章详细展示了构建过程及判断逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

树的子结构

题目:输入两棵二叉树A和B,判断B是不是A的子结构。

第一步:在树A中找到和树B的根节点的值一样的节点R;

第二步:判断树A中以R为根节点的子树是不是包含和树B一样的结构。

这里,我们通过输入树的前序遍历和中序遍历构建二叉树,然后判断树的子结构,代码如下:

package jianzhioffer;

import java.util.Scanner;

/**
 * 剑指Offer:树的子结构
 */
public class HasSubtree {
    //定义二叉树节点
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode righe = null;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    //根据前序遍历和中序遍历重建二叉树,并返回二叉树的根节点
    public BinaryTreeNode reConstructBinaryTree(int[] pre, int[] in) {
        if (pre.length == 0 || in.length == 0) {
            return null;
        }
        BinaryTreeNode node = binaryTreeReconstruct(pre, 0, pre.length - 1, in, 0, in.length - 1);
        return node;
    }

    //使用递归重构二叉树
    private BinaryTreeNode binaryTreeReconstruct(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn) {
        if (startIn > endIn || startPre > endPre)
            return null;
        BinaryTreeNode node = new BinaryTreeNode(pre[startPre]);
        for (int i = startIn; i <= endIn; i++) {
            if (in[i] == pre[startPre]) {
                node.left = binaryTreeReconstruct(pre, startPre + 1, startPre + i - startIn, in, startIn, i - 1);
                node.right = binaryTreeReconstruct(pre, i - startIn + startPre + 1, endPre, in, i + 1, endIn);
            }
        }
        return node;
    }

    /**
     * 在树1中查找与根节点的值一样的节点
     *
     * @param root1
     * @param root2
     * @return
     */
    private static boolean hasSubtree(BinaryTreeNode root1, BinaryTreeNode root2) {
        boolean result = false;
        if (root1 != null && root2 != null) {
            if (Equal(root1.val, root2.val))
                result = DoesTree1HaveTree2(root1, root2);
            if (!result)
                result = hasSubtree(root1.left, root2);
            if (!result)
                result = hasSubtree(root1.right, root2);
        }
        return result;
    }

    /**
     * 判断树1中以R为根节点的子树是不是和树2具有相同的结构
     *
     * @param root1
     * @param root2
     * @return
     */
    private static boolean DoesTree1HaveTree2(BinaryTreeNode root1, BinaryTreeNode root2) {
        if (root2 == null)
            return true;
        if (root1 == null&&root2!=null)
            return false;
        if (!Equal(root1.val, root2.val))
            return false;
        return DoesTree1HaveTree2(root1.left, root2.left) && DoesTree1HaveTree2(root1.right, root2.right);
    }

    /**
     * 判断两个数是否相等
     * 当计算机表示小数时,会存在一定范围的误差,如果其绝对值小于某一阈值,则认为它们相等
     *
     * @param num1
     * @param num2
     * @return
     */
    private static boolean Equal(int num1, int num2) {
        if (num1 - num2 > -0.0000001 && num1 - num2 < 0.0000001)
            return true;
        else
            return false;
    }

    //创建两个整型数组
    public static int[] nodeProcess(String[] array) {
        int[] num = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            num[i] = Integer.parseInt(array[i]);
        }
        return num;
    }

    /**
     * 主函数
     * 输入四行
     * 前两行分别表示树1的前序遍历和中序遍历
     * 后两行分别表示树2的前序遍历和中序遍历
     *
     * @param args
     */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String[] preStr_1 = sc.nextLine().split(",");
            String[] inStr_1 = sc.nextLine().split(",");
            int[] pre_1 = nodeProcess(preStr_1);
            int[] in_1 = nodeProcess(inStr_1);

            String[] preStr_2 = sc.nextLine().split(",");
            String[] inStr_2 = sc.nextLine().split(",");
            int[] pre_2 = nodeProcess(preStr_2);
            int[] in_2 = nodeProcess(inStr_2);

            HasSubtree hst = new HasSubtree();
            BinaryTreeNode root1 = hst.reConstructBinaryTree(pre_1, in_1);
            BinaryTreeNode root2 = hst.reConstructBinaryTree(pre_2, in_2);
            boolean result = hasSubtree(root1, root2);
            System.out.println(result);
        }
        sc.close();
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

镰刀韭菜

看在我不断努力的份上,支持我吧

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

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

打赏作者

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

抵扣说明:

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

余额充值