|
| 1 | +## 103_(二叉树的锯齿形层次遍历)Binary Tree Zigzag Level Order Traversal |
| 2 | +## 1 问题描述、输入输出与样例 |
| 3 | +### 1.1 问题描述 |
| 4 | +给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。<br> |
| 5 | +### 1.2 输入与输出 |
| 6 | +输入:<br> |
| 7 | +* TreeNode* root:二叉树的根节点指针<br> |
| 8 | +输出:<br> |
| 9 | +* vector<vector<int>>:锯齿形层次遍历的结果,是一个二维矢量的形式 |
| 10 | +### 1.3 样例 |
| 11 | +#### 1.3.1 样例1 |
| 12 | +输入: 给定二叉树: [3,9,20,null,null,15,7], |
| 13 | + |
| 14 | + 3 |
| 15 | + / \ |
| 16 | + 9 20 |
| 17 | + / \ |
| 18 | + 15 7 |
| 19 | + |
| 20 | +输出: |
| 21 | + |
| 22 | + [ |
| 23 | + [3], |
| 24 | + [20,9], |
| 25 | + [15,7] |
| 26 | + ] |
| 27 | + |
| 28 | +## 2 思路描述与代码 |
| 29 | +### 2.1 思路描述(基于队列的二叉树层次遍历) |
| 30 | +二叉树的层次遍历可以利用队列来做,其思路也很简单。<br> |
| 31 | +这里为了把每层的结果记录下来,对BFS的代码结构稍微改动了下,即里面用了个 for 循环做当前层遍历。<br> |
| 32 | +其次与102层次遍历不一样的是,这里使用 depth 记录深度,在深度 depth 为偶数的时候对当前层次遍历结果进行反转再插入 res 中。 |
| 33 | +```cpp |
| 34 | +初始化二叉树层次遍历的二维矢量 res ; |
| 35 | +头结点入队; |
| 36 | +深度初始化为0; |
| 37 | +while( 队列不空 ){ |
| 38 | + 初始化当前层的遍历结果 level; |
| 39 | + 获取当前层的数目数 len; |
| 40 | + for( int i = 0; i < len; i++ ){ |
| 41 | + 取出当前层的节点tmp并保存至 level; |
| 42 | + 左右孩子非空则入队; |
| 43 | + } |
| 44 | + 如果深度为偶数则反转 level; |
| 45 | + 将 level 保存至 res ; |
| 46 | +} |
| 47 | +返回 res ; |
| 48 | +``` |
| 49 | +比如给定二叉树: [3,9,20,null,null,15,7];<br> |
| 50 | +首先根节点3入队,然后进入 while 循环;<br> |
| 51 | +此时队列不空,深度为1,有1个元素3,for 循环后有 res = {[3]}, 队列里面有元素[9, 20];<br> |
| 52 | +此时队列不空,深度为2,有元素[9, 20],反转后为[20, 9], for 循环后有 res = {[3],[20,9]}, 队列里面有元素[15, 7];<br> |
| 53 | +此时队列不空,深度为3,有元素[15, 7],for 循环后有 res = {[3],[20,9], [15,7]}, 队列里面没有元素;<br> |
| 54 | +此时队列空后,返回 res = {[3],[20,9], [15,7]} 。 |
| 55 | + |
| 56 | +### 2.2 代码 |
| 57 | +```cpp |
| 58 | +vector<vector<int>> zigzagLevelOrder(TreeNode* root) { |
| 59 | + vector<vector<int>> res; |
| 60 | + if(root == nullptr) |
| 61 | + return res; |
| 62 | + //基于队列做层序遍历 |
| 63 | + queue<TreeNode*> q; |
| 64 | + q.push(root); |
| 65 | + //层序遍历的深度 |
| 66 | + int depth = 1; |
| 67 | + while( !q.empty() ){ |
| 68 | + //保存当前层遍历的结果 |
| 69 | + vector<int> layer; |
| 70 | + //获取当前层的节点数目 |
| 71 | + int layer_size = q.size(); |
| 72 | + //遍历当前的所有层 |
| 73 | + for( int i = 0; i < layer_size; i++ ){ |
| 74 | + TreeNode* tmp = q.front(); |
| 75 | + q.pop(); |
| 76 | + //如果左右子树非空,则入队 |
| 77 | + if(tmp->left) |
| 78 | + q.push(tmp->left); |
| 79 | + if(tmp->right) |
| 80 | + q.push(tmp->right); |
| 81 | + layer.push_back(tmp->val); |
| 82 | + } |
| 83 | + //将当前层遍历的结果存到res里面,同时深度加1 |
| 84 | + if((depth & 0x01) == 0) reverse(layer.begin(), layer.end()); |
| 85 | + res.push_back(layer); |
| 86 | + depth += 1; |
| 87 | + } |
| 88 | + return res; |
| 89 | + } |
| 90 | +``` |
| 91 | +## 3 思考与拓展 |
| 92 | +### 3.1 思考 |
| 93 | +本题,主要考察的还是数据结构。这里为了简单,直接对深度为偶数层的遍历结果直接反转。你也可以使用双端队列或者奇层用队列、偶层用堆栈。 |
| 94 | +#### 3.1.1 其他方法 |
| 95 | +#### 3.1.1.1 基于双端队列的二叉树锯齿形层次遍历 |
| 96 | +思路还是一致的,只是数据结构换了而已。<br> |
| 97 | +在 depth 为奇数的时候从队头出队;<br> |
| 98 | +在 depth 为偶数的时候从队尾出队;<br> |
| 99 | +#### 3.1.2 复杂度分析 |
| 100 | +方法|空间复杂度|时间复杂度 |
| 101 | +--- | --- | --- |
| 102 | +基于队列的二叉树层次遍历|O(2^h),h是树的高度|O(n) |
| 103 | +基于双端队列的二叉树锯齿形层次遍历|O(2^h),h是树的高度|O(n),由于不需要反序,所以会比基于队列的二叉树层次遍历快一点 |
| 104 | +#### 3.1.3 难点分析 |
| 105 | +1. 采用何种数据结果保存不同方式的层遍历结果 |
| 106 | +### 3.2 拓展 |
| 107 | +如果让你结合队列和堆栈做锯齿形层次遍历呢? |
0 commit comments