引言
牛客网刷题模式和leetcode的核心代码模式不同,其需要自行处理输入输出。本篇介绍刷题如何处理输入输出,以及刷题遇到的一些常见函数与其他知识。
以之前遇到的华为od的一道真题为例,处理输入输出:
二叉树层序遍历
题目描述
有一棵二叉树,每个节点由一个大写字母标识(最多26个节点)。
现有两组字母,分别表示后序遍历(左孩子->右孩子->父节点)和中序遍历(左孩子->父节点->右孩子)的结果,请你输出层序遍历的结果。
输入
每个输入文件一行,第一个字符串表示后序遍历结果,第二个字符串表示中序遍历结果。(每串只包含大写字母)
中间用单空格分隔。
输出
输出仅一行,表示层序遍历的结果,结尾换行。
示例1 输入输出示例仅供调试,后台判题数据一般不包含示例
输入
CBEFDA CBAEDF
输出
ABDCEF
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
struct Node
{
Node *left;
Node *right;
int val;
Node(int x) :val(x), left(nullptr), right(nullptr) {
}
};
void SplitString(string input, vector<string> &ouput, string pattern)
{
string::size_type pos;
input += pattern;
for (int i = 0; i < input.size(); i++)
{
pos = input.find(pattern, i);
if (pos < input.size())
{
string temp = input.substr(i, pos - i);
if (!(temp.empty()) && (temp != pattern))
{
ouput.push_back(temp);
}
}
i = pos + pattern.size() - 1;
}
}
Node *builTree(string backArray, string medArray)
{
//如果后序序列为空(因为在不断删减)
if (backArray.empty())
return nullptr;
//拿到后序的最后节点为根节点
int head = backArray.back();
//建立当前树的根节点
Node *root = new Node(head);
//在中序序列中找到该根节点的位置,进行分割左右
int headIndex = medArray.find(head);
//当根节点位置让左有节点,创建左子树(左子树长度都一样长)
if (headIndex > 0)
{
root->left = builTree(backArray.substr(0, headIndex), medArray.substr(0, headIndex));
}
else
{
root->left = nullptr;
}
//如果有右子树
if (headIndex < medArray.size() - 1)
{
//注意每次后序序列都要除去尾节点(根节点),这里易错
root->right = builTree(backArray.substr(headIndex).erase(backArray.substr(headIndex).size() - 1), medArray.substr(headIndex + 1));
}
else
{
root->right = nullptr;
}
return root;
}
int main()
{
string s;
getline(cin, s);
//分割为后序中序遍历序列
vector<string> treeArrays;
SplitString(s, treeArrays, " ");
//拿到后序中序序列
string a = treeArrays[0];
string b = treeArrays[1];
//根据后序和中序序列构造出树
Node *node = builTree(a,b);
//进行层序遍历
string tree;
queue<Node *> Q;
Q.push(node);
while (!Q.empty())
{
Node *head = Q.front();
Q.pop();
tree.push_back(head->val);
if (head->left != nullptr) Q.push(head->left);
if (head->right != nullptr) Q.push(head->right);
}
cout << tree << endl;
return 0;
}
1.字符串分割的几种常见处理方式
(1)输入输出
首先先回顾一下输出输出:
C++的输入输出通常使用cin、cout对象加上<< >>输入输出运算符。
①cin
cin是以空格、换行符为界(即不读入)来输入内容。
循环读入内容,并遇到换行符退出:
while (cin >> num) {
nums.push_back(num);
if (getchar() == '\n') break;
}
②getline
cin每次遇到空格和换行符就会结束,那么如果不想结束,就要使用getline
getline能够读入空格与换行符,并且默认是以换行符结束的,所以这里存在一个陷阱:
如果在getline之前用了cin或getline,那么cin之后的输入的换行符会被getline读取,导致真正的内容无法读入。
getline(cin,str,a)是将str读入到cin流中,当a不写时默认遇到换行符停止输入,并将换行符丢弃,如果a写了,如a为‘#’则表示遇到‘#’停止读入。
while(getline(cin,line))语句注意这里默认回车符停止读入,按Ctrl+Z或键入EOF回车即可退出循环。在这个语句中,首先getline从标准输入设备上读入字符,然后返回给输入流cin,注意了,是cin,所以while判断语句的真实判断对象是cin,也就是判断当前是否存在有效的输入流。
原理:
cin.getline读取换行符并替换成’\0’,并且不会主动丢弃换行符,会把它留在输入队列中。
使用:
循环读入每一行,遇到空行结束
while (getline(cin, line) && line.compare("") != 0) {
//compare相等返回0,>返回1,<返回-1
line += '\n'; //每输入完一行都换行
file += line; //将line放入file中
line.clear(); //清空line为下次做准备
}
解决方案就是清空输入缓冲区
③关于清空输入缓冲区
先补充一下C语言的输入
scanf:不会读入空格,Tab,换行符,遇到这些会输入结束。
gets:可以读入空格,Tab,换行符。
两者在读取字符串结束后会在末尾加’\0’
关于清空输入缓冲区,一般使用cin.ignore();
容易混淆的点:
cin.clear();是清理错误标识符而不是清空缓冲区。
当输入的类型不符合定义的变量类型时,会出现输入异常的情况 if (cin.fail()),那么如果输入错误,就要使用cin.clear()清理错误标识符,然后使用cin.ignore()取走刚才流中的字符来实现清空输入缓冲区。
感兴趣的可