引言
今天二叉树的题目,加油!!!
享受这种刷题的乐趣。
翻转二叉树
- 🎈 题目链接:https://leetcode.cn/problems/invert-binary-tree/description/?envType=study-plan-v2&envId=top-100-liked
- 🎈 做题状态:
我的解题
这道题可以直接使用核心函数作为递归函数,然后只不过需要使用一个临时变量记录一下节点,因为在交换节点的时候会有一个变量丢失,所以要用临时变量记录。
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (!root) return root;
TreeNode* tmp = root->right;
root->right = invertTree(root->left);
root->left = invertTree(tmp);
return root;
}
};
解题分析
题目分析
翻转二叉树(Invert Binary Tree)是一道经典的递归问题,要求将二叉树的每个节点的左右子树进行交换。例如:
原始树:
4
/ \
2 7
/ \ / \
1 3 6 9
翻转后:
4
/ \
7 2
/ \ / \
9 6 3 1
解题思路
使用了递归方法来翻转二叉树,核心逻辑如下:
- 递归终止条件:如果当前节点
root
为空,直接返回nullptr
。 - 交换左右子树:
- 用临时变量
tmp
保存右子树的根节点。 - 递归翻转左子树,并将结果赋给
root->right
。 - 递归翻转右子树(原右子树的根节点保存在
tmp
中),并将结果赋给root->left
。
- 用临时变量
- 返回当前节点:完成翻转后返回
root
。
代码点评
代码简洁且高效,时间复杂度为 O(n)(每个节点访问一次),空间复杂度为 O(h)(递归栈空间,h 为树高)。以下是代码的逐行解释:
TreeNode* invertTree(TreeNode* root) {
if (!root) return root; // 终止条件:空节点直接返回
TreeNode* tmp = root->right; // 临时保存右子树
root->right = invertTree(root->left); // 递归翻转左子树,并赋给右指针
root->left = invertTree(tmp); // 递归翻转原右子树(tmp),并赋给左指针
return root; // 返回当前节点
}
优化与变体
-
后序遍历风格:
可以显式地先递归翻转左右子树,再交换它们,逻辑更直观:TreeNode* invertTree(TreeNode* root) { if (!root) return nullptr; TreeNode* left = invertTree(root->left); TreeNode* right = invertTree(root->right); root->left = right; root->right = left; return root; }
-
迭代解法(BFS):
使用队列进行层序遍历,逐层交换左右子节点: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; }
关键点总结
- 递归思想:将问题分解为翻转左右子树的子问题。
- 临时变量:必须用
tmp
保存右子树,否则在修改root->right
后会丢失原右子树的引用。 - 终止条件:处理空节点是递归的基础情况。
常见错误
- 忘记保存右子树:直接写
root->right = invertTree(root->left); root->left = invertTree(root->right);
会导致右子树被覆盖后丢失。 - 忽略空节点检查:未处理
root == nullptr
的情况会导致访问空指针。
总结
解法是完全正确的,且代码清晰。通过临时变量 tmp
保存右子树是关键步骤,确保了交换的正确性。递归方法在此类问题中既自然又高效,适合作为首选解法。