本章主要来讲解两个OJ题,针对每个OJ题我分三部分来解决,分别是题目解析(主要弄清楚题目要求我们解决什么问题),算法原理,代码编写,接下来让我们进入正题。
一、二叉树的分层遍历
1.题目解析
题目的要求层序遍历,并且要将数据分层存储到数组中,所以需要一个二维数组作为返回值,而该题并不是简单的层序遍历,重难点在于如何把这些数据分层地存储到二维数组中,如何区分他们哪层是哪层?接下来看算法原理。
2.算法原理
对于层序遍历(广度优先遍历)使用队列再合适不过了,首先把根节点放入队列中,然后出队,访问它的左右子节点并依次放入队列中,循环进行以上操作直到队列为空,这样就能够完成层序优先遍历,不过还有一个要点就是如何把数据分层存入二维数组中。
要分层存储数据首先就需要分清楚数据分别在哪层,那么我们可以用一个变量来记录每层数据的个数,用while来单独处理每一层,比如示例一,第一层的数据个数是1个,那么用一个循环(循环的次数即为该层数据的个数)处理完第一层的数据,然后队列里的数据个数(2个)即为第二层的数据个数,然后使用循环(循环的次数即为该层数据的个数)处理第二层的数据,以此类推,直到队列为空。
3.代码编写
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> qu;
vector<vector<int>> arr;
if(root)
qu.push(root);
while(!qu.empty())
{
int sum=qu.size();//记录每层数据个数
vector<int> ar;
ar.reserve(sum);//提前开好空间减少扩容次数,提高效率
while(sum--)
{
TreeNode* rt=qu.front();
ar.push_back(rt->val);
qu.pop();
if(rt->left)
qu.push(rt->left);
if(rt->right)
qu.push(rt->right);
}
arr.push_back(ar);
}
return arr;
}
};
二、栈的压入弹出序列
1.题目解析
题目意思是给一个压栈顺序,一个出栈序列,要求判断该压栈顺序能不能弹出这样出栈序列。 例如示例一:压栈顺序1 2 3 4 5,出栈顺序4 3 5 2 1,为了达到这种出站栈顺序可以是1 2 3 4 入栈,4出栈,3出栈,5入栈,5出栈,2出栈,1出栈。即push(1),push(2),push(3),push(4),pop(4),pop(3),push(5),pop(5),pop(2),pop(1)。
示例二:压栈顺序1 2 3 4 5,出栈顺序4 3 5 1 2,为了达到这种出站栈顺序可以是1 2 3 4 入栈,4出栈,3出栈,5入栈,5出栈,然后只能是1出栈,2出栈,并不能模拟出所给的出栈效果,所以返回false。
2.算法原理
通过上面的解析我们发现,只要随便给一组入栈出栈序列,我们可以根据栈的存储规则自行判断出是否匹配。判断方法就是模拟栈的存取过程,那么我们的算法设计可以模拟栈操作,就是把我们的判断方法用代码模拟一遍。
模拟方法:准备一个空栈,准备两个指针p1和p2分别指向入栈和出栈序列的首元素下标。
第一步:把p1指向数据入栈,p1后移。
第二步:判断栈顶元素与p2指向元素是否相等,若相等则栈顶元素出栈,p2后移,然后再次判断栈顶元素与p2指向元素是否相等,以此方式重复进行直到不相等为止,进入第三部。
第三部:重复第一步和第二部,直到p1移动到数组末尾,然后判断栈是否为空,若为空说明数据都匹配上了返回true,若不是则返回false。
3.代码编写
bool IsPopOrder(vector<int>& pushV, vector<int>& popV)
{
stack<int> stk;
int p1=0,p2=0;
while(p1<pushV.size())
{
stk.push(pushV[p1++]);
while(!stk.empty()&&stk.top()==popV[p2])
{
stk.pop();
p2++;
}
}
return stk.empty();
}