代码随想录-刷题第十八天

513.寻找树左下角的值

题目链接:513. 找树左下角的值

思路:通过层序遍历比较简单,从左到右来遍历,记录最后一行第一个元素就是树左下角的值。递归遍历也可以,因为不需要处理中间节点,所以只需要保证先左后右的顺序就好,可以看作前序遍历。每次遍历到叶子节点,记录深度,如果深度比当前深度大,更新结果。

层序遍历实现

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        int res = 0;
        while (!q.isEmpty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                TreeNode cur = q.poll();
                // 记录最后一行第一个元素
                if (i == 0) {
                    res = cur.val;
                }
                if (cur.left != null) {
                    q.offer(cur.left);
                }
                if (cur.right != null) {
                    q.offer(cur.right);
                }
            }
        }
        return res;
    }
}

递归遍历实现

class Solution {
    // 记录二叉树的最大深度
    int maxDepth = 0;
    // 记录 traverse 递归遍历到的深度
    int depth = 0;
    TreeNode res = null;

    public int findBottomLeftValue(TreeNode root) {
        traverse(root);
        return res.val;
    }

    void traverse(TreeNode root) {
        if (root == null) {
            return;
        }
        // 前序遍历位置
        depth++;
        if (depth > maxDepth) {
            // 到最大深度时第一次遇到的节点就是左下角的节点
            maxDepth = depth;
            res = root;
        }
        traverse(root.left);
        traverse(root.right);
        // 后序遍历位置
        depth--;
    }
}

112.路经总和

题目链接:112. 路径总和

思路:采用递归遍历,当遍历到叶子节点的时候判断是否符合条件,符合条件返回true,不符合条件返回false。只要存在一条路径是true,结果就是true。(注意回溯的过程。)

class Solution {
    /* 遍历二叉树的思路 */
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) return false;
        hasPathSumHeplper(root, targetSum);
        return found;
    }

    boolean found = false;
    // 记录遍历过程中的路径和
    int curSum = 0;

    // 二叉树遍历函数
    void hasPathSumHeplper(TreeNode root, int targetSum) {
        if (root == null) return;
        // 前序遍历位置
        curSum += root.val;
        if (root.left == null && root.right == null) {
            if (curSum == targetSum) {
                found = true;
            }
        }

        hasPathSumHeplper(root.left, targetSum);
        hasPathSumHeplper(root.right, targetSum);

        // 后序遍历位置
        curSum -= root.val;
    }
}

113.路径总和II

题目链接:113. 路径总和 II

思路:递归遍历,没有处理中节点的操作,(可以看成前序遍历)定义数组来记录路径,每当遍历到叶子节点的时候判断是否符合条件,符合条件就将路径加入到结果中。(注意回溯过程)

class Solution {
    List<List<Integer>> res = new LinkedList<>(); // 结果
    List<Integer> path = new LinkedList<>(); // 记录路径

    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        if (root == null) return res;
        traverse(root, targetSum);
        return res;
    }

    // 遍历二叉树的同时维护经过的路径,
    // 在进入递归的时候要在 path 列表添加节点,结束递归的时候删除节点。
    private void traverse(TreeNode root, int targetSum) {
        if (root == null) return;

        targetSum = targetSum - root.val;

        if (root.left == null && root.right == null) {
            if (targetSum == 0) {
                // 找到一条路径
                path.add(root.val);
                res.add(new LinkedList<>(path));
                path.remove(path.size() - 1);
            }
            return;
        }

        // 维护路径列表
        path.add(root.val);
        traverse(root.left, targetSum);
        traverse(root.right, targetSum);
        path.remove(path.size() - 1);
    }
}

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

题目链接:106. 从中序与后序遍历序列构造二叉树

思路:构造二叉树,第一件事一定是找根节点,然后想办法构造左右子树。后序遍历结果最后一个就是根节点的值,然后再根据中序遍历结果确定左右子树的节点。

class Solution {
    // 存储 inorder 中值到索引的映射
    HashMap<Integer, Integer> valToIndex = new HashMap<>();

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        for (int i = 0; i < inorder.length; i++) {
            valToIndex.put(inorder[i], i);
        }
        return build(inorder, 0, inorder.length - 1,
                    postorder, 0, postorder.length - 1);
    }

    /*
       定义:
       中序遍历数组为 inorder[inStart..inEnd],
       后序遍历数组为 postorder[postStart..postEnd],
       构造这个二叉树并返回该二叉树的根节点
    */
    TreeNode build(int[] inorder, int inStart, int inEnd,
                int[] postorder, int postStart, int postEnd) {

        if (inStart > inEnd) {
            return null;
        }
        // root 节点对应的值就是后序遍历数组的最后一个元素
        int rootVal = postorder[postEnd];
        // rootVal 在中序遍历数组中的索引
        int index = valToIndex.get(rootVal);
        // 左子树的节点个数
        int leftSize = index - inStart;
        TreeNode root = new TreeNode(rootVal);
        // 递归构造左右子树
        root.left = build(inorder, inStart, index - 1,
                         postorder, postStart, postStart + leftSize - 1);
        
        root.right = build(inorder, index + 1, inEnd,
                          postorder, postStart + leftSize, postEnd - 1);
        return root;
    }
}

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

题目链接:105. 从前序与中序遍历序列构造二叉树

思路:构造二叉树,第一件事一定是找根节点,然后想办法构造左右子树。前序遍历结果第一个就是根节点的值,然后再根据中序遍历结果确定左右子树的节点。

class Solution {
    // 存储 inorder 中值到索引的映射
    HashMap<Integer, Integer> valToIndex = new HashMap<>();

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

    /*
       定义:前序遍历数组为 preorder[preStart..preEnd],
       中序遍历数组为 inorder[inStart..inEnd],
       构造这个二叉树并返回该二叉树的根节点
    */
    TreeNode build(int[] preorder, int preStart, int preEnd,
                   int[] inorder, int inStart, int inEnd) {
        if (preStart > preEnd) {
            return null;
        }

        // root 节点对应的值就是前序遍历数组的第一个元素
        int rootVal = preorder[preStart];
        // rootVal 在中序遍历数组中的索引
        int index = valToIndex.get(rootVal);

        int leftSize = index - inStart;

        // 先构造出当前根节点
        TreeNode root = new TreeNode(rootVal);
        // 递归构造左右子树
        root.left = build(preorder, preStart + 1, preStart + leftSize,
                inorder, inStart, index - 1);

        root.right = build(preorder, preStart + leftSize + 1, preEnd,
                inorder, index + 1, inEnd);
        return root;
    }
}

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值