一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
剑指 Offer 32 - II. 从上到下打印二叉树 II
思路
和上一题的代码一样,区别在于,每一层结束的时候,往queue里塞一个NULL做每一层的结尾标记。当我们访问到一层的结尾时,由于BFS的特点,我们刚好把下一层都加到了队列中。这个时候就可以给这层加上结尾标记NULL了。
c++代码
/**
* 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>> res; //记录答案
if(!root) return res;
vector<int> level; //记录一层节点
queue<TreeNode*> q;
q.push(root);
q.push(NULL); //第一层结尾标记
while(q.size()){
auto t = q.front();
q.pop();
if(!t){ //遍历到当前层的结尾
if(level.empty()) break;
res.push_back(level);
q.push(NULL); //给下一层添加结尾标记
level.clear();
}else{
level.push_back(t->val); //先将当层节点存贮到level,再将下一层存贮到队列中
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
}
return res;
}
};
剑指 Offer 32 - III. 从上到下打印二叉树 III
思路
和上一题的思路类似,我们再加上一个flag标记,初始化flag = false,表示奇数行,如果是偶数行,flag = true,每次打印完一行后,将flag取反。
c++代码
class Solution {
public:
// 宽度优先遍历
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res; //记录答案
queue<TreeNode*> q; //队列
vector<int> level; //存贮一层的节点
bool flag = false; //标记
q.push(root); //根节点入队
q.push(NULL); //一层的结尾标记
while(q.size()){
TreeNode* t = q.front();
q.pop();
if(!t){ //一层结束
if(!level.size()) break; // 最后一层结束
if(flag) reverse(level.begin(), level.end());
res.push_back(level);
flag = !flag;
level.clear();
q.push(NULL); //结尾标记入队
}else{
level.push_back(t->val); // 存贮当层节点
if(t->left) q.push(t->left); //下一层节点入队列
if(t->right) q.push(t->right);
}
}
return res;
}
};
剑指 Offer 33. 二叉搜索树的后序遍历序列
思路
递归 O(n^2)
什么是二叉搜索树 ?
二叉搜索树是一棵有序的二叉树,所以我们也可以称它为二叉排序树。具有以下性质的二叉树我们称之为二叉搜索树:若它的左子树不为空,那么左子树上的所有值均小于它的根节点;若它的右子树不为空,那么右子树上所有值均大于它的根节点。它的左子树和右子树分别也为二叉搜索树。
二叉搜索树的后序遍历是左右根,先遍历左子树,然后右子树,最后根节点。
判断是否是二叉搜索树的后序遍历序列:
- 递归当前序列的左右边界。
- 根节点是当前序列的最后一个元素。
- 遍历出左子树的终点在什么地方,这样我们就可以知道右子树的起始位置,然后我们遍历右子树的所有节点,看一下是否右子树的所有节点是否都比根节点要大,满足合法,否则不合法。
- 递归左右子树,只有左右子树同时合法,我们这棵树才是合法的。
如何遍历左子树的终点?
左子树的元素都小于根节点,这样我们从头遍历seq序列,通过该性质找到左右子树的分界点k,那么左子树序列为[l, k - 1],右子树序列为[k, r - 1]。
时间复杂度分析: dfs中有个while循环,最坏情况下会循环 O(n) 次,一共会执行O(n) 次dfs,所以时间复杂度是 O(n^2)。
c++代码
class Solution {
public:
bool verifyPostorder(vector<int>& post) {
if(post.empty()) return true;
return dfs(post, 0 ,post.size() - 1);
}
bool dfs(vector<int>& post, int l, int r){
if(l >= r) return true; //递归边界,只剩下一个数肯定满足
int root = post[r]; //记录根节点
int k = l;
while(k < r && post[k] < root) k++; //先遍历出左子树的终点 k - 1
for(int i = k; i <= r; i++){
if(post[i] < root) return false;
}
return dfs(post, l, k - 1) && dfs(post, k, r - 1);
}
};