题意:给出n篇文章,每篇文章有若干行,文章与文章之间用**********分开,再给出m个查询,查询分为四种:
1、A:查询所有包含A的那一行字符串
2、A AND B:查询一篇文章中同时包含A和B,A或B所在的那一行
3、A OR B:查询包含A或B所在的那一行
4、NOT A:查询不包含A的文章
在输出结果的时候,不同文章之间的行用----------分开,注意这里是10个符号,链接里面的输出数据里面只给了9个,被这个坑惨了(´இ皿இ`) ,不同的查询之间用==========分开,也是10个。
思路:
1、首先用vector数组保存所有字符串,同一片文章的所有行保存在一个vector中
2、在读取每一篇文章的每一行的时候,进行大小写转换,但不是将转换后的字符串保存在vector中,转换之后利用stringstream读取每一个单词,之后将这个单词所在的文章标号和行数保存在一个map中,map的键是string类型,值是vector<pair<int,int>>类型。
3、读取每一个操作,判断是哪种操作,利用set和集合的交并补即可AC
个人总结:
1、begin、end、rbegin、rend他们的区别
2、集合的操作
代码:
#include <set>
#include <map>
#include <vector>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 150;
typedef pair < int , int > PII;
int n , m;
set < PII > res;
string s , t , op;
vector < string > arts[N]; // 储存所有的文章
map < string , vector< PII > > loc; //储存每一个单词所在的位置
int main(void)
{
cin >> n;getchar();
for(int i = 0 ; i < n ; ++ i)
{
int line = 0;
while(getline(cin , s) , s[0] != '*')
{
arts[i].push_back(s);//第i篇文章的标号也就是i
int len = s.length();
for(int i = 0 ; i < len ; ++ i)//大小写转换
{
if(!isalpha(s[i])) s[i] = ' ';//如果不是一个字母,直接转成空格
else s[i] = tolower(s[i]);
}
stringstream in(s);//利用stingstream读取单词
while(in >> s) loc[s].push_back({i , line});//记录每个单词所在的文章和行数
line ++;
}
}
cin >> m;getchar();
while(m --)
{
res.clear();
getline(cin , op);
int a = op.find(' ') , b = op.rfind(' ');//分别从前往后和从后往前找到两个空格的位置
if(a != string::npos && b != string::npos && a != b && b - a - 1 == 3)//如果是AND查询
{
set < int > s1 , s2;
s = op.substr(0 , a);
t = op.substr(b + 1);
res.insert(loc[s].begin() , loc[s].end());//先将所有包含s和t的 编号及对应的行数添加到结果集合中
res.insert(loc[t].begin() , loc[t].end());
for(auto i : loc[s]) s1.insert(i.first);//s1保存所有s出现的文章
//找到交集
for(auto i : loc[t])
if(s1.find(i.first) != s1.end())
s2.insert(i.first);//s2保存的是所有同时有s和t的文章的编号
auto backup = res;//这里要先备份一下
for(auto i : backup)//删除
if(s2.find(i.first) == s2.end())
res.erase(i);
}
else if(a != string::npos && b != string::npos && a != b && b - a - 1 != 3)//OR查询
{
s = op.substr(0 , a);
t = op.substr(b + 1);
//or查询直接插入即可
res.insert(loc[s].begin() , loc[s].end());
res.insert(loc[t].begin() , loc[t].end());
}
else if(a != string::npos && b != string::npos && a == b)//NOT查询
{
//NOT查询要单独输出
s = op.substr(4);
set < int > art;
for(int i = 0 ; i < n ; ++ i)art.insert(i);
for(auto i : loc[s])
art.erase(i.first);//操作之后,art变为所有不包含s的文章编号
for(auto i : art)//对于NOT操作要输出整篇文章
{
for(auto j : arts[i]) cout << j << endl;
if(i != *art.rbegin()) puts("----------");
}
if(art.empty()) puts("Sorry, I found nothing.");
puts("==========");
continue;
}
else//第一种操作
{
s = op;
res.insert(loc[s].begin() , loc[s].end());
}
int pre = -1;
for(auto i : res)
{
if(i.first != pre && pre != -1) puts("----------");
pre = i.first;
cout << arts[i.first][i.second] << endl;
}
if(res.empty()) puts("Sorry, I found nothing.");
puts("==========");
}
return 0;
}