代码随想录day16-二叉树(4)
1、LeetCode 222 完全二叉树的节点个数
题目分析:
本题要求统计完全二叉树的结点个数。首先我们不按照完全二叉树的思路来的话,直接就为了统计结点的个数,那么使用深度优先以及广度优先都是可以办到的,但是我们没有充分利用完全二叉树的特点。
完全二叉树可以分为满二叉树和普通的完全二叉树。对于满二叉树而言,每一层的是满的,我们只要得到了层数i,那么节点的个数即使
2
i
−
1
2^i-1
2i−1个。那么如何判断二叉树是不是满二叉树呢?
我们只需要沿着根节点不断向左,以及不断向右,记录到叶子结点的层数,如果左右层数相等,就说明这个二叉树是满二叉树。
然后对于一些普通话的完全二叉树的,我们就可以使用后序遍历来做。
题目解答:
递归法:(使用后序遍历)
class Solution {
public:
int countNodes(TreeNode* root) {
if (root == nullptr) return 0;
int leftCountNode = countNodes(root->left); // 左
int rightCountNode = countNodes(root->right); // 右
return 1 + leftCountNode + rightCountNode;
}
};
层序遍历法:
class Solution {
public:
int countNodes(TreeNode* root) {
if (root == nullptr) return 0;
// 使用层序遍历法也是可以做的
queue<TreeNode*> que;
que.push(root);
int ans = 0;
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
ans++;
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return ans;
}
};
上述的两种方法都没有很好的利用完全二叉树的特性,以下是更好的解法:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
// 注意这个题目给定的就完全二叉树,可以充分利用完全二叉树的性质
if (root == nullptr) return 0; // 遇到空结点就返回
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
// 判断子树是不是满二叉树,如果左结点一直向左的深度等于右结点一直向右的深度,就代表是满二叉树
while (left) {
left = left->left;
leftDepth++;
}
while (right) {
right = right->right;
rightDepth++;
}
if (leftDepth == rightDepth) return (2 << leftDepth) - 1; // 满二叉树的结点个数是2^i - 1
// 下面就是非满二叉树的情况
int leftTreeNum = countNodes(root->left); // 左
int rightTreeNum = countNodes(root->right); // 右
int result = leftTreeNum + rightTreeNum + 1; // 中
return result;
}
};
上述的方法单独判断了是不是满二叉树的情况。
2、LeetCode 110 平衡二叉树
题目分析:
本题也可以使用后序遍历的方法求左右子树的高度,然后比较其高度差是不超过1即可。
题目解答:
class Solution {
public:
// 肯定是需要计算得到树的高度的
int getHeight( TreeNode* node) {
if (node == nullptr) return 0;
int leftHeight = getHeight(node->left);
if (leftHeight == -1) return -1; // 注意这里为什么需要加这两个条件
int rightHeight = getHeight(node->right);
if (rightHeight == -1) return -1;
// 如果高度差超过1,说明肯定不是平衡二叉树,直接返回-1
if (abs(leftHeight - rightHeight) > 1) {
return -1;
}
return 1 + max(leftHeight, rightHeight);
}
bool isBalanced(TreeNode* root) {
return getHeight(root) == -1 ? false : true;
}
};
注意: 上述代码里面的if (leftHeight == -1) return -1;
以及if (rightHeight == -1) return -1;
不能缺少,因为以根节点的左右结点为根节点的左右子树都不是平衡树的话,那肯定就是不符合答案的。
如果没有这两句话,那么假设**leftHeight = -1, rightHeight = -1**
的话,这个时候是不满足题意的,但是返回的却是1,即判定为平衡树。所以这里需要注意。
通过本题可以了解求二叉树深度 和 二叉树高度的差异,求深度适合用前序遍历,而求高度适合用后序遍历。