层序遍历十道题
层序遍历其实很简单,用一个队列很容易就能实现
102. 二叉树的层序遍历
这道题目要求逐层范围,因此别忘了在每层开始前记录一下当前队列的大小,作为弹出结点的个数
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty())
{
int size = q.size();
vector<int> vec;
while (size--)
{
TreeNode* cur = q.front();
q.pop();
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
vec.push_back(cur->val);
}
res.push_back(vec);
}
return res;
}
107.二叉树的层次遍历 II
比那个多个翻转
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty())
{
int size = q.size();
vector<int> vec;
while (size--)
{
TreeNode* cur = q.front();
q.pop();
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
vec.push_back(cur->val);
}
res.push_back(vec);
}
reverse(res.begin(), res.end());
return res;
}
199.二叉树的右视图
稍微修改一下,层序改从右向左,每次都把第一个先放进res
vector<int> rightSideView(TreeNode* root) {
vector<int> res;
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty())
{
int size = q.size();
res.push_back(q.front()->val);
while (size--)
{
TreeNode* cur = q.front();
q.pop();
if (cur->right) q.push(cur->right);
if (cur->left) q.push(cur->left);
}
}
return res;
}
637.二叉树的层平均值
vector<double> averageOfLevels(TreeNode* root) {
vector<double> res;
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty())
{
int size = q.size();
double sum = 0;
for (int i = 0; i < size; i++)
{
TreeNode* cur = q.front();
q.pop();
sum += cur->val;
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
}
res.push_back(sum / size);
}
return res;
}
429.N叉树的层序遍历
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> res;
queue<Node*> q;
if (root) q.push(root);
while (!q.empty())
{
int size = q.size();
vector<int> vec;
while (size--)
{
Node* cur = q.front();
q.pop();
for (auto& x : cur->children) q.push(x);
vec.push_back(cur->val);
}
res.push_back(vec);
}
return res;
}
515.在每个树行中找最大值
vector<int> largestValues(TreeNode* root) {
vector<int> res;
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty())
{
int size = q.size();
int maxNum = INT_MIN;
while (size--)
{
TreeNode* cur = q.front();
q.pop();
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
maxNum = max(maxNum, cur->val);
}
res.push_back(maxNum);
}
return res;
}
116.填充每个节点的下一个右侧节点指针
Node* connect(Node* root) {
queue<Node*> q;
if (root) q.push(root);
while (!q.empty())
{
int size = q.size();
// cout << size << endl;
for (int i = 0; i < size; i++)
{
Node* cur = q.front();
q.pop();
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
if (i == size - 1) cur->next = nullptr;
else cur->next = q.front();
}
}
return root;
}
117.填充每个节点的下一个右侧节点指针II
同116
104.二叉树的最大深度
1.层序遍历
int maxDepth(TreeNode* root) {
int depth = 0;
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty())
{
depth++;
int size = q.size();
while (size--)
{
TreeNode* cur = q.front();
q.pop();
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
}
}
return depth;
}
2.递归
显然,深度等于 max(左子树深度,右子树深度) + 1
int maxDepth(TreeNode* root) {
if (root == nullptr) return 0;
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
111.二叉树的最小深度
1.层序
int minDepth(TreeNode* root) {
int depth = 0;
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty())
{
depth++;
int size = q.size();
while (size--)
{
TreeNode* cur = q.front();
q.pop();
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
if (cur->left == nullptr && cur->right == nullptr)
return depth;
}
}
return depth;
}
2.递归
int minDepth(TreeNode* root) {
if (root == nullptr) return 0;
if (root->left == nullptr && root->right == nullptr) return 1;
if (root->left == nullptr) return minDepth(root->right) + 1;
if (root->right == nullptr) return minDepth(root->left) + 1;
return min(minDepth(root->left), minDepth(root->right)) + 1;
}
226.翻转二叉树
从此开始,我们就是使用几种遍历的题目了
这个题目就是把每个结点都左右翻一下,可以的方法很多,但是一定要搞清翻转的次数,别翻了又翻回去。
我们可以遍历每个结点,然后让它的两个子结点翻转。
对于前中后序遍历,层序遍历,我们可以将原本的打印换成别的工作,来实现一些功能
1.前、后序翻转(递归)
前序和后序都可以,但是中序不行,中序翻转的子树是同一个(其实也不是不行,只不过就是两次invert都是左子树,因为后一次的左实际上是原本的右,写题还是不能太机械)
TreeNode* invertTree(TreeNode* root) {
//翻转左子树,翻转右子树,左右翻转
if (root == nullptr) return nullptr;
//左、右、中,因此这是后序
invertTree(root->left);
invertTree(root->right);
swap(root->left, root->right);
return root;
}
2.利用遍历翻转
既然前序后序可以,自然我们可以用迭代版本
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> st;
if (root) st.push(root);
while (!st.empty())
{
TreeNode* cur = st.top();
st.pop();
if (cur->right) st.push(cur->right);
if (cur->left) st.push(cur->left);
swap(cur->left, cur->right);
}
return root;
}
3.层序遍历
层序遍历实际也可以,只不过还是注意先入队列后翻转
TreeNode* invertTree(TreeNode* root) {
queue<TreeNode*> q;
if (root) q.push(root);
while (!q.empty())
{
int size = q.size();
while (size--)
{
TreeNode* cur = q.front();
q.pop();
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
swap(cur->left, cur->right);
}
}
return root;
}
4.统一迭代法
这个是为了复习统一迭代法,所以我们写一下
统一迭代法不受遍历方法影响,因为访问一定在处理前,而访问时已经将结点入栈了,即便翻转了也不影响处理顺序
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> st;
if (root) st.push(root);
while(!st.empty())
{
TreeNode* cur = st.top();
st.pop();
if (cur)
{
//以中序为例
if (cur->right) st.push(cur->right);
st.push(cur);
st.push(nullptr);
if (cur->left) st.push(cur->left);
}
else
{
cur = st.top();
st.pop();
swap(cur->left, cur->right);
}
}
return root;
}
101. 对称二叉树
1.自己想的,用前序和翻转的前序对比
bool isSymmetric(TreeNode* root) {
//以中左右和中右左顺序遍历,检测是否一样
stack<TreeNode*> st1;
stack<TreeNode*> st2;
if (root) { st1.push(root);st2.push(root); }
while (!st1.empty() && !st2.empty())
{
TreeNode* cur1 = st1.top();
TreeNode* cur2 = st2.top();
st1.pop();
st2.pop();
if (cur1->val != cur2->val) return false;
if (cur1->left && cur2->right) { st1.push(cur1->left); st2.push(cur2->right); }
else if (!cur1->left && !cur2->right) { }
else return false;
if (cur1->right && cur2->left) { st1.push(cur1->right); st2.push(cur2->left); }
else if (!cur1->right && !cur2->left) { }
else return false;
}
return st1.empty() && st2.empty();
}
2.递归
bool compare(TreeNode* left, TreeNode* right)
{
if (left == nullptr && right == nullptr) return true;
else if (left != nullptr && right == nullptr) return false;
else if (left == nullptr && right != nullptr) return false;
else if (left->val != right->val) return false;
return compare(left->left, right->right) && compare(left->right, right->left);
}
bool isSymmetric(TreeNode* root) {
return compare(root->left, root->right);
}
3.使用队列,成对放入比较(类似层序遍历)
其实换成栈也可以,只要是成对成对比就行。(用栈的话就是上一层从外往里,这一层从里往外,不影响)
bool isSymmetric(TreeNode* root) {
queue<TreeNode*> q;
if (root) { q.push(root->left);q.push(root->right); }
while (!q.empty())
{
TreeNode* l = q.front();q.pop();
TreeNode* r = q.front();q.pop();
//两个对称位置的节点只有存在和不存在
if (l == nullptr && r == nullptr) continue;
if (!l || !r || l->val != r->val) return false;
q.push(l->left);
q.push(r->right);
q.push(l->right);
q.push(r->left);
}
return true;
}