代码随想录算法训练营第 14 天 | 110. 平衡二叉树、257. 二叉树的所有路径、404. 左叶子之和、222. 完全二叉树的节点个数

110. 平衡二叉树

题目链接

递归,后序遍历判断左右子树是不是平衡二叉树。

class Solution {
    public boolean isBalanced(TreeNode root) {
        return getHeight(root) != -1;
    }

    public int getHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        if (leftHeight == -1 || rightHeight == -1) { // 如果左右字树有不是平衡二叉树的,那么这棵树一定不是
            return -1;
        }
        if (Math.abs(rightHeight - leftHeight) > 1) {
            return -1;
        }
        return 1 + Math.max(leftHeight, rightHeight);
    }
}

257. 二叉树的所有路径

题目链接

易错点:
把一条路径添加到集合时,要新建列表,不能用原来的,否则当移除时,路径也会跟着移除

递归 + 回溯

class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<Integer> path = new ArrayList<>();
        List<List<Integer>> list = new ArrayList<>();
        List<String> result = new ArrayList<>();
        traversal(root, path, list);
        for (List<Integer> e : list) {
            StringBuilder sb = new StringBuilder();
            int i = 0;
            for (; i < e.size() - 1; i++) {
                sb.append(e.get(i));
                sb.append("->");
            }
            sb.append(e.get(i));
            result.add(sb.toString());
        }
        return result;
    }

    public void traversal(TreeNode root, List<Integer> path, List<List<Integer>> list) {
        path.add(root.val);
        if (root.left == null && root.right == null) {
            list.add(new ArrayList<>(path)); // 注意这里必须创建新列表,不然移除时,已经保存的路径也会跟着移除
            return;
        }
        if (root.left != null) {
            traversal(root.left, path, list);
            path.remove(path.size() - 1); // 需要显示撤销,因为 path 是同一个引用,
            // 改成 traversal(root.left, new ArrayList<>(path), list) 就不用 remove 了
        }
        if (root.right != null) {
            traversal(root.right, path, list);
            path.remove(path.size() - 1);
        }
    }
}

404. 左叶子之和

题目链接

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if (root == null) {
            return 0;
        }
        if (root.left == null && root.right == null) { // 叶子节点,返回 0
            return 0;
        }
        int leftNum = sumOfLeftLeaves(root.left);
        if (root.left != null && root.left.left == null && root.left.right == null) {
            leftNum = root.left.val; // 特殊情况,要覆盖掉之前的 leftNum
        }
        int rightNum = sumOfLeftLeaves(root.right);
        return leftNum + rightNum;
    }
}

评论区题解看到的比较好的答案:
将是不是左叶子作为一个参数

class Solution {
public:
    int result;
    void dfs(TreeNode* root, bool is_left) {
        if(!root) return;
        dfs(root->left, true);
        dfs(root->right, false);
        if(!root->left && !root->right && is_left) {
            result += root->val;
        }
    }
    int sumOfLeftLeaves(TreeNode* root) {
        result = 0;
        dfs(root, false);
        return result;
    }
};

222. 完全二叉树的节点个数

题目链接

层序遍历复杂度:O(n)
利用完全二叉树特性复杂度:O(logN * logN),见链接

思路:
利用完全二叉树的特性。

因为是一颗完全二叉树,所以子树也都是完全二叉树,只是可能不是满二叉树罢了。那么我们求满二叉树是很好求的,可以根据公式 2 ^ n - 1来求。

所以,如果能判断树是满二叉树,那么就很好求了。如果树不是满二叉树,就判断左右子树是不是满二叉树。由此得出递归思路。

如何判断是不是满二叉树呢?(注意这里的前提一定是一颗完全二叉树)
一直向左和一直向右遍历,如果深度相等,就是满二叉树。

易错点:
(2 << leftDepth) - 1 需加括号,<< 优先级低于 -

class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftDepth = 0;
        int rightDepth = 0;
        for (TreeNode node = root.left; node != null; node = node.left) {
            leftDepth++;
        }
        for (TreeNode node = root.right; node != null; node = node.right) {
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (2 << leftDepth) - 1;
        }
        int leftNum = countNodes(root.left); // 左
        int rightNum = countNodes(root.right); // 右
        return 1 + leftNum + rightNum; // 中
    }
}

补充层序遍历(不重要):

class Solution {
    public int countNodes(TreeNode root) {
        Queue<TreeNode> queue = new ArrayDeque<>();
        if (root == null) {
            return 0;
        }
        queue.offer(root);
        int cnt = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (; size > 0; size--) {
                TreeNode temp = queue.poll();
                if (temp.left != null) {
                    queue.offer(temp.left);
                }
                if (temp.right != null) {
                    queue.offer(temp.right);
                }
                cnt++;
            }
        }
        return cnt;
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值