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;
    }
}
相关文章
|
15天前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-2
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
15天前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-1
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
15天前
|
算法
二刷力扣--二叉树(3)
二刷力扣--二叉树(3)
|
15天前
二刷力扣--二叉树(2)
二刷力扣--二叉树(2)
|
15天前
二刷力扣--二叉树(1)基础、遍历
二刷力扣--二叉树(1)基础、遍历
|
16天前
|
索引
【LeetCode刷题】二分查找:山脉数组的峰顶索引、寻找峰值
【LeetCode刷题】二分查找:山脉数组的峰顶索引、寻找峰值
|
16天前
【LeetCode刷题】前缀和解决问题:742.寻找数组的中心下标、238.除自身以外数组的乘积
【LeetCode刷题】前缀和解决问题:742.寻找数组的中心下标、238.除自身以外数组的乘积
|
16天前
【LeetCode刷题】二分查找:寻找旋转排序数组中的最小值、点名
【LeetCode刷题】二分查找:寻找旋转排序数组中的最小值、点名
|
16天前
|
算法
【LeetCode刷题】滑动窗口解决问题:串联所有单词的子串(困难)、最小覆盖子串(困难)
【LeetCode刷题】滑动窗口解决问题:串联所有单词的子串(困难)、最小覆盖子串(困难)
|
16天前
|
算法 容器
【LeetCode刷题】滑动窗口解决问题:水果成篮、找到字符串中所有字母异位词
【LeetCode刷题】滑动窗口解决问题:水果成篮、找到字符串中所有字母异位词