404. 左叶子之和

计算给定二叉树的所有左叶子之和。

示例:

​ 3

/
9 20 /
15 7

在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/sum-of-left-leaves 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解:

二叉树的题目做多了,感觉到貌似一多半的题目,可以通过二叉树遍历来解决,前序/中序/后序/层序,总有一种适合你…的题目.

此题目中,是求左叶子之和,即为叶子节点 且 是其父节点的左子节点

我们是否可以通过 二叉树遍历 解决呢?

答案是可以的。

虽然遍历到当前元素current时,我们无法判断current是其父节点的左还是右。 但是当我们访问 其父节点时,就可以来判断,其左子节点是不是 叶子节点啊。如果是叶子节点,不就是满足要求的节点吗.

所以我们遍历整个二叉树, 当遍历的节点的 左子节点不为空, 且左子节点为叶子节点时, 就累加其左子节点的值。

直到遍历完一整颗二叉树,我们也就求出了最终结果

遍历方式有很多 前序 / 中序 / 后序 / 层序迭代 或者 递归 都可以解决此问题。

正好就趁此题,来复习下,二叉树的各种遍历啦。

递归

我们可以轻松的使用递归,实现 前序/中序/后序遍历, 即dfs遍历. 这里我们只写一种前序遍历。

代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    public int sumOfLeftLeaves(TreeNode root) {
			
        if (root == null) return result;
        if (root.left != null && root.left.left == null && root.left.right == null)
            result += root.left.val;

        sumOfLeftLeaves(root.left);
        sumOfLeftLeaves(root.right);

        return result;
    }


迭代

中序遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
     * 上边方法是递归,既然是dfs解决的问题
     * 那么使用迭代应该同样可以解决问题
     * <p>
     * 顺便复习下,迭代二叉树遍历
     */

    //迭代 中序遍历 因为写二叉搜索树的题目,用到中序遍历的情况特别多, 所以最熟悉的就是中序遍历 😳
    public int sumOfLeftLeaves1(TreeNode root) {
        if (root == null) return result;

        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || root != null) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }

            root = stack.pop();

            if (root.left != null && root.left.left == null && root.left.right == null)
                result += root.left.val;

            root = root.right;
        }
        return result;
    }

前序遍历

前序遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 迭代 前序遍历 说实话,一下子没想起来,在稿纸上自己画一画先
public int sumOfLeftLeaves2(TreeNode root) {
    if (root == null) return result;

    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        if (node.left != null && node.left.left == null && node.left.right == null)
            result += node.left.val;

        if (node.right != null) stack.push(node.right);
        if (node.left != null) stack.push(node.left);
    }
    return result;
}

后序遍历

后序遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 迭代 后序遍历
public int sumOfLeftLeaves3(TreeNode root) {
    if (root == null) return result;

    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    TreeNode pre = null;

    while (!stack.isEmpty()) {
        TreeNode node = stack.peek();
        if ((node.left == null && node.right == null) || (pre != null && (pre == node.left || pre == node.right))) {
            // 叶子节点 或者 上一个访问的节点是此节点的子节点时 出栈
            if (node.left != null && node.left.left == null && node.left.right == null)
                result += node.left.val;

            pre = node;
            stack.pop();
        } else {
            if (node.right != null) stack.push(node.right);
            if (node.left != null) stack.push(node.left);
        }
    }
    return result;
}

层序遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 迭代 层序遍历
public int sumOfLeftLeaves4(TreeNode root) {
    if (root == null) return 0;

    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root);
    while (!queue.isEmpty()){
        TreeNode node = queue.remove();

        if (node.left != null && node.left.left == null && node.left.right == null)
            result += node.val;

        if (node.left != null) queue.add(node.left);
        if (node.right != null) queue.add(node.right);
    }
    return result;
}

执行耗时

截屏2020-06-06上午1.16.17

以上是 从 方法一 -> 方法五的执行耗时。

递归最快,后序遍历最慢,前序/中序/层序时间一致

按理来说,时间复杂度都是 O(N), 执行时间相差大这个问题,先遗留下,以后研究下,再单独写一篇文章解释这个问题。