一、题目
1、审题
2、分析
求一棵完全二叉树的节点个数。
二、解答
1、思路
方法一、
将二叉树将 root 节点分为左右两颗子树。
①、若右子树的高度 小于 左子树的高度,则此完全二叉树的最后一个节点落于 左子树,则右子树是一棵高度为 h - 2 的完全二叉树;
节点数等于 1 << h - 2 + nodes(left);
②、若右子树的高度 等于 左子树的高度,则最后一个节点落于右子树,则左子树是一棵高度为 h - 1 的完全二叉树。
节点数等于 1 << h - 1 + nodes(right)。
1 public int countNodes(TreeNode root) { 2 3 int h = getHeight(root); // 根节点的最大高度 4 5 if(h < 1) 6 return 0; 7 // 右孩子的最大高度 8 int rightChildHeight = getHeight(root.right); 9 // 完全二叉树的最后一个孩子在 root 的右孩子上, 则 root 左孩子是 高度为 h - 1 的满二叉树 10 if(rightChildHeight == h - 1) 11 return (1 << h - 1) + countNodes(root.right); 12 else 13 // root 右孩子是层次为 n - 2 的满二叉树 14 return (1 << h - 2) + countNodes(root.left); 15 } 16 17 // 获得 root 的最大高度 18 private int getHeight(TreeNode root) { 19 return root == null ? 0 : 1 + getHeight(root.left); 20 }
方法二、
采用循环,每次将所要求得完全二叉树缩小成右子树或左子树;
不用重复调用方法求 h,h--即可。
1 public int countNodes(TreeNode root) { 2 int nodes = 0; 3 int h = getHeight(root); 4 while(root != null) { 5 //最后一个节点在右子树, 左子树是满二叉树 6 if(getHeight(root.right) == h - 1) { 7 nodes += (1 << h - 1); 8 root = root.right; 9 } 10 else { 11 nodes += (1 << h - 2); 12 root = root.left; 13 } 14 h--; 15 } 16 return nodes; 17 } 18 19 // 获得 root 的最大高度 20 private int getHeight(TreeNode root) { 21 return root == null ? 0 : 1 + getHeight(root.left); 22 }
方法三、
不用单独求树的高度,采用递归,每次必有左子树或右子树为满二叉树,在递归求另一边非满二叉树即可。
public int countNodes(TreeNode root) { if(root == null) return 0; TreeNode left = root, right = root; int height = 0; while(right != null) { left = left.left; right = right.right; height++; } if(left == null) // 满二叉树 return (1 << height) - 1; return 1 + countNodes(root.left) + countNodes(root.right); }