题目来源
题目描述
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
}
};
题目解析
这道题是leetcode:102.Binary Tree Level Order Traversal 二叉树层序遍历的变形,不同之处在于一行是从左到右遍历,下一行是从右到左遍历,交叉往返的之字形的层序遍历
bfs
最简单直接的方法就是利用层次遍历,并使用一个变量cnt来统计当前的层数(从0开始),将所有的奇数层的结点值进行翻转一下即可
如下:
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
if(root == nullptr){
return {};
}
std::vector<std::vector<int>>res;
std::queue<TreeNode *> q{{root}};
int cnt = 0;
while (!q.empty()){
std::vector<int> oneLevel;
for (int i = q.size(); i > 0; --i) {
TreeNode *t = q.front(); q.pop();
oneLevel.push_back(t->val);
if(t->left){
q.push(t->left);
}
if(t->right){
q.push(t->right);
}
}
if(cnt % 2 == 1){
std::reverse(oneLevel.begin(), oneLevel.end());
}
res.push_back(oneLevel);
++cnt;
}
return res;
}
};
bfs
- 问题是反转数组太耗时了,如果能够直接计算出每个节点值在数组中的坐标,就可以直接进行更新了。
- 由于每层的节点数是知道的,也就是队列的元素个数,所以可以直接初始化数组的大小。
- 此时可以使用一个变量leftToRight来标记顺序,初始时是true。
- 当变量值为true时,每次加入数组的位置就是i本身
- 如果值为false时,则加入到size-1-i位置上。
- 这样就相当于反转了数组
- 每层遍历完成之后,需要翻转 leftToRight 变量,同时不要忘了将 oneLevel 加入结果 res
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
if (!root) return {};
vector<vector<int>> res;
queue<TreeNode*> q{{root}};
bool leftToRight = true;
while (!q.empty()) {
int size = q.size();
vector<int> oneLevel(size);
for (int i = 0; i < size; ++i) {
TreeNode *t = q.front(); q.pop();
int idx = leftToRight ? i : (size - 1 - i);
oneLevel[idx] = t->val;
if (t->left) q.push(t->left);
if (t->right) q.push(t->right);
}
leftToRight = !leftToRight;
res.push_back(oneLevel);
}
return res;
}
};
递归
这里可以看成是一个先序遍历。递归函数需要用一个变量level来记录当前的深度。
- 由于level是从0开始的,假如结果res的大小等于level,就需要在结果res中新加一个空集,这样可以保证res[level]不会越界。
- 取出res[level]之后,判断level的奇偶,如果为偶数,就将node->val加入到onelevel的末尾,如果是奇数,就加到onelevel的开头。然后分别对 node 的左右子结点调用递归函数,此时要传入 level+1 即可
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> res;
helper(root, 0, res);
return res;
}
void helper(TreeNode* node, int level, vector<vector<int>>& res) {
if (!node) return;
if (res.size() <= level) {
res.push_back({});
}
vector<int> &oneLevel = res[level];
if (level % 2 == 0) oneLevel.push_back(node->val);
else oneLevel.insert(oneLevel.begin(), node->val);
helper(node->left, level + 1, res);
helper(node->right, level + 1, res);
}
};