给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
返回锯齿形层次遍历如下:
[ [3], [20,9], [15,7] ]
这道题看起来很简单,坑不少,直观理解就是通过一个变量flag来控制奇数时从左子节点-右子节点放入queue中,偶数时从右子节点-左子节点放入queue中,那么对不对呢~~~too simple!!!当然不是,我们来看看规律:
我们还是需要一个deque(双端队列,两端均可进出,为什么需要deque而不是queue,待会会说),对如下树:
遍历顺序如上图所示
1:3放入deque的back处,然后从deque的front出,我们先让3的右子节点先进deque,然后左节点进deque(默认是back进,front出,不特殊说明都是这个进出方法),此时的deque如图:
2:因为对于第二层必须要先访问20,然后9,所以必须20先从front出,由于不能从同一侧既出又进,所以对于第二层,是从front出,子节点先放右子节点,后放左子节点。第二层front出完deque后如图:
3:由于要先出15,后出7,所以对于第三层,必须从back出,由于要考虑第四层,所以放子节点必须先放左子节点,后方右子节点,第三层back出完后如图:
4:根据遍历顺序,必须先出9,再出17,所以出deque的顺序为front出,同理如果有第五层,则对这层的节点必须按照先放右子节点,后放左子节点的顺序。
按照上面的规律,我们总结出:
奇数层(根节点算第一层):back出,先放左子节点,后右子节点。
偶数层:front出,先放右子节点,后放左子节点。
等等!!!!!按照这个代码写出来还是错的,因为还要考虑根节点的特殊情况,根节点是第一层,但却是先放右子节点,后放左子节点,由于只有一个节点,back或者front出没区别。
总结出上述规律和特殊情况后就可以写代码了:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> res;
if (!root) {
return res;
}
deque<TreeNode*> deque;
deque.push_back(root);
bool left_to_right = true;
bool first = true;
while (!deque.empty()) {
int q = deque.size();
vector<int> tmp;
for (int i = 0; i < q; i++) {
if (first) {
tmp.push_back(deque.front()->val);
if (deque.front()->right) {
deque.push_back(deque.front()->right);
}
if (deque.front()->left) {
deque.push_back(deque.front()->left);
}
deque.pop_front();
first = false;
}
else{
if (left_to_right) {
tmp.push_back(deque.back()->val);
if (deque.back()->left) {
deque.push_front(deque.back()->left);
}
if (deque.back()->right) {
deque.push_front(deque.back()->right);
}
deque.pop_back();
}
if (!left_to_right) {
tmp.push_back(deque.front()->val);
if (deque.front()->right) {
deque.push_back(deque.front()->right);
}
if (deque.front()->left) {
deque.push_back(deque.front()->left);
}
deque.pop_front();
}
}
}
left_to_right = !left_to_right;
res.push_back(tmp);
}
return res;
}