代码随想录算法训练营第十八天 | 513.找树左下角的值、112. 路径总和、113.路径总和ii、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

513.找树左下角的值

题目链接:https://leetcode.cn/problems/find-bottom-left-tree-value/
文档讲解:https://programmercarl.com/0513.%E6%89%BE%E6%A0%91%E5%B7%A6%E4%B8%8B%E8%A7%92%E7%9A%84%E5%80%BC.html
视频讲解:https://www.bilibili.com/video/BV1424y1Z7pn

思路

  • 层序迭代遍历的代码比较简单。
  • 递归法中三个遍历顺序都可以。因为是找最后一层最左的结点,只要先遍历左节点就可以。

代码

层序遍历

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        int res = 0;
        if (root == null) return 0;
        Deque<TreeNode> deque = new LinkedList<>();
        deque.addLast(root);
        while (!deque.isEmpty()) {
            int size = deque.size();
            int flag = 0;
            while (size-- > 0) {
                flag++;
                TreeNode node = deque.pollFirst();
                if (flag == 1) res = node.val;
                if (node.left != null) deque.addLast(node.left);
                if (node.right != null) deque.addLast(node.right);
            }
        }
        return res;
    }
}

递归

class Solution {
    int maxDepth = Integer.MIN_VALUE;
    int res;

    public int findBottomLeftValue(TreeNode root) {
        if (root == null) return 0;
        getBottom(root, 1);
        return res;
    }

    public void getBottom(TreeNode root, int depth){
        if (root.left == null && root.right == null) {
            if (depth > maxDepth) {
                maxDepth = depth;
                res = root.val;
            }
        }

        if (root.left != null) { // 左
            getBottom(root.left, depth + 1); // 隐藏回溯
        }
        if (root.right != null) { // 右
            getBottom(root.right, depth + 1);
        }
        // 本题没有中
    } 
}

112. 路径总和

题目链接:https://leetcode.cn/problems/path-sum/
文档讲解:https://programmercarl.com/0112.%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
视频讲解:https://www.bilibili.com/video/BV19t4y1L7CR

思路

本题也是没有对中结点的处理所以前中后序遍历都可以。

代码

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) return false;
        return getHasPathSum(root, targetSum - root.val); // 这里传入的是减去当前节点的值
    }

    public boolean getHasPathSum(TreeNode root, int count) {
        if (root.left == null && root.right == null && count == 0) return true;

        if (root.left != null) {
            if (getHasPathSum(root.left, count - root.left.val)) return true;
        }
        if (root.right != null) {
            if (getHasPathSum(root.right, count - root.right.val)) return true;
        }
        return false;
    }
}

113.路径总和ii

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

代码

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        if (root == null) return res;
        path.add(root.val);
        getPath(root, targetSum - root.val);
        return res;
    }

    public void getPath(TreeNode root, int count) {
        if (root.left == null && root.right == null && count == 0) {
            res.add(new ArrayList<>(path)); // 使用了 new ArrayList<>(path) 来创建一个 path 的副本。这是因为 path 是一个全局变量,如果直接添加 path 的引用,那么在后续的操作中,任何对 path 的修改都会影响到结果列表中的路径。
            return;
        }// 找到合适的路径,返回
        if (root.left == null && root.right == null) return; // 到叶子结点但数值不对,返回
        
        if (root.left != null) {
            path.add(root.left.val);
            getPath(root.left, count - root.left.val);
            path.remove(path.size() - 1);
        }
        if (root.right != null) {
            path.add(root.right.val);
            getPath(root.right, count - root.right.val);
            path.remove(path.size() - 1);
        }
        return;
    }
}

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

题目链接:https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
文档讲解:https://programmercarl.com/0106.%E4%BB%8E%E4%B8%AD%E5%BA%8F%E4%B8%8E%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
视频讲解:https://www.bilibili.com/video/BV1vW4y1i7dn

思路

  1. 后序数组为0,空节点;数组长度为1,直接返回根节点。
  2. 后序数组最后一个元素为节点元素。
  3. 寻找中序数组位置作切割点。
  4. 切中序数组(根据中节点切)。
  5. 切后序数组(根据中序数组切出来的左子树长度来切)。
  6. 递归处理左区间右区间。
  7. 注意统一区间左闭右闭或者左闭右开。

代码

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        //1.数组大小为0,空节点
        if (inorder.length == 0) return null;
        return traversal(inorder, postorder);
    }

    public TreeNode traversal(int[] inorder, int[] postorder) {
        //1.数组大小为0,空节点
        if (inorder.length == 0 || postorder.length == 0) return null;
        // 2.如果不为空,取后序最后一个作为根节点(中节点)
        int rootValue = postorder[inorder.length - 1];
        TreeNode root = new TreeNode(rootValue);
        // 3.找到rootValue在中序数组中的位置,作为切割点
        int index;
        for (index = 0; index < inorder.length; index++) {
            if (inorder[index] == rootValue) break;
        }
        // 4.切割中序数组,切割成左中序和右中序
        int[] leftInorder = new int[index];
        int[] rightInorder = new int[inorder.length - index - 1];
        for (int i = 0, j = 0; i < inorder.length; i++) {
            if (i < index) leftInorder[i] = inorder[i];
            else if (i == index) continue;
            else rightInorder[j++] = inorder[i];
        }
        // 5.切割后序数组,切割成左后序和右后序
        int[] leftPostorder = new int[leftInorder.length];
        int[] rightPostorder = new int[rightInorder.length];
        for (int i = 0; i < leftInorder.length; i++) {
            leftPostorder[i] = postorder[i];
        }
        for (int i = 0; i < rightInorder.length; i++) {
            rightPostorder[i] = postorder[i + index];
        }
        // 6.递归处理左区间和右区间
        root.left = traversal(leftInorder, leftPostorder);
        root.right = traversal(rightInorder, rightPostorder);

        return root;
    }
}

105.从前序与中序遍历序列构造二叉树

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

代码

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

    public TreeNode getTree(int[] preorder, int[] inorder) {
        // 1. 后序数组为0,空节点;数组长度为1,直接返回根节点。
        if (inorder.length == 0 || preorder.length == 0) return null;
        // 2. 前序数组第一个元素为节点元素。
        int rootValue = preorder[0];
        TreeNode root = new TreeNode(rootValue);
        if (inorder.length == 1) return root;
        // 3. 寻找中序数组位置作切割点。
        int index;
        for (index = 0; index < inorder.length; index++) {
            if (inorder[index] == rootValue) break;
        }
        // 4. 切中序数组,切成左中序和右中序
        int[] leftInorder = new int[index];
        int[] rightInorder = new int[inorder.length - index - 1];
        for (int i = 0, j = 0; i < inorder.length; i++) {
            if (i < index) leftInorder[i] = inorder[i];
            else if (i == index) continue;
            else rightInorder[j++] = inorder[i];
        }
        // 5.切前序数组,切成左前序和右前序
        int[] leftPreorder = new int[leftInorder.length];
        int[] rightPreorder = new int[rightInorder.length];
        for (int i = 1, j = 0; i < preorder.length; i++) {
            if (i < 1 + leftInorder.length) leftPreorder[i - 1] = preorder[i];
            else rightPreorder[j++] = preorder[i];
        }
        // 6. 递归处理左区间右区间
        root.left = getTree(leftPreorder, leftInorder);
        root.right = getTree(rightPreorder, rightInorder);
        return root;
    }
}

之前准备面试落下好几天的任务,这两天的博客就简单写了,具体思路注释在代码里。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值