🔥个人主页: Milestone-里程碑
❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>
🌟心向往之行必能至
先看题目:
给定一棵二叉树,翻转这棵二叉树,并返回其根节点。所谓翻转,就是把每个节点的左子树和右子树互换,一层一层递归完成即可。
一、题目分析
翻转二叉树的核心逻辑只有两步:
- 终止条件 :如果当前节点是空节点(
nullptr),直接返回,不用处理。 - 递归处理:先交换当前节点的左右孩子,再递归翻转左子树、递归翻转右子树。
举个直观例子:
plaintext
原树:
4
/ \
2 7
/ \ / \
1 3 6 9
翻转后:
4
/ \
7 2
/ \ / \
9 6 3 1
每个节点的左右子树都完成了互换,完美符合要求。
二、完整 C++ 代码(递归版)
这是最简洁、最容易理解的递归实现,也是面试首选写法:
cpp
运行
/**
* 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 == nullptr) return nullptr;
// 交换当前节点的左右孩子
TreeNode* temp = root->left;
root->left = root->right;
root->right = temp;
// 递归翻转左子树
invertTree(root->left);
// 递归翻转右子树
invertTree(root->right);
// 返回翻转后的根节点
return root;
}
};
三、代码逐行解析
我把代码拆解开,一步步讲清楚每一行的作用:
1. 递归终止条件
cpp
运行
if(root == nullptr) return nullptr;
- 如果当前节点是空节点,没有左右孩子可以交换,直接返回,避免空指针报错。
- 这是递归的出口,所有递归题都必须有明确的终止条件。
2. 交换当前节点的左右孩子
cpp
运行
TreeNode* temp = root->left;
root->left = root->right;
root->right = temp;
- 用一个临时指针
temp暂存左孩子。 - 把右孩子赋值给左指针,左孩子赋值给右指针,完成当前节点的左右翻转。
3. 递归处理子树
cpp
运行
invertTree(root->left);
invertTree(root->right);
- 交换完当前节点后,它的左、右子树还没翻转,所以递归调用函数处理左、右子树。
- 递归会一直深入到叶子节点,再逐层返回处理,最终整棵树完成翻转。
4. 返回根节点
cpp
运行
return root;
- 最终返回翻转后的二叉树根节点,符合题目要求。
四、复杂度分析
-
时间复杂度:O(n)二叉树的每个节点都会被访问一次,所以时间复杂度和节点数成正比。
-
空间复杂度:O(h)h 是二叉树的高度,递归调用栈的深度等于树的高度。
- 最坏情况(斜树):h=n,空间复杂度 O(n)
- 最好情况(平衡二叉树):h=logn,空间复杂度 O(logn)
五、递归思想总结
这道题完美体现了递归三要素:
- 确定递归函数的功能:翻转以 root 为根的二叉树。
- 确定递归终止条件:节点为空时返回。
- 确定递归递推公式:交换当前节点左右孩子 + 递归翻转左右子树。
只要掌握这个思路,二叉树的绝大多数递归题都能轻松搞定~
六、小拓展:迭代版(广度优先)
如果面试要求不用递归,可以用队列 + BFS实现,思路是层序遍历每个节点,逐个交换左右孩子:
cpp
运行
TreeNode* invertTree(TreeNode* root) {
if(!root) return nullptr;
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
TreeNode* node = q.front();
q.pop();
// 交换当前节点左右孩子
swap(node->left, node->right);
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
return root;
}
总结
- 翻转二叉树核心:交换当前节点左右孩子 + 递归翻转子树。
- 递归代码极简,面试首选,时间复杂度 O(n)。
- 掌握递归三要素,二叉树递归题一通百通。