方法:递归遍历
首先我想到的就是交换根节点的孩子节点的位置,然后再交换这些孩子节点的孩子节点的位置。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if(root == NULL)
return NULL;
if(root->left!=NULL || root->right!=NULL){
TreeNode *temp;
temp = root->left;
root->left = root->right ;
root->right = temp ;
mirrorTree(root->left);
mirrorTree(root->right);
}
return root;
}
};
发现如果有第一个判断,其实后面那个判断是没必要的,这样就行:
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if(root == NULL)
return NULL;
TreeNode *temp;
temp = root->left;
root->left = root->right ;
root->right = temp ;
mirrorTree(root->left);
mirrorTree(root->right);
return root;
}
};
再简化一点代码可以写成这样:
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if(root == NULL)
return NULL;
TreeNode *temp = root->left;
root->left = mirrorTree(root->right);
root->right = mirrorTree(temp);
return root;
}
};
方法:使用栈或队列
栈模拟:
弹出栈顶结点,并交换其左右子树,直到栈为空。
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
stack<TreeNode*> s;
s.push(root);
while (!s.empty()) {
TreeNode* node = s.top();
s.pop();
if (node == NULL) {
continue;
}
swap(node->left, node->right);
s.push(node->left);
s.push(node->right);
}
return root;
}
};
队列模拟:
交换队首结点的左右子树。
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front();
q.pop();
if (node == NULL) {
continue;
}
swap(node->left, node->right);
q.push(node->left);
q.push(node->right);
}
return root;
}
};
基础知识补充
在C++中,栈和队列都是被封装好的
- 包含栈头文件:
#include<stack>
- 包含队列头文件:
#include<queue>
栈实现的是一个先进后出 FILO 的数据结构。
堆栈是一个容器的改编,栈是限定仅在表尾进行插入或者删除操作的线性表。因此表尾端为栈顶,表头端为栈底。不含有任何元素的栈叫空栈。
队列是一种容器适配器,实现的是一个先进先出FIFO的结构。
定义栈
stack<int> stk;
栈的相关操作:
- push() 向栈内压入一个成员
- pop() 从栈顶弹出一个成员
- empty() 如果栈为空则返回true,否则返回false
- top() 返回栈顶,但不删除成员
- size() 返回栈内元素的个数
定义队列
queue<int> q;
队列的相关操作:
- push(x) 将x接到队列的末端(入队)
- pop() 弹出队列的第一个元素,但并不会返回被弹出的元素的值(出队)
- front() 访问队首元素,返回最早被压入队列的元素
- back() 访问队尾元素,即最后被压入队列的元素
- empty() 队列为空时返回true
- size() 返回队列中的元素个数
队列的分类:
- 基于数组的循环队列:
以数组为底层数据结构时,每次从数组头部删除元素后,需要将头部以后的所有元素往前移动一个位置,时间复杂度为O(n)。
如果把队首标志往后移动,就不用移动元素,但是这样会造成数组空间的流失。
如果希望队列的插入和删除都是O(1)的时间复杂度,同时不造成空间的浪费,应该使用循环队列。即将数组看成一个首尾相连的圆环,删除元素时将队首标志往后移动,如果添加元素时尾部已经没有空间,考虑数组头部的空间是否空闲,如果是,则在头部插入。
判断队列空或已满:
栈空:队首标志=队尾标志
栈满:少用一个元素,队尾标志+1 = 队首
- 基于链表的队列
基于链表的队列不存在数组的O(n)的元素移动或者空间浪费问题。
我们以链表头部为队首,尾部为队尾,存储一个指向队尾的指针,方便从链表尾插入元素。使用带头节点的链表方便从链表头删除元素。