题目一:二叉树的递归遍历(前中后序遍历)
解题思路:
方法一:递归三步法:
1.确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
2.确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
3.确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
以前序遍历为例:
1.确定递归函数的参数和返回值:因为要打印出前序遍历节点的数值,所以参数里需要传入vector来放节点的数值,除了这一点就不需要再处理什么数据了也不需要有返回值,所以递归函数返回类型就是void;
2.确定终止条件:在递归的过程中,如何算是递归结束了呢,当然是当前遍历的节点是空了,那么本层递归就要结束了,所以如果当前遍历的这个节点是空,就直接return;
3.确定单层递归的逻辑:前序遍历是中左右的循序,所以在单层递归的逻辑,是要先取中节点的数值。
代码:
/**
* 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:
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
vec.push_back(cur->val); // 中
traversal(cur->left, vec); // 左
traversal(cur->right, vec); // 右
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root, result);
return result;
}
};
//中序遍历
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
traversal(cur->left, vec); // 左
vec.push_back(cur->val); // 中
traversal(cur->right, vec); // 右
}
//后序遍历
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
traversal(cur->left, vec); // 左
traversal(cur->right, vec); // 右
vec.push_back(cur->val); // 中
}
方法二:二叉树的迭代遍历:使用栈
1.前序遍历
前序遍历的顺序是中左右,每次都是先处理根节点,再处理子节点,那么我们可以先把根节点放进栈中,然后把根节点取出放进数组当中,然后再将右节点放进栈中,再把左节点放进栈中。因为栈是后进先出的,所以先出来的是左节点,最后才是右节点。
代码:
/**
* 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:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == nullptr) return result;
st.push(root);
while(!st.empty())
{
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if (node->right) st.push(node->right);
if (node->left) st.push(node->left);
}
return result;
}
};
2.后续遍历
正常的后续遍历顺序为左右中,我们可以根据前序遍历进行修改,前序遍历为中左右,调整一下顺序可以变成中右左,再将所得数组进行翻转,就可以得到后续遍历的数组:左右中。
代码:
/**
* 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:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode *> st;
vector<int> result;
if (root == nullptr) return result;
st.push(root);
while (!st.empty())
{
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if (node->left) st.push(node->left);
if (node->right) st.push(node->right);
}
reverse(result.begin(), result.end());
return result;
}
};
3.中序遍历
中序遍历与前后序遍历相比是有所差异的,前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,所以刚刚才能写出相对简洁的代码,因为要访问的元素和要处理的元素顺序是一致的,都是中间节点。而中序遍历,中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。
我们先使用一个指针遍历二叉树,先访问到最底层,将最底层的左节点放进栈内(先判断其左子节点为空,将其放入栈内之后再操作其右子节点)
代码:
/**
* 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:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode *> st;
TreeNode* cur = root;
while (cur!=nullptr || !st.empty())
{
if (cur != nullptr)// 指针来访问节点,访问到最底层
{
st.push(cur);// 将访问的节点放进栈
cur = cur->left;// 左
}else
{//此时已知左孩子为空
cur = st.top();// 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
st.pop();
result.push_back(cur->val);// 中
cur = cur->right;// 右
}
}
return result;
}
};
题目二:二叉树的层序遍历
题目描述:
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
解题思路:
层序遍历,我们可以理解为从左到右一层一层的遍历;即遍历完一层就记录一下当前层的元素,再遍历下一层的元素。我们可以使用一个队列,先遍历到的元素先放进队列,队列是先进先出,这样上一层的元素都遍历完,弹出以后,队列中存放的就是下一层的元素值。就以下面的二叉树为例:
这个二叉树的根节点是6,先将6放进队列当中,这个时候我们需要定义一个size值,来记录当前队列中有几个元素,也就是当前层共有多少个元素。第一层就一个元素,记录size值为1,只需要弹出一个元素,弹出6以后,将6的左孩子和右孩子,也就是4,7两个元素加入队列。这个时候,记录size为2,第二层有两个元素;也就是第二层需要从队列中弹出2个元素。先弹出4,将4的左孩子,右孩子1和3加入队列;此时队列中的元素有:7,1,3。我们之前记录了,第二层的size是2,还需要再弹出一个元素,也就是把7也弹出,这个时候,把5和8加入队列。此时队列中的元素为:1,3,5,8。共计4个元素,此时记录size为4,第三层需要从队列中弹出4个元素。后面的操作与前面类似,先弹出队列的第一个元素,然后将第一个元素的左孩子和右孩子加入队列,当4个元素都弹出以后,记录一下当前队列的size值。循环往复,一直到不符合循环条件为止。
代码:
/**
* 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:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode *> que;//定义一个队列,存放遍历过的元素,先进先出
if(root != NULL) que.push(root);//根节点不为空的话,就把他加进队列当中
vector<vector<int>> result;//一个二维数组,存放最后的结果
while (!que.empty())//队列中有元素就一直循环遍历
{
int size = que.size();//size记录本层的元素数量,也就是本层需要弹出的元素数量
//因为会出现队列中同时存在本层元素和本层元素下一层元素的情况,比如同时出现第二层和第三层的元素
vector<int> vec;//定义一个数组,存放当前层的元素
for (int i=0; i<size; i++)//循环将本层的所有元素弹出,加入到数组中,并将下一层的元素加入到队列当中
//一定用size,不要用que.size(),因为que.size()是不断变化的
{
TreeNode* node = que.front();//将队列的第一个元素取出
que.pop();
vec.push_back(node->val);//将元素放入数组
if(node->left) que.push(node->left);//如果该元素存在左右孩子,就把他们加进队列当中
if(node->right) que.push(node->right);
}
result.push_back(vec);//将一维数组,加入二维数组当中
}
return result;
}
};
题目三:翻转二叉树
题目描述:
翻转一棵二叉树
解题思路:
翻转二叉树,其实就把每一个节点的左右孩子交换一下就可以了,遍历的过程中去翻转每一个节点的左右孩子就可以达到整体翻转的效果。
前序和后序遍历都可以实现,中序遍历稍微绕一些。
中序遍历的顺序是左根右,当我们翻转完1和3,回到2;将2和7调换以后,原来的左子树成了右子树,右子树成了左子树。而中序遍历的顺序是左根右,就相当于原来的右子树现在成了左子树,再次操作的时候,还是操作的原来的左子树(2,3,1).7,6,9这颗子树就没有被操作过。因此递归遍历的时候,处理完左,根,最后还是要处理左。
代码:
1.前序遍历:根左右
/**
* 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:
TreeNode* invertTree(TreeNode* root) {
if(root == NULL) return root;
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
};
2.后续遍历:左右根
/**
* 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:
TreeNode* invertTree(TreeNode* root) {
if(root == NULL) return root;
invertTree(root->left);
invertTree(root->right);
swap(root->left, root->right);
return root;
}
};
3.中序遍历:左根右
/**
* 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:
TreeNode* invertTree(TreeNode* root) {
if(root == NULL) return root;
invertTree(root->left);
swap(root->left, root->right);
invertTree(root->left);//原来的左子树变成右子树,右子树变成左子树,要处理之前没处理过的子树
return root;
}
};
题目四:对称二叉树
题目描述:
给定一个二叉树,检查它是否是镜像对称的。
解题思路:
确定一个二叉树是否是对称二叉树,要比较的是根节点的左右子树是不是互相翻转的,我们要比较的是两个子树的内侧元素和外侧元素是否相等。
因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。所以本题应该采取后续遍历。
递归三部曲:
1.确定递归函数的参数和返回值
因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。函数的返回值为bool。
bool compare(TreeNode* left, TreeNode* right)
2.确定终止条件
要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。
左节点为空,右节点不为空,不对称,return false
左不为空,右为空,不对称 return false
左右都为空,对称,返回true
左右都不为空,比较节点数值,不相同就return false
if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val != right->val) return false;
没有使用else,而是else if, 因为我们把以上情况都排除之后,剩下的就是 左右节点都不为空,且数值相同的情况。
3.确定单层递归的逻辑
此时才进入单层递归的逻辑,单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。
比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。
如果左右都对称就返回true ,有一侧不对称就返回false 。
bool outside = compare(left->left, right->right); // 左子树:左、 右子树:右
bool inside = compare(left->right, right->left); // 左子树:右、 右子树:左
bool isSame = outside && inside; // 左子树:中、 右子树:中(逻辑处理)
return isSame;
至此主要逻辑完。
代码:
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right) {
// 首先排除空节点的情况
if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
// 排除了空节点,再排除数值不相同的情况
else if (left->val != right->val) return false;
// 此时就是:左右节点都不为空,且数值相同的情况
// 此时才做递归,做下一层的判断
bool outside = compare(left->left, right->right); // 左子树:左、 右子树:右
bool inside = compare(left->right, right->left); // 左子树:右、 右子树:左
bool isSame = outside && inside; // 左子树:中、 右子树:中 (逻辑处理)
return isSame;
}
bool isSymmetric(TreeNode* root) {
if (root == NULL) return true;
return compare(root->left, root->right);
}
};
题目五:二叉树的最大深度
题目描述:
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例: 给定二叉树 [3,9,20,null,null,15,7],
返回它的最大深度 3 。
解题思路:
二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始),也就是说任意一个节点到根节点的距离。
二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始),也就是说任意一个节点到叶子节点的距离。
在本题中,最大深度也就是根节点的高度。
以深度,高度从1开始为例:
计算最大深度可以转换成求根节点的高度,我们可以先求得叶子节点到其根节点的距离,然后将其返还给根节点,根节点+1,就是该根节点的高度,然后再把高度返回给上一层的根节点,上层的根节点再+1;直至返回给二叉树的根节点,+1,即所要求的高度也就是最大深度。
本题从叶子节点往上返回,因此考虑采用后序遍历,左右根,才能实现从叶子节点向根节点返回。
本体采用递归法:
1.首先确定递归函数的参数和返回值:参数就是传入的根节点,返回值就是返回这颗二叉树的最大深度,为int类型
int getdepth(TreeNode* node)
2.确定终止条件:如果节点为空,表示高度为0。
if (node == NULL) return 0;
3.确定单层递归的逻辑
二叉树后序遍历的顺序是左右根,也就是先求左子树的高度,再求右子树的高度,然后取左右子树最大高度+1,就是当前根节点的最大深度
int leftdepth = getdepth(node->left); // 左
int rightdepth = getdepth(node->right); // 右
int depth = 1 + max(leftdepth, rightdepth); // 中
return depth;
代码:
class Solution {
public:
int getHeight(TreeNode *node){
if(node == NULL) return 0;
int leftHeight = getHeight(node->left);
int rightHeight = getHeight(node->right);
int height = 1 + max(leftHeight, rightHeight);
return height;
}
int maxDepth(TreeNode* root) {
return getHeight(root);
}
};
精简版代码:
class solution {
public:
int maxDepth(TreeNode* root) {
if (root == null) return 0;
return 1 + max(maxDepth(root->left), maxDepth(root->right));
}
};
题目六:二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
返回它的最小深度 2
解题思路:
二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始),也就是说任意一个节点到根节点的距离。
二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始),也就是说任意一个节点到叶子节点的距离。
使用后序遍历,其实求的是根节点到叶子节点的最小距离,就是求高度的过程,不过这个最小距离 也同样是最小深度。
本题依旧采取递归法:
1.传入的参数为根节点,返回值为深度,int型
int getDepth(TreeNode* node)
2.确定终止条件,终止条件也是遇到空节点返回0,表示当前节点的高度为0。
if (node == NULL) return 0;
3.确定单层递归的逻辑
按照最大深度的写法来写是不对的,会犯上图的错误。
按最大深度的写法来写,没有左孩子的分支会算为最短深度,但实际上并不是。
如果左子树为空,而右子树不为空,最小深度应该是右子树的最小深度+1;
如果左子树不为空,而右子树为空,说明最小深度是左子树深度+1。
如果左右子树都不为空,那么最小深度应该为左右子树深度的最小值+1。
求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。
int leftDepth = getDepth(node->left); // 左
int rightDepth = getDepth(node->right); // 右
// 中
// 当一个左子树为空,右不为空,这时并不是最低点
if (node->left == NULL && node->right != NULL) {
return 1 + rightDepth;
}
// 当一个右子树为空,左不为空,这时并不是最低点
if (node->left != NULL && node->right == NULL) {
return 1 + leftDepth;
}
int result = 1 + min(leftDepth, rightDepth);
return result;
代码:
class Solution {
public:
int getDepth(TreeNode* node) {
if (node == NULL) return 0;
int leftDepth = getDepth(node->left); // 左
int rightDepth = getDepth(node->right); // 右
// 中
// 当一个左子树为空,右不为空,这时并不是最低点
if (node->left == NULL && node->right != NULL) {
return 1 + rightDepth;
}
// 当一个右子树为空,左不为空,这时并不是最低点
if (node->left != NULL && node->right == NULL) {
return 1 + leftDepth;
}
int result = 1 + min(leftDepth, rightDepth);
return result;
}
int minDepth(TreeNode* root) {
return getDepth(root);
}
};
精简版代码:
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == NULL) return 0;
if (root->left == NULL && root->right != NULL) {
return 1 + minDepth(root->right);
}
if (root->left != NULL && root->right == NULL) {
return 1 + minDepth(root->left);
}
return 1 + min(minDepth(root->left), minDepth(root->right));
}
};
题目七:完全二叉树的节点个数
给出一个完全二叉树,求出该树的节点个数。
示例 1:
输入:root = [1,2,3,4,5,6]
输出:6
示例 2:
输入:root = []
输出:0
示例 3:
输入:root = [1]
输出:1
提示:
树中节点的数目范围是[0, 5 * 10^4]
0 <= Node.val <= 5 * 10^4
题目数据保证输入的树是 完全二叉树
解题思路:
方法一:
按普通二叉树解决,采用后序遍历。
1.确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。
int getNodesNum(TreeNode* cur)
2.确定终止条件:如果为空节点的话,就返回0,表示节点数为0。
if (cur == NULL) return 0;
3.确定单层递归的逻辑:先求它的左子树的节点数量,再求右子树的节点数量,最后取总和再加一 (加1是因为算上当前中间节点)就是目前节点为根节点的节点数量。
int leftNum = getNodesNum(cur->left); // 左
int rightNum = getNodesNum(cur->right); // 右
int treeNum = leftNum + rightNum + 1; // 中
return treeNum;
代码:
方法一:递归法
/**
* 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 getNodeNum(TreeNode* cur){
if (cur == nullptr) return 0;
int leftNum = getNodeNum(cur->left);
int rightNum = getNodeNum(cur->right);
int treeNum = leftNum + rightNum + 1;
return treeNum;
}
int countNodes(TreeNode* root) {
return getNodeNum(root);
}
};
方法二:层序遍历,与层序遍历模板相比,增加一个变量,记录节点数量
class Solution {
public:
int countNodes(TreeNode* root) {
queue<TreeNode*> que;
if (root != NULL) que.push(root);
int result = 0;
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
result++; // 记录节点数量
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return result;
}
};
方法三:完全二叉树法
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
关键在于如何去判断一个左子树或者右子树是不是满二叉树。
在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。
在完全二叉树中,如果递归向左遍历的深度不等于递归向右遍历的深度,则说明不是满二叉树。
判断其子树是不是满二叉树,如果是则利用公式计算这个子树(满二叉树)的节点数量,如果不是则继续递归。
1.确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。
int getNodesNum(TreeNode* cur)
2.第二步,确定终止条件
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<<1) 相当于2^2,返回满足满二叉树的子树节点数量
}
3.第三步,单层递归的逻辑
int leftTreeNum = countNodes(root->left); // 左
int rightTreeNum = countNodes(root->right); // 右
int result = leftTreeNum + rightTreeNum + 1; // 中
return result;
代码:
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<<1) 相当于2^2,所以leftDepth初始为0
}
int leftTreeNum = countNodes(root->left); // 左
int rightTreeNum = countNodes(root->right); // 右
int result = leftTreeNum + rightTreeNum + 1; // 中
return result;
}
};