糟糕糟糕OMG 魔法怎么失灵了 – 题解

简单概括下题目要求:

  1. 将输入数据中的时间修改正确;
  2. 根据输入的字符串查找是否有匹配。

题目并不难,但是输入输出的格式以及几处细节比较繁琐,写起来可能比较复杂。
具体细节不在详述了,可以参考代码。

解决的方式有很多,这里提供一种方式,对于题目要求的查找匹配以及匹配后的排序可以使用 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;
}