题目的主要信息:

  • 开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号,及相同错误出现的次数
  • 记录最多8条错误记录,循环记录,最后只用输出最后出现的八条错误记录
  • 对相同的错误记录只记录一条,但是错误计数增加,最后一个斜杠后面的带后缀名的部分(保留最后16位)和行号完全匹配的记录才做算是”相同“的错误记录
  • 输入的文件可能带路径,记录文件名称不能带路径,超过16个字符的文件名称,只记录文件的最后有效16个字符
  • 循环记录时,只以第一次出现的顺序为准,后面重复的不会更新它的出现时间,仍以第一次为准。如果个超过8条的错误中第一条出现了它,最后一条也是它,不应该输出,以它是第一条出现的为准

方法一:暴力法

具体做法:

我们可以在vector数组中嵌套两层pair,由此可以记录文件名、行号、出现次数,记为record。同时,我们准备一个8个长度的vector的pair数组用指针循环记录将要输出的文件和行号,记为res。

对于每一行输入,首先要做的提取文件名:我们从字符串末尾开始遍历,找到第一个反斜杠,将这些字符组装成文件名,如果文件名大于16,我们要用substr函数题取最后16位。

题取文件名以后,我们检查这个文件及这个行号是否在record数组中出现过了,这里遍历record数组依次检查即可,如果出现过就将其记录的出现次数加1,其他不做变动;如果没有出现过,则将其添加到record数组的末尾,然后将其添加进res数组中,这里要循环使用空间,即下标(index=(index+1)%8)(index = (index + 1) \% 8),这也刚好符合第一次出现的位置为准。

最后我们一共循环8次,每次要输出res数组中记录的字符串非空的文件名(防止不足8次的错误)、行号即record中与之对应的出现次数。

#include<iostream>
#include<vector>
using namespace std;

string getfilename(string filepath){ //题取文件名
    string res = "";
    for(int i = filepath.length() - 1; i >= 0; i--){ //逆向查找到第一个斜杠
        if(filepath[i] ==  '\\')
            break;
        res = filepath[i] + res; //将字符加到字符串前面
    }
    if(res.length() > 16) //长度大于16的时候,截取后16位
        res = res.substr(res.length() - 16, 16);
    return  res;
}

bool find(vector<pair<pair<string, int>, int>>& record, string& file, int num){ //找到出现过的文件名和行号
    for(int i = 0; i < record.size(); i++){
        if(record[i].first.first == file && record[i].first.second == num){ //文件名和行号相同
            record[i].second++; //直接在后面添加出现次数
            return true;
        }
    }
    return false;
}

void findoutput(vector<pair<pair<string, int>, int>>& record, string& file, int num){ //打印该错误出现的次数
    for(int i = 0; i < record.size(); i++){
        if(record[i].first.first == file && record[i].first.second == num){ //文件名和行号相同
            cout << record[i].second << endl; //直接输出次数
            return;
        }
    }
}

int main(){
    string filepath;
    int num; 
    vector<pair<pair<string, int>, int> > record; //记录文件名、行号、出现次数
    vector<pair<string, int> > res(8, {"", 0}); 
    int index = 0; //记录下标
    while(cin >> filepath >> num){
        string file = getfilename(filepath); //提取文件名
        if(!find(record, file, num)){ //出现新的才添加
            record.push_back(make_pair(make_pair(file, num), 1)); //记录中添加一个全新的
            res[index] = make_pair(file, num);
            index = (index + 1) % 8; //循环
        }
    }
    for(int i = 0; i < 8; i++){
        if(res[index].first != ""){ //只输出有记录的,防止不足8个
            cout << res[index].first << " " << res[index].second << " ";
            findoutput(record, res[index].first, res[index].second);
        }
        index = (index + 1) % 8;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n2)O(n^2),一共nn个字符串,每个字符串的查找都是O(n)O(n)
  • 空间复杂度:O(n)O(n),记录字符串的长度最坏为nn

方法二:哈希表

具体做法:

我们可以用哈希表来代替上述暴力查找,省去不少时间。同时,方法一中嵌套的pair过多,我们可以将输入的行号也看成是字符串,将文件名+空间+行号,这样组成一个新的字符串看成哈希表的key值,而这个key值出现的次数即为哈希表的value值。这样我们每次只需要检查哈希表中没有出现过这一串key值就可以,添加新的key也要将其纳入res数组中,同时循环储存,最后输出的时候也是查哈希表找到出现次数。

alt

#include<iostream>
#include<vector>
#include<unordered_map>
using namespace std;

string getfilename(string filepath){ //题取文件名
    string res = "";
    for(int i = filepath.length() - 1; i >= 0; i--){ //逆向查找到第一个斜杠
        if(filepath[i] ==  '\\')
            break;
        res = filepath[i] + res; //将字符加到字符串前面
    }
    if(res.length() > 16) //长度大于16的时候,截取后16位
        res = res.substr(res.length() - 16, 16);
    return  res;
}

int main(){
    string filepath, num; //把路径和行号都当成字符串
    unordered_map<string, int> mp;
    vector<string> res(8, "");
    int index = 0; //记录下标
    while(cin >> filepath >> num){
        string file = getfilename(filepath);
        string key = file + " " + num;
        if(mp.find(key) == mp.end()){ //没有出现过,需要添加到哈希表中
            mp[key] = 1;
            res[index] = key;
            index = (index + 1) % 8; //循环记录
        }else
            mp[key]++; //遇到相同的错误,计数增加
    }
    for(int i = 0; i < 8; i++){
        if(res[index] != "") //只输出有记录的,防止不足8个
            cout << res[index] << " " << mp[res[index]] << endl;
        index = (index + 1) % 8;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n),对于unordered_map每次查找和插入都是O(1)O(1),一共nn操作
  • 空间复杂度:O(n)O(n),哈希表最大长度为nn