--------------------------/12/29---------------------------
收获:for循环的时候队列的长度会变化,所以得先用一个变量存储,感觉就没有其他难点了
32-I
//广度优先/*** 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:vector<int> levelOrder(TreeNode* root) {if(!root) return {};vector<int> ans;queue <TreeNode*> que;que.push(root);while(!que.empty()) {TreeNode* tmp = que.front();que.pop();ans.push_back(tmp -> val);if(tmp -> left != NULL) que.push(tmp -> left);if(tmp -> right != NULL) que.push(tmp -> right); }return ans;}};
32-II
class Solution {public:vector<vector<int>> levelOrder(TreeNode* root) {if(!root) return {};vector<vector<int>> ans;queue<TreeNode*> que;que.push(root);while(!que.empty()) {vector<int> res;int len = que.size();for(int i = 0; i < len; i ++) {TreeNode* cur = que.front();que.pop();res.push_back(cur -> val);if(cur -> left) que.push(cur -> left);if(cur -> right) que.push(cur -> right);}ans.push_back(res);}return ans;}};
32-III
class Solution {public:vector<vector<int>> levelOrder(TreeNode* root) {if(!root) return {};int flag = 1;//从左向右取数字vector<vector<int>> ans;deque<TreeNode*> d;d.push_back(root);while(!d.empty()) {vector<int> tmp;int len = d.size();for(int i = 0; i < len; i ++) {if(flag == 1) {TreeNode* cur = d.front();d.pop_front();tmp.push_back(cur -> val);if(cur -> left) d.push_back(cur -> left);if(cur -> right) d.push_back(cur -> right);}else {TreeNode* cur = d.back();d.pop_back();tmp.push_back(cur -> val);if(cur -> right) d.push_front(cur -> right);if(cur -> left) d.push_front(cur -> left);} }flag = !flag;ans.push_back(tmp);}return ans;}};
--------------------------一刷----------------------------------
之前一直在做深度优先的题目,导致广度优先有点生疏了
先稍微复习一下:
一般而言,深度优先利用递归的方式,走到没有路时回溯至上一个还有路的点;
广度优先利用队列存储的方式,当队列不为空时不断往外扩张从而走遍所有路径。
通过啊哈算法中比较经典的计算小岛面积的问题来直观感受两者的区别
ps:只是最基础的模板,代码没有优化,且根据书上原代码,队列借助数组实现
//深度优先遍历void dfs(int x, int y) {int k, tx, ty;for(int k = 0; k <= 3; k++) {tx = x + next[k][0];//next数组定义为四个方向ty = y + next[k][1];if(越界) continue;if(为陆地并且点尚未走过){sum ++;//小岛面积book[x][y]=1;//标记该点走过dfs(tx, ty);//一走到底}}return ;}//广度优先遍历void bfs(int x, int y) {while(head < tail) {int k, tx, ty;for(int k = 0; k<= 3; k++) {tx = que[head].x + next[k][0];//next数组定义为四个方向ty = que[head].y + next[k][1];if(越界) continue;if(为陆地并且点尚未走过){sum ++;//小岛面积book[x][y]=1;//标记该点走过que[tail].x = tx;que[tail].y = ty;tail++;}}head++;//层层递进}}
而对二叉树的广度优先遍历(又称为二叉树的层次遍历)的区别只在于其遍历方向只有两个->左子树和右子树,于是可以得到代码
class Solution {public:vector<int> levelOrder(TreeNode* root) {if(root == NULL)return {};queue <TreeNode*> que;vector <int> ans;que.push(root);while(!que.empty()) {TreeNode* cur = que.front();que.pop();//do somethingif(cur -> left != NULL) que.push(cur -> left);if(cur -> right != NULL) que.push(cur -> right);}return ans;}};
12-I题目描述
解法BFS
/*** 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:vector<int> levelOrder(TreeNode* root) {if(root == NULL)return {};queue <TreeNode*> que;vector <int> ans;que.push(root);while(!que.empty()) {TreeNode* cur = que.front();que.pop();ans.push_back(cur -> val);if(cur -> left != NULL) que.push(cur -> left);if(cur -> right != NULL) que.push(cur -> right);}return ans;}};
时间复杂度O(n),空间复杂度O(n)
12-II 题目描述
解法
多增加了每层的边境判定,由于二叉树层次遍历的特性,我们能通过队列的长度得知该层需要处理的结点个数。
或者重复2^n次方也可以,上述队列长度的方法挺难想到。
/*** 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:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> ans;if(root == NULL)return {};queue <TreeNode*> que;que.push(root);while(!que.empty()) {vector<int> tmp;int len = que.size();for(int i = 0; i < len ; i++) {//for循环结束说明这层处理结束TreeNode* cur = que.front();que.pop();tmp.push_back(cur -> val);if(cur -> left != NULL) que.push(cur -> left);if(cur -> right != NULL) que.push(cur -> right);}ans.push_back(tmp);}return ans;}};
要注意到que.push并不是在做这一层的事情,而是在压入下一层的结点,防止对12-III的处理出现误解
时间复杂度O(n),空间复杂度O(n);
12-III题目描述
解法一 vector倒转
利用vector倒转实现,简单粗暴,告诉面试官之后就能等通知了
class Solution {public:vector<vector<int>> levelOrder(TreeNode* root) {int flag=0;vector<vector<int>> ans;if(root == NULL)return {};queue <TreeNode*> que;que.push(root);while(!que.empty()) {vector<int> tmp;int len = que.size();for(int i = 0; i < len ; i++) {TreeNode* cur = que.front();que.pop();tmp.push_back(cur -> val);if(cur -> left != NULL) que.push(cur -> left);if(cur -> right != NULL) que.push(cur -> right);}if(flag == 1) {reverse(tmp.begin(), tmp.end());flag=0;}else flag=1;ans.push_back(tmp);}return ans;}};
解法deque
也是一个比较少用到的数据结构,所以来复习一下deque
直接转载另一篇博客了deque知识点
简单来说就是可以两边都可以删除增加元素的队列
class Solution {public:vector<vector<int>> levelOrder(TreeNode* root) {int flag=0;//0从左到右 1从右到左vector<vector<int>> ans;if(root == NULL)return {};deque <TreeNode*> d;d.push_front(root);while(!d.empty()) {vector<int> tmp;int len = d.size();for(int i = 0; i < len ; i++) {if(flag == 0) {TreeNode* cur = d.front();d.pop_front();tmp.push_back(cur -> val);if(cur -> left != NULL) d.push_back(cur -> left);if(cur -> right != NULL) d.push_back(cur -> right);}else {TreeNode* cur = d.back();d.pop_back();tmp.push_back(cur -> val);if(cur -> right != NULL) d.push_front(cur -> right);if(cur -> left != NULL) d.push_front(cur -> left);}}flag = !flag;ans.push_back(tmp);}return ans;}};
中间的部分比较绕
根据第二题可得每一层都是一次完整的for循环,所以可以把从左到右的情况和从右到左的情况分开分析。
当从左到右时,从deque的首部取元素(也就是上一层的最后一个元素),然后以从左到右的顺序压入deque的尾部。
当从右到左时,从deque的尾部取元素(也就是上一层的最后一个元素),然后以从右到左的顺序压入deque的头部。
比如例题中的二叉树
顺序
3入队第一次for循环flag=0 从左到右
TreeNode* cur = d.front();d.pop_front();tmp.push_back(cur -> val);if(cur -> left != NULL) d.push_back(cur -> left);if(cur -> right != NULL) d.push_back(cur -> right);
3出队列 9 20从后端入队 tmp={3} deque={9,20}
第二次for循环flag=1 从右到左
TreeNode* cur = d.back();d.pop_back();tmp.push_back(cur -> val);if(cur -> right != NULL) d.push_front(cur -> right);if(cur -> left != NULL) d.push_front(cur -> left);
20出队 NULL NULL入队 tmp={20} deque={9}9出队 7 15前端入队 tmp={20,9} deque{15,7}
第三次for循环flag=0 从左到右
TreeNode* cur = d.front();d.pop_front();tmp.push_back(cur -> val);if(cur -> left != NULL) d.push_back(cur -> left);if(cur -> right != NULL) d.push_back(cur -> right);
15出队 NULL tmp={15} deque={}
7出队 NULL tmp={15,7} deque={}
总之就是按照之字的顺序把元素丢到deque中,并且要保证丢入元素顺序和上一层相反,同时不能影响到上一层元素的出队。
画个图来看,其实从左到右的元素次序并没有变化,变的只是从后往前取和从前往后取。
时间复杂度O(n) 空间复杂度O(N)