搜索与回溯算法
从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector <vector <int>> ret; //动态数组
if(!root) {
return ret;
}
queue <TreeNode*> q;
q.push(root);
while(!q.empty()) {
int currentLevelSize = q.size();
ret.push_back(vector <int> ());
for(int i=1;i<=currentLevelSize;i++) {
auto node = q.front();
q.pop();
ret.back().push_back(node->val);
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
}
return ret;
}
};
这里主要涉及的是层序遍历,层序遍历主要的方法就是从上到下进行一次广度优先搜索(BFS),而BFS通常借助队列先入先出的特性实现
算法流程
- 1.特例处理: 当根节点为空,则返回空列表 [] ;
- 2.初始化: 打印结果列表 res = [] ,包含根节点的队列 queue = [root] ;
- 3.BFS 循环: 当队列 queue 为空时跳出;
- a.新建一个临时列表 tmp ,用于存储当前层打印结果;
- b.当前层打印循环: 循环次数为当前层节点数(即队列 queue 长度);
- 1.出队: 队首元素出队,记为 node;
- 2.打印: 将 node.val 添加至 tmp 尾部;
- 3.添加子节点: 若 node 的左(右)子节点不为空,则将左(右)子节点加入队列 queue ;
- c.将当前层结果 tmp 添加入 res 。
- 4.返回值: 返回打印结果列表 res 即可。
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ans;
if(!root) {
return ans;
}
queue<TreeNode*> nodeQueue;
nodeQueue.push(root);
bool isOrderLeft = true;
while(!nodeQueue.empty()) {
deque<int> levelLsit;
int size = nodeQueue.size();
for(int i=0;i<size;i++) {
auto node = nodeQueue.front();
nodeQueue.pop();
if(isOrderLeft) {
levelLsit.push_back(node->val);
}else {
levelLsit.push_front(node->val);
}
if(node->left) {
nodeQueue.push(node->left);
}
if(node->right) {
nodeQueue.push(node->right);
}
}
ans.emplace_back(vector<int>{levelLsit.begin(),levelLsit.end()});
isOrderLeft = !isOrderLeft;
}
return ans;
}
};
这里是层序遍历,但是多了一个偶数层倒序的要求。具体的实现方法是使用一个双端队列,使得在两端都可以进行插入操作,设置一个判断码来分辨奇数层和偶数层,然后使用对应的back插入和front插入方法就可以轻松实现了
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)B是A的子结构, 即 A中有出现和B相同的结构和节点值。
class Solution {
public:
bool isSubStructure(TreeNode* A, TreeNode* B) {
if(A == NULL || B == NULL) return false;
if(A->val == B->val) {
if(dfs_isEqual(A,B)) {
return true;
}
}
return isSubStructure(A->left, B) || isSubStructure(A->right, B);
}
bool dfs_isEqual(TreeNode* A, TreeNode* B) {
if(B == NULL) return true;
if(A == NULL) return false;
if(A->val == B->val) {
return dfs_isEqual(A->left,B->left) && dfs_isEqual(A->right,B->right);
}else {
return false;
}
}
};
首先进行树的判空处理。然后依次比较A与B的结点,采用dfs的策略进行比较。如果计较到B先为空,则说明B是A的子树;如果A先为空,则返回false,这个过程是将一直递归下去。而A的每个节点也要分别作为起始与B比较,同样采用递归实现,即A的左右子树分别与B进行比较,最终全部比较完毕。
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if(root == nullptr) return nullptr;
TreeNode* left = mirrorTree(root->left);
TreeNode* right = mirrorTree(root->right);
root->left = right;
root->right = left;
return root;
}
};
一样的事,用的是递归遍历,重点学一学递归吧,挺神奇的。
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
class Solution {
public:
bool check(TreeNode *p, TreeNode *q) {
if(!p && !q) return true;
if(!p || !q) return false;
return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);
}
bool isSymmetric(TreeNode* root) {
return check(root, root);
}
};
如果同时满足下面的条件,两个树互为镜像:
- 它们的两个根结点具有相同的值
- 每个树的右子树都与另一个树的左子树镜像对称
通过「同步移动」两个指针的方法来遍历这棵树,ppp 指针和 qqq 指针一开始都指向这棵树的根,随后 ppp 右移时,qqq 左移,ppp 左移时,qqq 右移。每次检查当前 ppp 和 qqq 节点的值是否相等,如果相等再判断左右子树是否对称。