LeetCode刷题Day14——二叉树(完全二叉树、平衡二叉树、二叉树路径、左叶子之和)

简介: 一、完全二叉树的节点个数题目链接:222. 完全二叉树的节点个数

一、完全二叉树的节点个数

题目链接:222. 完全二叉树的节点个数

/**
 * <pre>
 * 1.二分查找+位运算
 * 2.递归:如果子树是完全二叉树则直接返回子树的节点数,如果不是完全二叉树则继续判断其左右子树
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/15 10:54
 */
public class 完全二叉树的节点个数222 {
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        TreeNode node = root;
        int h = 0;
        while (node.left != null) {
            h++;
            node = node.left;
        } // 求出最大高度
        int left = 1 << h, right = (1 << (h+1)) - 1; // 最下一层节点的标号
        while (left <= right) {
            int mid = ((right - left) >> 1) + left;
            if (check(root, h, mid)) {
                // 该节点存在,则往右查找
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return right;
    }
    public boolean check(TreeNode root, int height, int index) {
        int bits = 1 << (height-1);
        TreeNode node = root;
        while (node != null && bits > 0) {
            // &运算可以用来求一个数中的指定位,将要判断的那一位置为1,其他位为0,然后用这个数和指定数想与,结果如果为0就说明对应位置为0,结果如果不为0就说明对应位置为1
            // 此处我们要判断index的第二位到结束的每一位是0还是1来决定是往左走还是往右走,这里用bits来控制
            // 最开始bits=1<<(height-1)其实就是一个首位为1(因为是height-1所以这里的首位对应的是index的第二位),其他都为0的数
            // 然后每次判断后就对bits右移1位,即然后1后移以判断index后面的位是否为1
            // 比如index=5,即101,首位不用看,第二位0就说明从根节点先像左走,第三位为1就说明第二步是往右走即可到达结点5
            if ((index & bits) == 0) {
                node = node.left;
            } else {
                node = node.right;
            }
            bits >>= 1;
        }
        return node != null;
    }
    public int countNodes2(TreeNode root) {
        if (root == null) {
            return 0;
        }
        TreeNode left = root.left;
        TreeNode right = root.right;
        int leftHeight = 0, rightHeight = 0;
        while (left != null) {
            left = left.left;
            leftHeight++;
        }
        while (right != null) {
            right = right.right;
            rightHeight++;
        }
        if (leftHeight == rightHeight) {
            return (1 << (leftHeight+1)) - 1;
        }
        return countNodes2(root.left) + countNodes2(root.right) + 1;
    }
}

二、平衡二叉树

题目链接:110. 平衡二叉树

/**
 * <pre>
 * 1.自顶向下递归,不断求左右节点的高度判断差值是否大于1(每个节点的高度会被重复计算)
 * 2.自底向上递归,采用后续遍历,从最下的节点开始,求其左右节点高度,判断是否平衡,如果不平衡则整棵树不平衡,如果平衡则继续往上判断
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/15 14:33
 */
public class 平衡二叉树110 {
    public boolean isBalanced(TreeNode root) {
        if (root == null) {
            return true;
        }
        if (Math.abs(getHeight(root.left) - getHeight(root.right)) > 1) { // 判断当前节点左右子树是否平衡
            return false;
        }
        return isBalanced(root.left) && isBalanced(root.right); // 如果平衡则继续往下判断左右子节点
    }
    public int getHeight(TreeNode treeNode) {
        if (treeNode == null) {
            return 0;
        }
        return Math.max(getHeight(treeNode.left), getHeight(treeNode.right)) + 1;
    }
    public boolean isBalanced2(TreeNode root) {
        return getHeight2(root) >= 0;
    }
    public int getHeight2(TreeNode treeNode) {
        if (treeNode == null) {
            return 0;
        }
        int leftHeight = getHeight2(treeNode.left);
        int rightHeight = getHeight2(treeNode.right);
        if (leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {
            return -1; // 相当于后续遍历,到最下面一个节点后判断其左右子树是否平衡,不平衡则返回-1,如果子节点的高度已经是-1了则肯定不平衡了直接返回-1
        }
        return Math.max(leftHeight, rightHeight) + 1;
    }
}

三、二叉树的所有路径

题目链接:257. 二叉树的所有路径

/**
 * <pre>
 * 1.深度优先搜索
 * 2.广度优先搜索
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/15 23:46
 */
public class 二叉树的所有路径227 {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<>();
        traversal(res, new StringBuilder(), root);
        return res;
    }
    public void traversal(List<String> res, StringBuilder path, TreeNode root) {
        TreeNode left = root.left;
        TreeNode right = root.right;
        if (left == null && right == null) {
            res.add(path.toString() + root.val); // 不能用path.append后再toString,会导致path值改变
            return;
        }
        int len = path.length();
        path.append(root.val).append("->");
        if (left != null) {
            traversal(res, path, left);
        }
        if (right != null) {
            traversal(res, path, right);
        }
        path.delete(len, path.length()); // 回溯
    }
    public List<String> binaryTreePaths2(TreeNode root) {
        List<String> res = new ArrayList<>();
        Queue<TreeNode> nodeQueue = new LinkedList<>();
        Queue<String> pathQueue = new LinkedList<>();
        nodeQueue.offer(root);
        pathQueue.offer(String.valueOf(root.val));
        while (!nodeQueue.isEmpty()) {
            TreeNode treeNode = nodeQueue.poll();
            String path = pathQueue.poll();
            if (treeNode.left == null && treeNode.right == null) {
                res.add(path);
            }
            if (treeNode.left != null) {
                nodeQueue.offer(treeNode.left);
                pathQueue.offer(path + "->" + treeNode.left.val);
            }
            if (treeNode.right != null) {
                nodeQueue.offer(treeNode.right);
                pathQueue.offer(path + "->" + treeNode.right.val);
            }
        }
        return res;
    }
}

四、左叶子之和

题目链接:404. 左叶子之和

/**
 * <pre>
 * 1.深搜
 * 2.广搜
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/15 23:46
 */
public class 左叶子之和404 {
    public int sumOfLeftLeaves(TreeNode root) {
        if (root == null) {
            return 0;
        }
        return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right) + (root.left != null && root.left.left == null && root.left.right == null ? root.left.val : 0); // 等于左子树左叶子节点和+右子树左叶子节点和
    }
    public int sumOfLeftLeaves2(TreeNode root) {
        if (root == null) {
            return 0;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int sum = 0;
        while (!queue.isEmpty()) {
            TreeNode poll = queue.poll();
            if (poll.left != null) {
                if (poll.left.left == null && poll.left.right == null) {
                    sum += poll.left.val;
                } else {
                    queue.offer(poll.left);
                }
            }
            if (poll.right != null) {
                queue.offer(poll.right);
            }
        }
        return sum;
    }
}
相关文章
|
1月前
【LeetCode 35】112.路径总和
【LeetCode 35】112.路径总和
24 0
|
1月前
【LeetCode 36】113.路径总和II
【LeetCode 36】113.路径总和II
28 0
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
16 1
|
1月前
【LeetCode 33】110.平衡二叉树
【LeetCode 33】110.平衡二叉树
11 1
|
1月前
【LeetCode 43】236.二叉树的最近公共祖先
【LeetCode 43】236.二叉树的最近公共祖先
19 0
|
1月前
【LeetCode 38】617.合并二叉树
【LeetCode 38】617.合并二叉树
14 0
|
1月前
【LeetCode 37】106.从中序与后序遍历构造二叉树
【LeetCode 37】106.从中序与后序遍历构造二叉树
16 0
|
1月前
【LeetCode 34】257.二叉树的所有路径
【LeetCode 34】257.二叉树的所有路径
16 0
|
1月前
【LeetCode 32】111.二叉树的最小深度
【LeetCode 32】111.二叉树的最小深度
16 0
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行