树——4、17、22、60、59、61

4、重建二叉树

大佬的解析

//利用原理,先序遍历的第一个节点就是根。在中序遍历中通过根 区分哪些是左子树的,哪些是右子树的
    //左右子树,递归
    HashMap<Integer, Integer> map = new HashMap<>();//标记中序遍历
    int[] preorder;//保留的先序遍历

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        for (int i = 0; i < preorder.length; i++) {
            map.put(inorder[i], i);
        }
        return recursive(0,0,inorder.length-1);
    }

    /**
     * @param pre_root_idx  先序遍历的索引
     * @param in_left_idx  中序遍历的索引
     * @param in_right_idx 中序遍历的索引
     */
    public TreeNode recursive(int pre_root_idx, int in_left_idx, int in_right_idx) {
        //相等就是自己
        if (in_left_idx > in_right_idx) {
            return null;
        }
        //root_idx是在先序里面的
        TreeNode root = new TreeNode(preorder[pre_root_idx]);
        // 有了先序的,再根据先序的,在中序中获 当前根的索引
        int idx = map.get(preorder[pre_root_idx]);

        //左子树的根节点就是 左子树的(前序遍历)第一个,就是+1,左边边界就是left,右边边界是中间区分的idx-1
        root.left = recursive(pre_root_idx + 1, in_left_idx, idx - 1);

        //由根节点在中序遍历的idx 区分成2段,idx 就是根

        //右子树的根,就是右子树(前序遍历)的第一个,就是当前根节点 加上左子树的数量
        // pre_root_idx 当前的根  左子树的长度 = 左子树的左边-右边 (idx-1 - in_left_idx +1) 。最后+1就是右子树的根了
        root.right = recursive(pre_root_idx + (idx-1 - in_left_idx +1)  + 1, idx + 1, in_right_idx);
        return root;
    }

容易理解的解析

copyOfRange(original,int from,int to)该方法是从original数组的下标from开始赋值,到下标to结束,不包括下标为to的元素。实际上看完代码应该这样理解copyOfRange(original,int from,int to)该方法返回一个长度为to-from的数组,其中from~min(original.length,to)之间的元素(不包括min(original.length,to))是从数组original复制的元素,剩下的值为0

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
import java.util.Arrays;
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        if (pre.length == 0 || in.length == 0) {
            return null;
        }
        TreeNode root = new TreeNode(pre[0]);
        // 在中序中找到前序的根
        for (int i = 0; i < in.length; i++) {
            if (in[i] == pre[0]) {
                // 左子树,注意 copyOfRange 函数,左闭右开
                root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i));
                // 右子树,注意 copyOfRange 函数,左闭右开
                root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, pre.length), Arrays.copyOfRange(in, i + 1, in.length));
            }
        }
        return root;
    }
}

17、树的子结构

class Solution {
    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);
    }
}

题解

22、从上到下打印树

BFS 通常借助 队列 的先入先出特性来实现

Queue使用时要尽量避免Collection的add()和remove()方法,而是要使用offer()来加入元素,使用poll()来获取并移出元素。它们的优点是通过返回值可以判断成功与否,add()和remove()方法在失败的时候会抛出异常。

题解

class Solution {
    public int[] levelOrder(TreeNode root) {
        if (root == null) // 空树则返回空数组
            return new int[0];
        Queue<TreeNode> q = new LinkedList<> (); // 借助一个队列,通过 BFS 实现按层遍历二叉树
        ArrayList<Integer> tmp =new ArrayList<> (); // 申请一个动态数组 ArrayList 动态添加节点值
        
        q.offer(root); // 根结点先入队
        while (q.size() != 0) {
            TreeNode node = q.poll(); // 取出当前队首元素
            tmp.add(node.val); 
            if(node.left != null) q.offer(node.left); // 左子节点入队
            if(node.right != null) q.offer(node.right); // 右子节点入队
        }

        // 将 ArrayList 转为 int数组并返回
        int[] res = new int[tmp.size()];
        for (int i=0; i<res.length; i++) {
            res[i] = tmp.get(i);
        }
        return res;
    }
}

60、二叉树打印成多行

如果需要分层打印,打印多行

分层打印树

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root != null) queue.add(root);
        while(!queue.isEmpty()) {
            List<Integer> tmp = new ArrayList<>();
            for(int i = queue.size(); i > 0; i--) {  //当前层节点数  循环
                TreeNode node = queue.poll();
                tmp.add(node.val);
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
            }
            res.add(tmp);
        }
        return res;
    }
}

59、之字形顺序打印

利用双端队列的两端皆可添加元素的特性,设打印列表(双端队列) tmp ,并规定:

  • 奇数层 则添加至 tmp 尾部 ,
  • 偶数层 则添加至 tmp 头部

Java 中将链表 LinkedList 作为双端队列使用

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root != null) queue.add(root);
        while(!queue.isEmpty()) {
            LinkedList<Integer> tmp = new LinkedList<>();
            for(int i = queue.size(); i > 0; i--) {
                TreeNode node = queue.poll();
                if(res.size() % 2 == 0) tmp.addLast(node.val); // 偶数层 -> 队列头部
                else tmp.addFirst(node.val); // 奇数层 -> 队列尾部
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
            }
            res.add(tmp);
        }
        return res;
    }
}

61、序列化二叉树

题解很不错

public class Codec {
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if(root==null)
            return "#,";
        String res="";
        res+=root.val+",";   //前序遍历,根左右
        res+=serialize(root.left);
        res+=serialize(root.right);
        return res;
    }
    //反序列化
    int start=-1;
    TreeNode deserialize(String str){
        if(str==null || str.length()==0)
            return null;//若 data 为空,直接返回 null ;
        String[] strArr=str.split(",");
        return deserialize(strArr);
    }
    TreeNode deserialize(String[] strArr){
        start++;
        if(start>=strArr.length || strArr[start].equals("#"))
            return null;//超出索引,等于结束标志
        TreeNode cur=new TreeNode(Integer.valueOf(strArr[start]));//节点出队,记为 node ;
        cur.left=deserialize(strArr);//构建 node 的左子节点:node.left 的值为 vals[i] ,i在递归的时候会+1
        cur.right=deserialize(strArr);//构建 node 的右子节点:node.left 的值为 vals[i] ,i在递归的时候会+1
        return cur;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值