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

目录

题目链接:513. 找树左下角的值 - 力扣(LeetCode)

题目链接:112. 路径总和 - 力扣(LeetCode)

题目链接:113. 路径总和 II - 力扣(LeetCode)

题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

题目链接:105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)


       “我昨天遇到一个人,觉得她非常有意思,令我印象深刻。但今天就不再会遇到了,人生就是这样。”   

题目链接:513. 找树左下角的值 - 力扣(LeetCode)

找到二叉树最底层最左边节点的值.

思路:使用广度优先搜索(BFS)遍历二叉树。BFS遍历从根节点开始,一层一层地向下遍历,在同一层中从左到右依次遍历节点。这样,当遍历到最后一层时,第一个节点即为最底层最左边的节点。

class Solution513 {
    public int findBottomLeftValue(TreeNode root) {
        /**
         * 使用广度优先搜索(BFS)遍历二叉树.
         * BFS遍历从根节点开始,一层一层地向下遍历,在同一层中从左到右依次遍历节点。
         * 这样,当遍历到最后一层时,第一个节点即为最底层最左边的节点。
         */
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        TreeNode current = null;

        while (!queue.isEmpty()){
            current = queue.poll(); // 取出队列的第一个节点

            // 先将右子节点加入队列,再将左子节点加入队列
            // 这样保证最底层的最左边节点会是最后遍历到的节点
            if (current.right != null) {
                queue.add(current.right);
            }
            if (current.left != null) {
                queue.add(current.left);
            }

        }
        return current.val;
    }
}

题目链接:112. 路径总和 - 力扣(LeetCode)

要判断二叉树中是否存在从根节点到叶子节点的路径,使得该路径上所有节点值的和等于给定的目标和.

思路:使用深度优先搜索(DFS)进行递归遍历。在遍历过程中,逐步累加路径上的节点值,并在到达叶子节点时检查累加值是否等于目标和。

class Solution112 {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return false; // 空树直接返回 false
        }
        return dfs(root, targetSum); // 调用递归函数
    }

    // 递归函数,深度优先搜索
    private boolean dfs(TreeNode node, int sum) {
        if (node == null) {
            return false; // 到达空节点,返回 false
        }

        // 更新剩余的目标和
        sum -= node.val;

        // 如果当前节点是叶子节点,检查累加值是否等于目标和
        if (node.left == null && node.right == null) {
            return sum == 0;
        }

        // 递归检查左子树和右子树
        return dfs(node.left, sum) || dfs(node.right, sum);
    }
}

说明:方法dfs是递归函数,用于遍历二叉树。在遍历过程中,减去当前节点的值以更新剩余的目标和。如果当前节点是叶子节点(即左右子节点都为空),则检查当前累加值是否等于目标和。如果当前节点不是叶子节点,则递归检查其左子树和右子树

题目链接:113. 路径总和 II - 力扣(LeetCode)

为了找出二叉树中所有从根节点到叶子节点的路径,使得这些路径的节点值之和等于给定的目标和。

思路:使用深度优先搜索(DFS)进行递归遍历。在遍历过程中,记录当前路径上的节点值,当到达叶子节点并且路径和等于目标和时,将当前路径加入结果列表。

class Solution113 {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) {
            return result; // 如果树为空,返回空列表
        }
        List<Integer> currentPath = new ArrayList<>();
        dfs(root, targetSum, currentPath, result); // 调用递归函数
        return result;
    }

    // 递归函数,深度优先搜索
    private void dfs(TreeNode node, int sum, List<Integer> currentPath, List<List<Integer>> result) {
        if (node == null) {
            return; // 到达空节点,直接返回
        }

        // 将当前节点加入路径
        currentPath.add(node.val);
        sum -= node.val; // 更新剩余的目标和

        // 如果当前节点是叶子节点,检查累加值是否等于目标和
        if (node.left == null && node.right == null && sum == 0) {
            result.add(new ArrayList<>(currentPath)); // 将当前路径加入结果集
        } else {
            // 递归检查左子树和右子树
            dfs(node.left, sum, currentPath, result);
            dfs(node.right, sum, currentPath, result);
        }

        // 回溯,移除当前节点
        currentPath.remove(currentPath.size() - 1);
    }
}

方法dfs是递归函数,用于遍历二叉树。思路如上题,在遍历过程中,将当前节点值加入路径列表,并减去当前节点值以更新剩余的目标和。如果当前节点是叶子节点且路径和等于目标和,则将当前路径加入结果集;如果当前节点不是叶子节点,则递归检查其左子树和右子树。最后,回溯,移除当前节点

题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

要从中序遍历(inorder)和后序遍历(postorder)构造二叉树,我们需要理解这些遍历序列的性质:

  1. 后序遍历:后序遍历的最后一个元素是二叉树的根节点。
  2. 中序遍历:在中序遍历中,根节点将中序遍历序列分成左子树的节点和右子树的节点。

基于上述性质,我们可以递归地构建二叉树。具体步骤如下:

  1. 从后序遍历的最后一个元素取出当前子树的根节点。
  2. 在中序遍历中找到该根节点的位置,这样可以将中序遍历分成左子树和右子树两部分。
  3. 根据中序遍历左子树和右子树的大小,在后序遍历中划分出对应的左子树和右子树。
  4. 递归地构建左右子树。
class Solution106 {
    private int postIndex;
    private Map<Integer, Integer> inorderIndexMap;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        postIndex = postorder.length - 1;
        inorderIndexMap = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) {
            inorderIndexMap.put(inorder[i], i);
        }
        return buildTreeHelper(inorder, postorder, 0, inorder.length - 1);
    }

    // 递归方法,构建二叉树
    private TreeNode buildTreeHelper(int[] inorder, int[] postorder, int inorderStart, int inorderEnd) {
        if (inorderStart > inorderEnd) {
            return null;
        }

        // 从后序遍历数组中取出当前子树的根节点
        int rootVal = postorder[postIndex--];
        TreeNode root = new TreeNode(rootVal);

        // 在中序遍历数组中找到根节点的位置
        int inorderIndex = inorderIndexMap.get(rootVal);

        // 递归构建右子树和左子树(注意先构建右子树,再构建左子树,因为后序遍历从后向前处理)
        root.right = buildTreeHelper(inorder, postorder, inorderIndex + 1, inorderEnd);
        root.left = buildTreeHelper(inorder, postorder, inorderStart, inorderIndex - 1);

        return root;
    }
}

题目链接:105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

要从前序遍历(preorder)和中序遍历(inorder)构造二叉树,我们可以利用以下性质:

  1. 前序遍历:前序遍历的第一个元素是二叉树的根节点。
  2. 中序遍历:在中序遍历中,根节点将序列分为左子树的节点和右子树的节点。

基于这些性质,可以递归地构建二叉树。具体步骤如下:

  1. 从前序遍历的第一个元素取出当前子树的根节点。
  2. 在中序遍历中找到该根节点的位置,这样可以将中序遍历分成左子树和右子树两部分。
  3. 根据中序遍历左子树和右子树的大小,在前序遍历中划分出对应的左子树和右子树。
  4. 递归地构建左右子树。
class Solution105 {
    private int preIndex = 0;
    private Map<Integer, Integer> inorderIndexMap;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        inorderIndexMap = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) {
            inorderIndexMap.put(inorder[i], i);
        }
        return buildTreeHelper(preorder, inorder, 0, inorder.length - 1);
    }

    // 辅助递归方法,构建二叉树
    private TreeNode buildTreeHelper(int[] preorder, int[] inorder, int inorderStart, int inorderEnd) {
        if (inorderStart > inorderEnd) {
            return null;
        }

        // 从前序遍历数组中取出当前子树的根节点
        int rootVal = preorder[preIndex++];
        TreeNode root = new TreeNode(rootVal);

        // 在中序遍历数组中找到根节点的位置
        int inorderIndex = inorderIndexMap.get(rootVal);

        // 递归构建左子树和右子树
        root.left = buildTreeHelper(preorder, inorder, inorderStart, inorderIndex - 1);
        root.right = buildTreeHelper(preorder, inorder, inorderIndex + 1, inorderEnd);

        return root;
    }
}

思考:为什么前序和后序不能唯一确定一棵二叉树。

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有数组中的元素进行平方,并按照非递减的顺返回结果。这里由于数组已经是有的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值