【二叉树 2.3】222. 完全二叉树的节点个数(利用完全二叉树的性质,时间复杂度O(lgN))

155 阅读1分钟

文章目录

普通二叉树结点个数计算,时间复杂度O(n)

其实不需要是完全二叉树,可以是二叉树节点个数,就是一个二叉树遍历(不包括null节点),不知道为什么还是中等难度,解法包括:递归三遍历、迭代三遍历、层序遍历

最简单的方法(递归)

class Solution {
    public int countNodes(TreeNode root) {
        if(root == null) {   // 防止下面的root.left root.right 空指针异常
    		return 0;
    	}
        return  1+ countNodes(root.left) + countNodes(root.right);  // 中左右  中每次加1,左子树遍历,右子树遍历
    }
}

前序递归

class Solution {
    List<Integer> list=new ArrayList<>();  // 返回值为list,但是参数中没有list,所以必须新建一个list盛放返回值
    public int countNodes(TreeNode root) {
        if (null == root) return list.size();  // null==root判断要在三个之前,防止空指针   return;返回一个完成标志就好了
        list.add(root.val);  // 中
        countNodes(root.left);  // 左
        countNodes(root.right);  // 右
        return list.size();
    }
}

中序递归

class Solution {
    List<Integer> list=new ArrayList<>();  // 返回值为list,但是参数中没有list,所以必须新建一个list盛放返回值
    public int countNodes(TreeNode root) {
        if (null == root) return list.size();  // null==root判断要在三个之前,防止空指针   return;返回一个完成标志就好了
        countNodes(root.left);  // 左
        list.add(root.val);  // 中
        countNodes(root.right);  // 右
        return list.size();
    }
}

后序递归

class Solution {
    List<Integer> list=new ArrayList<>();  // 返回值为list,但是参数中没有list,所以必须新建一个list盛放返回值
    public int countNodes(TreeNode root) {
        if (null == root) return list.size();  // null==root判断要在三个之前,防止空指针   return;返回一个完成标志就好了
        countNodes(root.left);  // 左
        countNodes(root.right);  // 右
        list.add(root.val);  // 中
        return list.size();
    }
}

前序迭代

class Solution {
    public int countNodes(TreeNode root) {
        if (null == root) return 0;  // null==root判断要在三个之前,防止空指针   return;返回一个完成标志就好了
        List<Integer> list=new ArrayList<>();  // 返回值为list,但是参数中没有list,所以必须新建一个list盛放返回值
        Stack<TreeNode> stack=new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.peek(); //
            if (node!=null){
                stack.pop();
               if (node.right !=null)stack.push(node.right);  // 这一条if保证插入的不是一个null,后面取出node.val的时候不是空指针异常
                if (node.left !=null) stack.push(node.left);
                stack.push(node);stack.push(null);
            }else{
                stack.pop();
                node = stack.pop();
                list.add(node.val);
            }
        }
        return list.size();
    }
}

中序迭代

class Solution {
    public int countNodes(TreeNode root) {
        if (null == root) return 0;  // null==root判断要在三个之前,防止空指针   return;返回一个完成标志就好了
        List<Integer> list=new ArrayList<>();  // 返回值为list,但是参数中没有list,所以必须新建一个list盛放返回值
        Stack<TreeNode> stack=new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.peek(); //
            if (node!=null){
                stack.pop();
               if (node.right !=null)stack.push(node.right);  // 这一条if保证插入的不是一个null,后面取出node.val的时候不是空指针异常
                stack.push(node);stack.push(null);
                if (node.left !=null) stack.push(node.left);
            }else{
                stack.pop();
                node = stack.pop();
                list.add(node.val);
            }
        }
        return list.size();
    }
}

后序迭代

class Solution {
    public int countNodes(TreeNode root) {
        if (null == root) return 0;  // null==root判断要在三个之前,防止空指针   return;返回一个完成标志就好了
        List<Integer> list=new ArrayList<>();  // 返回值为list,但是参数中没有list,所以必须新建一个list盛放返回值
        Stack<TreeNode> stack=new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            TreeNode node = stack.peek(); //
            if (node!=null){
                stack.pop();
                stack.push(node);stack.push(null);
                if (node.right !=null)stack.push(node.right);  // 这一条if保证插入的不是一个null,后面取出node.val的时候不是空指针异常
                if (node.left !=null) stack.push(node.left);
            }else{
                stack.pop();
                node = stack.pop();
                list.add(node.val);
            }
        }
        return list.size();
    }
}

层序遍历

class Solution {
    public int countNodes(TreeNode root) {
        if (null == root) return 0;  // null==root判断要在三个之前,防止空指针   return;返回一个完成标志就好了
        List<Integer> list=new ArrayList<>();  // 返回值为list,但是参数中没有list,所以必须新建一个list盛放返回值
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            int size = queue.size(); //
            for (int i=0;i<size;i++){
                TreeNode node = queue.poll();
                list.add(node.val);   // 层序遍历类似前序遍历,中左右
                if (node.left!=null) queue.offer(node.left);   // 这一条if保证插入的不是一个null,后面取出node.val的时候不是空指针异常
                if (node.right!=null) queue.offer(node.right);
            }
        }
        return list.size();
    }
}

层序遍历类似前序遍历,中左右

利用完成二叉树的性质,时间复杂度O(logN)

二分查找 + 位运算

class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int level = 0;
        TreeNode node = root;
        while (node.left != null) {
            level++;
            node = node.left;
        }
        int low = 1 << level, high = (1 << (level + 1)) - 1;
        while (low < high) {
            int mid = (high - low + 1) / 2 + low;
            if (exists(root, level, mid)) {
                low = mid;
            } else {
                high = mid - 1;
            }
        }
        return low;
    }

    public boolean exists(TreeNode root, int level, int k) {
        int bits = 1 << (level - 1);
        TreeNode node = root;
        while (node != null && bits > 0) {
            if ((bits & k) == 0) {
                node = node.left;
            } else {
                node = node.right;
            }
            bits >>= 1;
        }
        return node != null;
    }
}