404. 左叶子之和
给定二叉树的根节点 root ,返回所有左叶子之和。
示例 1:
输入: root = [3,9,20,null,null,15,7]
输出: 24
解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
示例 2:
输入: root = [1]
输出: 0
提示:
- 节点数在
[1, 1000]范围内 -1000 <= Node.val <= 1000
无返回值的DFS,前序
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
dfs(root);
return sum;
}
// 记录左叶子之和
int sum = 0;
// 二叉树遍历函数
void dfs(TreeNode root) {
if (root == null) {
return;
}
// 前序位置,不能无条件累加当前节点的值,我们要算的是左叶子节点的和。注意这里操作的是当前节点和左子节点,不是只有当前节点。为什么要这样?因为左叶子节点=左+叶子,这一定需要两个节点才能判断。为什么不能通过当前节点和父节点判断?因为这样比较复杂。
if (root.left != null &&
root.left.left == null && root.left.right == null) {
// 找到左侧的叶子节点,记录累加值
sum += root.left.val;
}
// 递归框架
dfs(root.left);
dfs(root.right);
}
}
- 时间复杂度O(n),n是二叉树的节点总数
- 空间复杂度O(h),h是二叉树的高度
有返回值的DFS
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
// 调用递归函数,并从根节点开始。注意根节点不是左节点。
return dfs(root, false);
}
/**
* 递归函数,计算左叶子节点之和
*
* @param node 当前节点
* @param isLeft 标记当前节点是否是左节点
* @return 返回左叶子节点的和
*/
private int dfs(TreeNode node, boolean isLeft) {
if (node == null) {
return 0; // 如果节点为空,返回 0
}
// 判断是否为左叶子节点
if (node.left == null && node.right == null && isLeft) {
return node.val; // 如果是左叶子节点,返回该节点的值
}
// 递归求取左子树和右子树的左叶子之和
int leftSum = dfs(node.left, true); // 左子树,标记为左节点
int rightSum = dfs(node.right, false); // 右子树,标记为右节点
// 返回左子树和右子树中所有左叶子节点的和
return leftSum + rightSum;
}
}
- 时间复杂度O(n),n是二叉树的节点总数
- 空间复杂度O(h),h是二叉树的高度
BFS
class Solution {
/**
* 计算二叉树中所有左叶子节点的和
*
* @param root 二叉树的根节点
* @return 所有左叶子节点的和
*/
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) {
return 0; // 如果根节点为空,则返回0
}
Queue<TreeNode> queue = new LinkedList<>(); // 创建一个队列用于层次遍历
queue.offer(root); // 将根节点添加到队列中
int sum = 0; // 初始化左叶子节点和为0
while (!queue.isEmpty()) {
TreeNode currentNode = queue.poll(); // 从队列中取出当前节点
// 检查左右子节点是否存在,只入队非叶子节点,因为没必要入队叶子节点
if (currentNode.left != null) {
// 检查左子节点是否为叶子节点
if (isLeafNode(currentNode.left)) {
sum += currentNode.left.val; // 如果是叶子节点,则将其值累加到sum中。如果是叶子节点,则没必要加入队列了,只要把它的和算进去就好了,他没有子节点了。
} else {
queue.offer(currentNode.left); // 否则将左子节点添加到队列中继续遍历
}
}
// 检查右子节点是否存在且不是叶子节点,只入队非叶子节点的右子节点
if (currentNode.right != null && !isLeafNode(currentNode.right)) {
queue.offer(currentNode.right); // 将右子节点添加到队列中继续遍历
}
}
return sum; // 返回左叶子节点的和
}
/**
* 判断节点是否为叶子节点
*
* @param node 要判断的节点
* @return 如果节点是叶子节点,则返回true,否则返回false
*/
private boolean isLeafNode(TreeNode node) {
return node.left == null && node.right == null; // 如果节点的左子节点和右子节点都为空,则为叶子节点
}
}
- 时间复杂度:O(n),其中 n 是树中的节点个数。
- 空间复杂度:O(n)。空间复杂度与广度优先搜索使用的队列需要的容量相关,为 O(n)。