(滑稽)据说会做这道题就可以直接超越大佬Max Howell(Homebrew的作者),可以自行了解。还等什么,冲起来!
1.题目描述
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
示例1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
示例2:
输入:root = [2,1,3]
输出:[2,3,1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/invert-binary-tree
2.题目分析
2.1 递归思路
拿到这道题很容易想到的就是想到使用递归思想来解答。也就是对每个节点的左右子节点进行交换。这不,递归就来了。
前面说到的对处理每个子结点就是一个递的过程,进行交换然后保存修改就是一个归的过程,既然说到处理每个子节点,那么其思路就是对二叉树进行一个简单的遍历过程。递归伪代码如下
- 访问节点,不为空则继续访问,否则直接退出
- 保存节点的左子树
- 更新节点的左子树为完成交换后的右子树
- 更新右子树为完成交换后的左子树
有时候我们写出了递归的解法却是一知半解,按照题目中要求我们对于每个节点只处理一次,所以使用前序和后序遍历的话直接套用递归遍历函数就可以实现。但是如果是使用中序遍历实现的话就不能这么简单的处理了,因为中序递归遍历的时候访问顺序是左中右,所以问如果要采用类似的递归的话就要写成如下形式。可以看到两次的递归调用都是针对根节点的左子树实现的。这是因为经过了一次中间节点的翻转。
TreeNode* invertTree(TreeNode* root) {
if (root == NULL) return root;
invertTree(root->left);
swap(root->left, root->right);
invertTree(root->left);
return root;
}
基于题意,采用类前序或者后序遍历的递归最为恰当,代码见3.1。
2.2 基于前序遍历的迭代
可以使用递归的话必然也可以基于栈使用迭代法操作。我们很容易注意到上面的操作其实就是一个树的遍历操作,那么我们便可以将这一点应用到交换左右子树上。如果我们使用基于前序遍历的迭代法的话,就是每次在遍历完根节点后将其左右子树交换然后继续后续遍历的操作。
2.3 基于层次遍历的迭代
自然也是可以在进行层次遍历的时候对于每个结点的左右子节点进行交换实现树的翻转。
3.题目解答
3.1 递归
TreeNode* invertTree(TreeNode* root) {
if(root == nullptr) return root;
TreeNode *temp = root->right;
//左右互换
root->right = invertTree(root->left);
root->left = invertTree(temp);
return root;
}
3.2 迭代法实现
TreeNode* invertTree(TreeNode* root) {
// 通过前序遍历进行树的反转
if (root == NULL) return root;
stack<TreeNode*> st;
TreeNode *node = root;
// 栈不为空或者当前节点不为空就继续
while(!st.empty() || node){
// 节点下沉
while(node){
st.push(node);
// 节点交换
swap(node->left,node->right);
node = node->left;
}
// 访问右子树
TreeNode *cur = st.top();
st.pop();
node = cur->right;
}
return root;
}
3.3 层次遍历迭代
TreeNode* invertTree(TreeNode* root) {
// 通过层次遍历进行树的反转
if (root == NULL) return root;
queue<TreeNode*> que;
TreeNode *node = root;
que.push(root);
// 队列不空继续处理
while(!que.empty()){
size_t _size = que.size();
while(_size--){
TreeNode* cur = que.front();
que.pop();
// 交换左右子树
swap(cur->left,cur->right);
if(cur->left !=nullptr) que.push(cur->left);
if(cur->right !=nullptr) que.push(cur->right);
}
}
return root;
}
总结:树的很多算法实现都是基于其遍历来实现的,所以务必要深刻理解树的遍历及其实现。