剑指offer刷题总结——树篇(一)

154 篇文章 5 订阅
43 篇文章 2 订阅

星级:2

1.重建二叉树

【题目】

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列 {1,2,4,7,3,5,6,8} 和中序遍历序列 {4,7,2,1,5,3,8,6},则重建二叉树并返回。

【代码】

package swear2offer.tree;

public class ReCreateTree {

    /**
     * 前序遍历序列 {1,2,4,7,3,5,6,8}
     * 中序遍历序列 {4,7,2,1,5,3,8,6}
     *
     * 思路:
     * 需要考虑递归的方式,本身树这一结构就很适合进行递归
     * 前序是 根、左、右
     * 中序是 左、右、根
     * 然后用递归的方式把左右节点放置在根节点之下
     * */
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {

        return CreateTree(pre,0, pre.length,in,0,in.length);
    }

    public TreeNode CreateTree(int[] pre, int pStart,int pEnd,int[] in,int iStart,int iEnd) {

        if (pStart>pEnd || iStart>iEnd ) return null;

        if (pStart>=pre.length|| iStart>=in.length) return null;

        int rootIndex,leftSize,rightSize;

        TreeNode root = new TreeNode(pre[pStart]);

        // 根节点在中序序列的下标
        rootIndex = GetIndex(in,root.val);

        // 左子树长度
        leftSize = rootIndex - iStart;
        // 右子树长度
        rightSize = iEnd - rootIndex;

        // 左子树
        root.left = CreateTree(pre,pStart+1,pStart+leftSize,
                        in,iStart,rootIndex-1);
        // 右子树
        root.right = CreateTree(pre,pStart+leftSize+1,pEnd,
                in,rootIndex+1,iEnd);

        return root;
    }

    public int GetIndex(int[] a, int target) {

        for(int i=0; i<a.length; i++) {
            if (a[i] == target) {
                return i;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] pre = {1,2,4,7,3,5,6,8};
        int[] in = {4,7,2,1,5,3,8,6};
        TreeNode node = new ReCreateTree().reConstructBinaryTree(pre,in);
        System.out.println(node);
    }
}

【思路】

这类问题只需要用代码实现解决问题的过程即可,但是需要注意的是**,递归的跳出和数组边界越界**的问题,因为随着左边界不断右移,必然会出现越界的情况,需要在递归原有的跳出条件上加上越界判断。


2.树的子结构

【题目】

输入两棵二叉树 A,B,判断 B 是不是 A 的子结构。(ps:我们约定空树不是任意一个树的子结构)

【代码】

package swear2offer.tree;


public class SubTree {

    /**
     * 输入两棵二叉树 A,B,判断 B 是不是 A 的子结构。
     * (ps:我们约定空树不是任意一个树的子结构)
     * */
    //1. 创建一个辅助函数判断两棵树是否相等 2. 递归遍历 A 树的每一个节点作为根结点和 B 树进行比较
    public boolean isSubStructure(TreeNode A, TreeNode B) {
        if(A == null || B == null) return false;
        return dfs(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);
    }
    public boolean dfs(TreeNode A, TreeNode B){
        if(B == null) return true;
        if(A == null) return false;
        return A.val == B.val && dfs(A.left, B.left) && dfs(A.right, B.right);
    }

【思路】

子树和子结构,是两种概念,需要区分:

(一)子树

一棵大树 A,一棵小树 B,若 B 是 A 的子树,则:

  • B 和 A 的结点值完全相同,它们俩的左子树、右子树所有结点的值也完全相同
  • 或者 B 的左孩子和 A 的结点值完全相同,它们俩的左子树、右子树所有结点的值也完全相同
  • 或者 B 的右孩子和 A 的结点值完全相同,它们俩的左子树、右子树所有结点的值也完全相同

举个形象的例子:子树
在这里插入图片描述
这棵大树的子树有:

  • 4 和 5 对应的两棵子树
  • 3 本身自己完整的一棵树

而里面的小框圈出来的不是 3 这棵大树的子树!

(二)子结构

还是上面那张图,子结构就是不用那么严格,图中的小框就是整棵树的子结构,图中的黄色大框也是整棵树的子结构,所以只要找到符合树的一部分树结点即可

可以看到,子结构的判断就是 “没那么严格” 了,和判断子树的写法就是一行代码不同而已,值不想等的时候不直接返回 false,继续往树的右结点和左结点找,找的一个相等值的结点就好,但如果你 一旦找到了结点值是相等的,那么久要保证这两个数的结点值要一一对应上了!


3.二叉树的镜像

【题目】

操作给定的二叉树,将其变换为源二叉树的镜像。
在这里插入图片描述
【代码】

package swear2offer.tree;

import java.util.LinkedList;
import java.util.Queue;

public class Mirror {

    // 队列存储树的节点
    Queue<TreeNode> queue = new LinkedList<>();

    /**
     * 操作给定的二叉树,将其变换为源二叉树的镜像。
     *
     * 思路:
     * 先把交换父节点,在交换子节点,从上往下交换,需要队列辅助实现
     * */
    public void Mirror(TreeNode root) {
        if (root == null) return;

        TreeNode node,temp;
        queue.add(root);

        while (!queue.isEmpty()) {
            // 获得队列首元素
            node = queue.remove();

            // 把左右子树加入队列
            if (node.left != null) queue.add(node.left);
            if (node.right != null) queue.add(node.right);

            // 交换子树
            temp = node.right;
            node.right = node.left;
            node.left = temp;
        }
    }
}


4.从上往下打印二叉树

【题目】

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

【代码】

/**
     * 从上往下打印出二叉树的每个节点,同层节点从左至右打印。
     * */
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {

        ArrayList<Integer> list = new ArrayList<>();

        if (root == null) return list;

        Queue<TreeNode> q = new LinkedList<>();

        q.add(root);
        list.add(root.val);

        TreeNode node;

        while (!q.isEmpty()) {
            node = q.remove();

            // 把左右子树加入队列
            if (node.left != null) {
                q.add(node.left);
                list.add(node.left.val);
            }
            if (node.right != null) {
                q.add(node.right);
                list.add(node.right.val);
            }
        }

        return list;

    }

5.二叉搜索树的后序遍历序列

【题目】

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出 Yes, 否则输出 No。假设输入的数组的任意两个数字都互不相同。

【代码】

/**
     * 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。
     * 如果是则输出 Yes, 否则输出 No。假设输入的数组的任意两个数字都互不相同。
     *
     * 以最后一个元素为支点,判断左半部分是否都小于支点,右半部分是否大于支点
     * */
    public boolean VerifySquenceOfBST(int [] sequence) {

        int n;

        n = sequence.length;

        if (n == 0) return false;

        return Judge(sequence,0,n-1);

    }

    public boolean Judge (int[] a, int start, int end) {
        if (start >= end) return true;

        int pivot,i,j;

        pivot = a[end];

        // 找到大于支点的下标
        for (i = start; i<end; i++) {
            if (a[i]>pivot) {
                break;
            }
        }

        // 序列中存在大于支点的元素
        if (i<end) {

            // 大于支点的元素后面,如果存在小于支点的元素,则不正确
            for (j=i; j<end; j++) {
                if (a[j]<pivot) return false;
            }

            return Judge(a,start,i-1) && Judge(a,i,end-1);

        } else {
            return Judge(a,start,end-1);
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值