简单概括下题目要求:
- 将输入数据中的时间修改正确;
- 根据输入的字符串查找是否有匹配。
题目并不难,但是输入输出的格式以及几处细节比较繁琐,写起来可能比较复杂。
具体细节不在详述了,可以参考代码。
解决的方式有很多,这里提供一种方式,对于题目要求的查找匹配以及匹配后的排序可以使用 STL
中的 map
以及 foreach
进行存储和输出。
map<string, map<int, json_content>> userData;//json_content 是仿照题目要求自定义的结构体
for (int i = 0; i < m; i++)
{
cin >> keyWord;
if (userData.find(keyWord) != userData.end())
{
for (auto j : userData[keyWord])
{
format_out(j.second);//格式化输出
}
}
else
{
puts("Maybe this student help to arrest Bulbul.");
}
}
json_content
是仿照题目要求自定义的结构体,用于后面的 format_out()
用于输出,但也可以将其处理为一个字符串,省去 format_out()
的过程。
需要注意的一点是,修正月份的时候,9月应当修正为10月,如果只是判断出月份的最后一位并 ++
,则这种情况无法被正确的处理。可以进行特判或者是将月份整体转化为数字后进行输出。(题解代码中采用的后者)
完整代码
#include <bits/stdc++.h>
using namespace std;
struct json_content
{
string nickname;
string publicTime;
string content;
int keyTime;
}; // 仿照题目的 JSON 要求自定义的结构体
map<string, map<int, json_content>> userData; // 嵌套使用的 map
// 格式化输出的函数
void format_out(json_content content)
{
string f1 = "{\"nickname\":\"";
string f2 = "\",\"publicTime\":\"";
string f3 = "\",\"content\":\"";
string f4 = "\"}";
cout << f1 << content.nickname << f2 << content.publicTime << f3 << content.content << f4 << endl;
}
// 以下两个函数是字符串转数字以及数字转字符串
int toNum(string s)
{
int num = 0;
int len = s.size();
for (int i = 0; i < len; i++)
{
num *= 10;
num += s[i] - '0';
}
return num;
}
string toString(int num)
{
string str;
stack<char> s; // 这里使用栈进行倒置,从而输出正确的字符串
while (num)
{
s.push((num % 10) + '0');
num /= 10;
}
while (s.size())
{
str += s.top();
s.pop();
}
return str;
}
// 该函数为修正时间,传参时使用了C++的引用,可以直接在函数体中通过形参改变实参
void changeTime(string s, json_content &content)
{
string year, month, day;
string newTime, strNum;
int len = s.size();
int tag1 = 0, tag2 = 0; // 这里是记录了时间中 “-” 的位置,从而更好地分隔字符串
for (int i = 0; i < len; i++)
{
if (s[i] == '-')
{
if (!tag1)
tag1 = i;
else
tag2 = i;
continue;
}
}
// 使用 substr 进行分隔字符串,这里需要注意边界
year = s.substr(0, tag1);
month = s.substr(tag1 + 1, (tag2 - tag1 - 1));
month = toString(toNum(month) + 1);
day = s.substr(tag2 + 1, (len - tag2 - 1));
newTime = year + "-" + month + "-" + day;
strNum = year;
/*
* 这一部分是构造时间的索引,我们可以将所有的时间进行统一
* 补齐月份和日期的前导零,使新的字符串的低四位永远是匹配的月份。
* 高四位的年份补齐或不补齐并无影响。举例说明;
* 220-1-1 重新构造后变为了 2200101
* 2023-1-17 重新构造后变为了 20230117
* 2022-12-30 重新构造后变为了 20221230
* 这样就可以比较日期的大小了。
* 此处可以转换为 int 也可以直接用 string 做索引(string 在 map 中按字典序排序)
*/
if (month.size() == 1)
{
strNum += "0";
}
strNum += month;
if (day.size() == 1)
{
strNum += "0";
}
strNum += day;
content.publicTime = newTime;
content.keyTime = toNum(strNum);
}
// 添加新的数据到 map 中
void add(string s)
{
int len = s.size();
int cnt = 0;
json_content content;
int begin = 13;
for (int i = 13; i < len; i++) // 数一下 JSON 中的字符数量可知,第十三个字符是昵称的开始
{
if (s[i] == ',')
{
cnt++;
if (cnt == 1)
i += 14; // 同上,这一部分的字符是固定的
else
i += 11; // 同上,这一部分的字符是固定的
begin = i + 1; // 注意边界问题
continue;
}
if (s[i] == '\"')
{
switch (cnt)
{
case 0:
content.nickname = s.substr(begin, (i - begin));
break;
case 1:
changeTime(s.substr(begin, (i - begin)), content);
break;
case 2:
content.content = s.substr(begin, (i - begin));
break;
}
}
}
userData[content.nickname].insert({content.keyTime, content});
}
int main()
{
int n, m;
string input;
cin >> n;
getchar(); // 吃一下回车
for (int i = 0; i < n; i++)
{
getline(cin, input);
add(input);
}
cin >> m;
string keyWord;
for (int i = 0; i < m; i++)
{
cin >> keyWord;
if (userData.find(keyWord) != userData.end())
{
for (auto j : userData[keyWord]) // foreach 输出
{
format_out(j.second);
}
}
else
{
puts("Maybe this student help to arrest Bulbul.");
}
}
return 0;
}