ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【剑指Offer】个人学习笔记_ 07_重建二叉树

2021-03-15 21:57:07  阅读:185  来源: 互联网

标签:preorder TreeNode 07 Offer int root 二叉树 l1 inorder


目录

刷题日期:20:4827 星期一2021年3月15日

个人刷题记录,代码收集,来源皆为leetcode

经过多方讨论和请教,现在打算往Java方向发力

主要答题语言为Java

题目:

剑指 Offer 07. 重建二叉树

难度中等360

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

限制:

0 <= 节点个数 <= 5000

初始解答:

二叉树的题还是第一次遇到,书本中的代码也有一页多,自己先尽量思考大致的思路,了解判断根节点,左右子树的方法,然后大概想出来思路,参考别人的代码完成。

前序遍历的第一个数字是根节点;

中序遍历根节点之前的都是左子树;

之后的都是右子树;

一直循环,再复杂多层的情况目前还想不太明白。

要使用递归不断确定到最下层的左子树、双亲、右子树。

参考了Ant的评论:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        //题目已经确定了函数名和输入的参数,那么想要递归就不重新定义函数
        //而是直接把题目作为递归的那个函数
        int n = preorder.length; //判断遍历结果长度
        if (n == 0)
            return null;  //为空返回空
        int rootVal = preorder[0], rootIndex = 0; //否则第一步先找到根节点,确定参数
        for(int i = 0; i <n; i++) {
            if(inorder[i] == rootVal) {
                rootIndex = i;
                break;  //在中序遍历中找到根节点的位置并记录
            }
        }
        TreeNode root = new TreeNode(rootVal);
        //下面的两句是核心
        root.left = buildTree(Arrays.copyOfRange(preorder, 1, 1 + rootIndex), Arrays.copyOfRange(inorder, 0, rootIndex));

        /* Arrays.copyOfRange(T[ ] original,int from,int to)
        //将一个原始的数组original,从下标from开始复制,复制到上标to,生成一个新的数组。
        注意这里包括下标from,不包括上标to */
        root.right = buildTree(Arrays.copyOfRange(preorder, 1 + rootIndex, n), Arrays.copyOfRange(inorder, rootIndex + 1, n));

        return root;
    }
}

执行结果:效率很是一般,难道是用了递归的缘故吗,但是这种解决树的问题,不就应该用递归么。

通过

显示详情

执行用时:14 ms, 在所有 Java 提交中击败了14.42%的用户

内存消耗:88.7 MB, 在所有 Java 提交中击败了5.04%的用户

知识点:

  • 前序遍历列表:第一个元素永远是 【根节点 (root)】
  • 中序遍历列表:根节点 (root)【左边】的所有元素都在根节点的【左分支】,【右边】的所有元素都在根节点的【右分支】

算法思路:

  1. 通过【前序遍历列表】确定【根节点 (root)】
  2. 将【中序遍历列表】的节点分割成【左分支节点】和【右分支节点】
  3. 递归寻找【左分支节点】中的【根节点 (left child)】和 【右分支节点】中的【根节点 (right child)】

试试看有没有效率更高的。

参考方法二:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        //直接返回新建立函数的结果est:establish
        return est(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
    }
    public TreeNode est(int[] preorder, int l1, int r1, int[] inorder, int l2, int r2) {
        if(l1>r1||l2>r2) return null;
        int i = l2;
        while(inorder[i]!=preorder[l1]) {
            i++;
        }
        TreeNode root = new TreeNode(preorder[l1]);
        root.left = est(preorder,l1+1,l1+i-l2,inorder,l2,i-2);
        root.right = est(preorder,l1+i-l2+1,r1,inorder,i+1,r2);
        return root;
    }
}

但是输入:[3,9,20,15,7] [9,3,15,20,7]

输出

[3,null,20,null,7]

差别

预期结果

[3,9,20,null,null,15,7]

与预期答案并不相同,寻找问题所在。

少的是左子树的9,判断错误在left节点语句上,果然排查发现最后的i-1码成了i-2,所以把9给跳过了,修正便可。

root.left = est(preorder,l1+1,l1+i-l2,inorder,l2,i-2);//错误代码
root.left = est(preorder,l1+1,l1+i-l2,inorder,l2,i-1);//正确代码

学习他人:

方法一:

AntL1 2020-02-13

题目函数直接递归

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int n = preorder.length;
        if (n == 0)
            return null;
        int rootVal = preorder[0], rootIndex = 0;
        for (int i = 0; i < n; i++) {
            if (inorder[i] == rootVal) {
                rootIndex = i;
                break;
            }
        }
        TreeNode root = new TreeNode(rootVal);
        root.left = buildTree(Arrays.copyOfRange(preorder, 1, 1 + rootIndex), Arrays.copyOfRange(inorder, 0, rootIndex));
        root.right = buildTree(Arrays.copyOfRange(preorder, 1 + rootIndex, n), Arrays.copyOfRange(inorder, rootIndex + 1, n));

        return root;
    }
}

方法二:

SilenL12021-03-02

java 递归 不用HashMap

重新建立函数进行递归。

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return help(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
    }
    public TreeNode help(int[] preorder,int l1,int r1,int[] inorder,int l2,int r2){
        if(l1>r1||l2>r2) return null;
        int i =l2;
        while(inorder[i]!=preorder[l1]){//在中序数组中去寻找根节点
            i++;
        }
        TreeNode root = new TreeNode(preorder[l1]);
        root.left = help(preorder,l1+1,l1+i-l2,inorder,l2,i-1);
        root.right = help(preorder,l1+i-l2+1,r1,inorder,i+1,r2);
        return root;
    }
}

help函数。

方法三:

作者:jyd
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/mian-shi-ti-07-zhong-jian-er-cha-shu-di-gui-fa-qin/
来源:力扣(LeetCode)

用HashMap,代码:

class Solution {
    int[] preorder;
    HashMap<Integer, Integer> dic = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        for(int i = 0; i < inorder.length; i++)
            dic.put(inorder[i], i);
        return recur(0, 0, inorder.length - 1);
    }
    TreeNode recur(int root, int left, int right) {
        if(left > right) return null;                          // 递归终止
        TreeNode node = new TreeNode(preorder[root]);          // 建立根节点
        int i = dic.get(preorder[root]);                       // 划分根节点、左子树、右子树
        node.left = recur(root + 1, left, i - 1);              // 开启左子树递归
        node.right = recur(root + i - left + 1, i + 1, right); // 开启右子树递归
        return node;                                           // 回溯返回根节点
    }
}

注意:本文方法只适用于 “无重复节点值” 的二叉树。

总结

以上就是本题的内容和学习过程了,虽然有很多简短的方法,但是书中进行替换的思路是值得学习的。

欢迎讨论,共同进步。

标签:preorder,TreeNode,07,Offer,int,root,二叉树,l1,inorder
来源: https://blog.csdn.net/qq_39295220/article/details/114854166

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有