1.完全二叉树结点数
题目链接:. - 力扣(LeetCode)
讲解链接:代码随想录 (programmercarl.com)
视频链接:要理解普通二叉树和完全二叉树的区别! | LeetCode:222.完全二叉树节点的数量_哔哩哔哩_bilibili
本题可以当作普通树来数结点,遍历所有结点。
但是完全二叉树有自己的特点,首先满二叉树也是一颗完全二叉树,而满二叉树的结点可以通过公式计算。如果完全二叉树不是满的,那么它遍历的过程中一定有子树成为满二叉树。
因此每次递归可以先判断是否为满二叉树,而判断满二叉树的条件是,左右遍历深度相同。
递归法:
三要素
1.参数与返回值:需要统计结点个数,返回int类型。参数为树结点指针。
2.终止条件:遇到空指针终止。
3.单层逻辑:首先判断是否未满二叉树,若满则用公式计算并返回。若不满则再递归计算左右子树结点个数,返回左右子树结点和+1。
代码如下:
int count(TreeNode* root){
if (root == nullptr)
return 0;
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftDepth = 0;
int rightDepth = 0;
while (left != nullptr){
left = left->left;
leftDepth++;
}
while (right != nullptr){
right = right->right;
rightDepth++;
}
if (leftDepth == rightDepth)
return (2 << leftDepth) - 1;
int leftCount = count(root->left);
int rightCount = count(root->right);
return leftCount + rightCount + 1;
}
int countNodes(TreeNode* root) {
return count(root);
}
2.平衡二叉树
题目链接:. - 力扣(LeetCode)
讲解链接:代码随想录 (programmercarl.com)
视频链接:后序遍历求高度,高度判断是否平衡 | LeetCode:110.平衡二叉树_哔哩哔哩_bilibili
平衡二叉树是左右子树高度差不超过1的二叉树。因此本题主要求解左右子树的高度。
递归法:
三要素
1.参数与返回值:需要比较左右子树高度,返回int类型。参数为树结点指针。
2.终止条件:空指针。
3.单层逻辑:先递归求左右子树高度,然后比较他们的绝对值之差。如果递归过程中某子树高度为-1(不平衡),就直接返回-1。如果平衡,该树的高度就是左右子树高度较大者+1。
代码如下:
int getHeight(TreeNode* root){
if (root == nullptr)
return 0;
int leftHeight = getHeight(root->left);
int rightHeight = getHeight(root->right);
if (leftHeight == -1 || rightHeight == -1)
return -1;
if (abs(leftHeight - rightHeight) > 1)
return -1;
else
return 1 + max(leftHeight, rightHeight);
}
bool isBalanced(TreeNode* root){
return getHeight(root) == -1 ? false : true;
}
3.所有路径
题目链接:. - 力扣(LeetCode)
讲解链接:代码随想录 (programmercarl.com)
视频链接:递归中带着回溯,你感受到了没?| LeetCode:257. 二叉树的所有路径_哔哩哔哩_bilibili
本题涉及回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。
递归法:
三要素
1.参数与返回值:本题不需要返回值,路径与结果集从参数导入,还需要树结点指针作为参数。
2.终止条件:遇到叶子节点中止(路径走到头了),同时要将至今位置记录的path加入到结果集中。记录路径使用的是vector数组,而结果集的元素是string,因此需要将vector转换为string,然后再加入结果集。
3.单层逻辑:向左孩子结点前进,递归完后要回溯,将path中的元素pop()一个(即左孩子结点),因为接下来要想右孩子前进,同样递归完要进行回溯。
代码如下:
void traversal(TreeNode* cur, vector<int>& path, vector<string>& result){
path.push_back(cur->val);
if (cur != nullptr && cur->left == nullptr && cur->right == nullptr){
string str;
for (int i = 0; i < path.size() - 1; ++i) {
str += to_string(path[i]);
str += "->";
}
str += to_string(path[path.size() - 1]);
result.push_back(str);
return;
}
if (cur->left){
traversal(cur->left, path, result);
path.pop_back();
}
if (cur->right){
traversal(cur->right, path, result);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root){
vector<string> result;
vector<int> path;
traversal(root, path, result);
return result;
}
4.左叶子之和
题目链接:. - 力扣(LeetCode)
讲解链接:代码随想录 (programmercarl.com)
视频链接:二叉树的题目中,总有一些规则让你找不到北 | LeetCode:404.左叶子之和_哔哩哔哩_bilibili
左叶子是作为左孩子的叶子节点。只看当前结点无法判断其是否为左叶子,需要从父节点开始判断。
递归法:
三要素
1.参数与返回值:需要返回子树左叶子之和,为int类型。参数为树节点指针。
2.结束条件:空指针或叶子节点(叶子节点没有孩子所有不会有下一个左叶子)。
3.单层逻辑:当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。
代码如下:
int sumOfLeftLeaves(TreeNode* root){
if (root == nullptr)
return 0;
if (root->left == nullptr && root->right == nullptr)
return 0;
int leftSum = sumOfLeftLeaves(root->left);
if (root->left && !root->left->left && !root->left->right)
leftSum = root->left->val;
int rightSum = sumOfLeftLeaves(root->right);
return leftSum + rightSum;
}
tips:
if (root->left && !root->left->left && !root->left->right) leftSum = root->left->val;
这句代码是判断左孩子是否为左叶子。