算法刷题 - 二叉树(查询二叉树左下角的值 + 路径总和 + 最大二叉树 + 合并二叉树 + 二叉搜索树搜索)

131 阅读6分钟

算法刷题博客封面.png

简介

题目01: 查询二叉树内最左侧最底部节点 (LeetCode 513)

题目02: 查询二叉树的路径总和 (LeetCode 112)

题目03: 构造最大二叉树 (LeetCode 654)

题目04: 合并二叉树 (LeetCode 617)

题目05: 二叉搜索树搜索 (LeetCode 700 )

题目 01 - 查询二叉树左下角的值

原题链接

LeetCode 513 - 找树左下角的值

题目描述

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

如果仅有根节点: 返回根节点的值

思路

方法

  • 层序遍历;借助队列结构
  • 修改入队顺序:如果右子节点不为空,右子节点先入队,再将左子节点入队
  • 出队顺序: 右子节点先出队,之后左子节点
  • 因此,每一层树层的最左侧节点为队列内的对尾节点

代码实现

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        // 检查输入
        if (root == null) {
            return 0;
        }

        // 队列,辅助遍历各个树层内的节点
        Deque<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

       /* 
         遍历每一树层
         入队顺序: 右 -> 左; 出队顺序: 右 -> 左;最左侧元素最后出队
        */
        int bottomLeft = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            while (size-- > 0) {
                TreeNode top = queue.pop();
                // 更新,每一层对尾元素为当前层的最左元素
                bottomLeft = top.val;
                // 右子节点先入队
                if (top.right != null) {
                    queue.offer(top.right);
                }
                // 左子节点先入队
                if (top.left != null) {
                    queue.offer(top.left);
                }
            }
        }
        return bottomLeft;
    }
}

执行结果

  • 时间复杂度: O(N)
  • 空间复杂度: O(N)

题目 02 - 求二叉树的路径总和

原题链接

LeetCode-112 路径总和

题目描述

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum

判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum

如果存在,返回 true ;否则,返回 false

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

思路

方法

  • 递归 递归返回条件:
  1. 如果当前路径之和等于 targetSum, 且已经抵达叶子节点,返回true
  2. 当前节点为空返回 false
  3. 单层遍历条件:
  • 如果左子节点不为空:
    • 更新之前记录当前 currVal = sum;
    • 更新 sum + node.left.val
    • 返回当前层后 sum = currVal
  • 如果右子节点不为空,同理

代码实现

class Solution {

    public boolean hasPathSum(TreeNode root, int targetSum) {
        //检查输入
        if (root == null) {
            return false;
        }
        if(root.left == null && root.right == null) {
            return root.val == targetSum;
        }
        return isPathExist(root, root.val, targetSum);
    }

    public boolean isPathExist(TreeNode node, int sum, int targetSum) {
        if (node == null) {
            return false;
        }
        // 如果和满足并且抵达一个叶子节点
        if (sum == targetSum && node.left == null && node.right == null) {
            return true;
        }
        // 左子节点不为空
        boolean isLeftExist = false;
        if (node.left != null) {
            // 更新路径之和
            isLeftExist = isPathExist(node.left, sum + node.left.val, targetSum);
        }
        // 右子节点不为空
        boolean isRightExist = false;
        if (node.right != null) {
            // 更新路径之和
            isRightExist = isPathExist(node.right, sum + node.right.val, targetSum);
        }
        return isLeftExist || isRightExist;
    }
}

执行结果

  • 时间复杂度: O(N)
  • 空间复杂度: O(H)

题目 03 - 最大二叉树

原题链接

LeetCode - 654 最大二叉树

题目描述

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

  • 创建一个根节点,其值为 nums 中的最大值。
  • 递归地在最大值 左边 的 子数组前缀上 构建左子树。
  • 递归地在最大值 右边 的 子数组后缀上 构建右子树。
  • 返回 nums 构建的 最大二叉树 。

思路

方法

  • 递归
  • 借助左右指针 left right 遍历数组:
  • 每层递归内
  1. 遍历区间 [left, right] 获取最大节点值所在的下标 maxIdx
  2. 基于最大值所在的下标划分当前左半区为 [left, maxIdx] 右半区为 [maxIdx + 1, right]
  3. 递归返回条件:
  • a. left < right, 无节点值可用;返回空
  • b. left = right; 叶子节点值;构造一个节点返回
  1. 设当前层内父节点为 node, node.left 通过左半区 [left, maxIdx] 得到; node.right 通过右半区得到 [maxIdx + 1, rightIdx]

代码实现

class Solution {

    public boolean hasPathSum(TreeNode root, int targetSum) {
        //检查输入
        if (root == null) {
            return false;
        }
        if(root.left == null && root.right == null) {
            return root.val == targetSum;
        }
        return isPathExist(root, root.val, targetSum);
    }

    public boolean isPathExist(TreeNode node, int sum, int targetSum) {
        if (node == null) {
            return false;
        }
        // 如果和满足并且抵达一个叶子节点
        if (sum == targetSum && node.left == null && node.right == null) {
            return true;
        }
        // 左子节点不为空
        boolean isLeftExist = false;
        if (node.left != null) {
            // 更新路径之和
            isLeftExist = isPathExist(node.left, sum + node.left.val, targetSum);
        }
        // 右子节点不为空
        boolean isRightExist = false;
        if (node.right != null) {
            // 更新路径之和
            isRightExist = isPathExist(node.right, sum + node.right.val, targetSum);
        }
        return isLeftExist || isRightExist;
    }
}

执行结果

  • 时间复杂度: O(N)
  • 空间复杂度: O(H)

题目 04 - 合并二叉树

原题链接

LeetCode - 617 合并二叉树

题目描述

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。

你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;

否则,不为 null 的节点将直接作为新二叉树的节点。 返回合并后的二叉树。 注意: 合并过程必须从两个树的根节点开始。

思路

方法

  • 递归
  • 递归返回条件: 节点为空
  1. 如果 node1 左子树为空而 node2 左子树不为空; 将其加入到node1作为左子节点
  2. 如果 node1 右子树为空而 node2 右子树不为空; 将其加入到node1作为左子节点
  3. 如果 node1 和 node2 当前都不为空,累加值 node1.val += node2.val

代码实现

class Solution {

    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        //递归返回条件一: 都为空
        if(root1 == null && root2 == null) {
            return null;
        }
        //返回条件二, 其中一个子树为空,返回另一个
        if(root1 == null && root2 != null) {
            return root2;
        }
        if(root1 != null && root2 == null) {
            return root1;
        }   
        //以 root1 树为基树,将root2合并至root1
        root1.val += root2.val;     //合并,累加值
        root1.left = mergeTrees(root1.left, root2.left);    //合并左子树
        root1.right = mergeTrees(root1.right, root2.right); //合并右子树
        return root1;
    }
}

代码简化

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        //递归返回条件
        if(root2 == null) return root1;
        if(root1 == null) return root2;
        
        //两个结点值相加
        root1.val += root2.val;

        //将 root2 合并到 root1 树
        root1.left = mergeTrees(root1.left, root2.left);
        root1.right = mergeTrees(root1.right, root2.right);

        return root1;
    }

}

执行结果

  • 时间复杂度: O(N)
  • 空间复杂度: O(H)

题目 05 - 二叉搜索树搜索

原题链接

LeetCode - 700 二叉搜索树

题目描述

给定二叉搜索树(BST)的根节点 root 和一个整数值 val。

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

思路

方法

  • 递归
  • 由于二叉搜索树,如果当前父节点值比 val 小,递归查找左子树
  1. 否则,递归查找右子树
  2. 直到 node.val == val

代码实现

class Solution {

    public TreeNode searchBST(TreeNode root, int val) {
        //递归返回条件,为空或者找到匹配的子树根节点
        if(root == null || root.val == val) {   
            return root;
        }
        //比val小,递归查找左子树
        if(root.val < val) {
            return searchBST(root.right, val);
        }
        //比val大,递归查找右子树
        if(root.val > val) {
            return searchBST(root.left, val);
        }
        //无则返回null
        return null;
    }
}

执行结果

  • 时间复杂度: O(logN)
  • 空间复杂度: O(H)

参考

  1. 代码随想录 - 查找而二叉树内最左下角的值
  2. 代码随想录 - 路径总和
  3. 代码随想录 - 构造最大二叉树
  4. 代码随想录 - 合并二叉树
  5. 代码随想录 - 二叉树搜索树搜索