代码随想录day18|513.找树左下角的值 112.113 路径总和i和ii 105.106.从中序与前序后序遍历序列构造二叉树

513. 找树左下角的值

题目链接:https://leetcode.com/problems/find-bottom-left-tree-value/

Given the root of a binary tree, return the leftmost value in the last row of the tree.

思路:
在树的最后一行找到最左边的值。
优先左边搜索,然后记录深度最大的叶子节点,前序遍历(中后序也可以)

递归

class Solution {
    int maxDepth = -1;
    int result = 0;
    public int findBottomLeftValue(TreeNode root) {
        result = root.val;
        traversal(root, 0);
        return result;
    }

    // 寻找深度最深的左叶子节点 // 有问题,应该是深度最深的最左边的节点
    public void traversal (TreeNode node, int depth) {
        depth++; // 需要回溯吗?
        if (node.left == null && node.right == null) {
            if (depth > maxDepth) {
                maxDepth = depth;
                result = node.val;
                return;
            }
        }
        if (node.left != null) { // depth++;需要回溯为什么
            traversal(node.left, depth);
        }
        if (node.right != null) {
            traversal(node.right, depth);
        }
    }
}
class Solution {
    int maxDepth = -1;
    int result = 0; //记录最大深度最左边节点的值
    public int findBottomLeftValue(TreeNode root) {
        result = root.val;
        traversal(root, 1);
        return result;
    }

    // 寻找深度最深的左叶子节点 // 有问题,应该是深度最深的最左边的节点
    public void traversal (TreeNode node, int depth) {
    //遇到叶子节点就更新最大深度
        if (node.left == null && node.right == null) {
            if (depth > maxDepth) {
                maxDepth = depth;
                result = node.val;
                return;
            }
        }
        if (node.left != null) {
            traversal(node.left, depth+1);
        }
        if (node.right != null) {
            traversal(node.right, depth+1);
        }
    }
}

层序遍历(更简单)

class Solution {
    // 层序遍历
    public int findBottomLeftValue(TreeNode root) {
        Deque<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int leftMost = root.val;
        while (!queue.isEmpty()) {
            int size = queue.size();
            leftMost = queue.peek().val;
            while (size -- > 0) {
                TreeNode node = queue.poll(); // 中
                if (node.left != null) queue.offer(node.left); // 左
                if (node.right != null) queue.offer(node.right); // 右
            }
        }
        return leftMost;
    }
}

这里有个疑问?回溯到底有没有必要?????

112. 路径总和

题目链接:https://leetcode.com/problems/path-sum/

Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum =22
Output: true
Explanation: The root-to-leaf path with the target sumis shown.
在这里插入图片描述

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return false;
        }
        return traversal(root, targetSum, root.val);
    }
    private boolean traversal (TreeNode node, int targetSum, int count) {
        if (node.left == null && node.right == null) {
            if (count == targetSum) {
                return true;
            }
        }
        boolean left = false;
        boolean right = false;
        if (node.left != null) {
            if(traversal(node.left, targetSum, count+node.left.val)){ // 可直接返回
                return true;   
            }
        }
        if (node.right != null) {
            if(right = traversal(node.right, targetSum, count+node.right.val)){
                return true;
            }
        }
        return false;
    }
}

思路:

  1. 返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)

  1. 遍历的路线,并不要遍历整棵树,所以递归函数需要返回值,可以用bool类型表示。
  2. 确定终止条件:遍历到叶子节点且sum满足,不放入空节点
  3. 迭代与回溯,count直接在传入参数处改变,数值没有改变,此时不需要回溯,拎出来就需要了

113.路径总和2

题目链接:https://leetcode.com/problems/path-sum-ii/

Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
Output: [[5,4,11,2],[5,8,4,5]]
Explanation: There are two paths whose sum equals targetSum:
5 + 4 + 11 + 2 = 22
5 + 8 + 4 + 5 = 22

class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> result = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        if (root == null) return result; 
        traversal(root, targetSum, root.val, path, result);
        return result;
    }
    private void traversal(TreeNode node, int targetSum, int count, List<Integer> path, List<List<Integer>> result){
        path.add(node.val);
        if (node.left == null && node.right == null) {
            if (count == targetSum) {
                result.add(new ArrayList<>(path));
                //result.add(path);
            }
            return;
        }
        if (node.left != null) {
            traversal(node.left, targetSum, count+node.left.val, path, result);
            path.remove(path.size()-1); // 回溯
        }
        if (node.right != null) {
            traversal(node.right, targetSum, count+node.right.val, path, result);
            path.remove(path.size()-1);
        }
    }
}

思路:
出错了!!!!注意:

  1. 要遍历整个树,找到所有路径,所以递归函数不要返回值!
  2. result添加path需要new arraylist
  3. path添加必须要回溯

106.从中序与后序遍历序列构造二叉树

题目链接:
https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/

Given two integer arrays inorder and postorder where inorder is the inorder traversal of a binary tree and postorder is the postorder traversal of the same tree, construct and return the binary tree.

在这里插入图片描述

Input: inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
Output: [3,9,20,null,null,15,7]

思路:
模拟一层层切割 前中后序

第一步:如果数组大小为零的话,说明是空节点了。

第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

第五步:切割后序数组,切成后序左数组和后序右数组

第六步:递归处理左区间和右区间

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        // 第一步:如果数组大小为零的话,说明是空节点了。
        if (postorder.length == 0) {
            return null;
        }
        // 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
        int rootVal = postorder[postorder.length - 1];
        TreeNode root = new TreeNode(rootVal);

        // 叶子节点
        if (postorder.length == 1){
            return root;
        }

        // 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
        int index = 0;
        for (int i = 0; i < inorder.length; i ++) {
            if (inorder[i] == rootVal){
                index = i;
            }
        }
        // 左闭右开区间:[0, delimiterIndex)
        // 第四步:切割中序数组,得到 中序左数组和中序右数组
        int[] left_inorder = Arrays.copyOfRange(inorder, 0, index);
        int[] right_inorder = Arrays.copyOfRange(inorder, index+1, inorder.length);
        // 第五步:切割后序数组,得到 后序左数组和后序右数组
        int[] left_postorder = Arrays.copyOfRange(postorder, 0, left_inorder.length);
        int[] right_postorder = Arrays.copyOfRange(postorder, left_inorder.length, left_inorder.length + right_inorder.length);
        // 第六步:递归处理左区间和右区间
        root.left = buildTree(left_inorder, left_postorder);
        root.right = buildTree(right_inorder, right_postorder);

        return root;
    }
}

思路:

  1. 如何切割?先找root,切割中序再后序
  2. 边界值 保持循环不变量
  3. 中序数组大小一定是和后序数组的大小相同的(这是必然)

105.前序中序

题目链接:https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder.length == 0) {
            return null;
        }
        int rootVal = preorder[0];
        TreeNode root = new TreeNode(rootVal);

        int index = 0;
        for (int i = 0; i < inorder.length; i ++){
            if (inorder[i] == rootVal) {
                index = i;
            }
        }

        int[] left_inorder = Arrays.copyOfRange(inorder, 0, index);
        int[] right_inorder = Arrays.copyOfRange(inorder, index+1, inorder.length);

        int[] left_preorder = Arrays.copyOfRange(preorder, 1, left_inorder.length+1);
        int[] right_preorder = Arrays.copyOfRange(preorder, left_inorder.length+1, preorder.length);

        root.left = buildTree(left_preorder, left_inorder);
        root.right = buildTree(right_preorder, right_inorder);
        return root;
    }
}

思路:
必须有中序,因为中序可以分割左右

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值