算法Day14|二叉树专题part4

63 阅读4分钟

1、题目1:513-找树左下角的值

题目:leetcode.cn/problems/fi…

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

思路

层序遍历简单,从右边往左边迭代即可

public int findBottomLeftValue(TreeNode root) {
    LinkedList<TreeNode> queue = new LinkedList<>();
    if(root == null){
        return 0;
    }
    int val = 0;
    queue.offer(root);
    while (!queue.isEmpty()){
        int size = queue.size();
        while (size-- >0){
            TreeNode node = queue.pop();
            val = node.val;
            if(node.right!=null){
                queue.offer(node.right);
            }
            if(node.left !=null){
                queue.offer(node.left);
            }
        }
    }
    return val;
}

2、题目2:112-路径总和

题目:leetcode.cn/problems/pa…

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false

叶子节点 是指没有子节点的节点。

输入: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 输出: true 解释: 等于目标和的根节点到叶节点路径如上图所示。

思路:类似前面的打印路径

public static boolean hasPathSum(TreeNode root, int targetSum) {
    HashSet<Integer> set = new HashSet<>();
    if(root == null){
        return false;
    }
    ArrayList<Integer> list = new ArrayList<>();
    getSum(root,set,list);
    return set.contains(targetSum)?true:false;
}

public static void getSum(TreeNode node,HashSet<Integer> set,ArrayList<Integer> list){
    list.add(node.val);
    // 碰到叶子节点要回溯下
if(node.left == null && node.right ==null){
        int sum = list.stream().mapToInt(Integer::intValue).sum();
        set.add(sum);
    }
    if(node.left !=null){
        getSum(node.left,set,list);
        // 回溯
list.remove(list.size()-1);
    }
    if(node.right !=null){
        getSum(node.right,set,list);
        // 回溯
list.remove(list.size()-1);
    }
}

3、题目3:113-路径总和II

题目:leetcode.cn/problems/pa…

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

输入: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22 输出: [[5,4,11,2],[5,8,4,5]]

思路,掌握递归三部曲即可

public static List<List<Integer>> pathSum(TreeNode root, int targetSum) {
    List<List<Integer>> list = new ArrayList();
    if(root == null){
        return list;
    }
    ArrayList<Integer> paths = new ArrayList<>();
    getSameValue(root,targetSum,paths,list);
    return list;
}
static void  getSameValue(TreeNode node,int targeSum,ArrayList<Integer> paths,List<List<Integer>> res){
    paths.add(node.val);
    // 到根节点算是完成一条路径,需要取出这条路径进行比对
if(node.left == null && node.right == null){
        int sum=0;
        for (Integer path : paths) {
            sum+=path;
        }
        if(sum == targeSum){
            res.add(new ArrayList<>(paths));
        }
    }
    if(node.left !=null){
        getSameValue(node.left,targeSum,paths,res);
        paths.remove(paths.size()-1);
    }
    if(node.right !=null){
        getSameValue(node.right,targeSum,paths,res);
        paths.remove(paths.size()-1);
    }
}

4、题目4:106-从中序与后序遍历序列构造二叉树

给定两个整数数组 inorderpostorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这棵 二叉树

输入: inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出: [3,9,20,null,null,15,7]

思路

1、后序数组为空,空节点

2、后续数组最后一个元素为节点元素

3、寻找中序数组位置作为切割点

4、切中序位置,切成中序左数组和中序右数组

5、切后序位置,切成后序左数组和后序右数组

6、递归处理左区间和右区间

递归三部曲:

1、入参返回

TreeNode traver(int[] pre ,int[] end){
}

2、结束逻辑

if(end.size ==0) return null;
rootVal = end(end.size()-1)//后序最后一个
TreeNode root = new TreeNode(rootVal );
if(root.size==1) return root;

3、单层递归逻辑

 // 第三步:找切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
    if (inorder[delimiterIndex] == rootValue) break;
}

// 第四步:切割中序数组,得到 中序左数组和中序右数组
// 第五步:切割后序数组,得到 后序左数组和后序右数组

// 第六步
root->left = traversal(中序左数组, 后序左数组);
root->right = traversal(中序右数组, 后序右数组);

为什么要切割中序数组呢?

切割点在后序数组的最后一个元素,就是用这个元素来切割中序数组的,所以必要先切割中序数组。

public TreeNode buildTree(int[] inorder, int[] postorder) {
    map = new HashMap<>();
    for (int i = 0; i < inorder.length; i++) {
        map.put(inorder[i],i);
    }
    return findNode(inorder,0,inorder.length,postorder,0,postorder.length); // 前闭后开
}

private TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd) {
    //左闭右开
if(inBegin >= inEnd || postBegin >= postEnd){
        return null;
    }
    // 找到后序遍历的最后一个元素在中序遍历中的位置
int rootIndex = map.get(postorder[postEnd - 1]);
    TreeNode root = new TreeNode(inorder[rootIndex]);  // 构造结点
int lenOfLeft = rootIndex - inBegin;  // 保存中序左子树个数,用来确定后序数列的个数
root.left = findNode(inorder, inBegin, rootIndex,
            postorder, postBegin, postBegin + lenOfLeft);
    root.right = findNode(inorder, rootIndex + 1, inEnd,
            postorder, postBegin + lenOfLeft, postEnd - 1);
    return root;
}