PTA数据结构与算法编程题目集 7-44 基于词频的文件相似度 (30 分)

7-44 基于词频的文件相似度 (30 分)
实现一种简单原始的文件相似度计算,即以两文件的公共词汇占总词汇的比例来定义相似度。为简化问题,这里不考虑中文(因为分词太难了),只考虑长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。

输入格式:
输入首先给出正整数N(≤100),为文件总数。随后按以下格式给出每个文件的内容:首先给出文件正文,最后在一行中只给出一个字符#,表示文件结束。在N个文件内容结束之后,给出查询总数M(≤10
​4
​​ ),随后M行,每行给出一对文件编号,其间以空格分隔。这里假设文件按给出的顺序从1到N编号。

输出格式:
针对每一条查询,在一行中输出两文件的相似度,即两文件的公共词汇量占两文件总词汇量的百分比,精确到小数点后1位。注意这里的一个“单词”只包括仅由英文字母组成的、长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。单词间以任何非英文字母隔开。另外,大小写不同的同一单词被认为是相同的单词,例如“You”和“you”是同一个单词。

输入样例:
3
Aaa Bbb Ccc

Bbb Ccc Ddd

Aaa2 ccc Eee
is at Ddd@Fff

2
1 2
1 3
输出样例:
50.0%
33.3%

思路: 一开始是打算直接来,写几个函数将文件中的不合法单词都过滤掉,然后再另一个文件中查找另一个文件的单词,最后计算结果,然而最后一个测试点被卡的死死的,无论我怎么优化总会超时,就这样这道题目卡了将近两天

以下是原来的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<cctype>
using namespace std;
const int maxn = 1e4;
int N,M;
char File[110][maxn];
char word[11];

void extractword(char a[],int *ptr)//提取单词
{
    memset(word,0,sizeof(word));
    for(;*ptr < strlen(a);(*ptr)++){
        int v = 0;
        while(isalpha(a[*ptr]) && v < 10){
            a[*ptr] = tolower(a[*ptr]);
            word[v++] = a[(*ptr)++];
        }
        if(v >=3 && v <= 10){
            return;
        }
    }
}

void filter(char a[])  // 过滤长度小于3的单词和长度大于10多于的字母
{
    for(int i=0;i < strlen(a);i++){
        int len = 0;
        int ptri = i;
        if(isalpha(a[i])){
            while(isalpha(a[i])){
                len++;
                i++;
                if(len > 10){
                    a[i - 1] = ' ';
                }
            }
            if(len < 3){
                while(ptri < i){
                    a[ptri++] = ' ';
                }
            }
        }
        else
            a[i] = ' ';
    }
}

bool Search(const char word[],string a[],int n)//二分查找法,查找两个文件中是否有相同的单词
{
    int L = 0, R = n;
    while(R > L){
        int M = (R-L)/2 + L;
        int f = strcmp(word,a[M].c_str());
        if(f == 0)
            return true;
        else if(f > 0){
            L = M + 1;
        }
        else{
            R = M;
        }
    }
    return false;
}

int main()
{
    cin >> N;
    for(int i=1;i <= N;i++){
        int j = 0;
        string c;
        while((getline(cin,c)) && strcmp(c.c_str(),"#") != 0){
            strncat(File[i],c.c_str(),c.length());//将一个文件中的内容拼接在一起
        }
        filter(File[i]); //过滤掉不合法的字母
    }
    cin >> M;
    for(int i=0;i < M;i++){
        int f1,f2;
        scanf("%d%d",&f1,&f2);
        int ptr = 0,n1 = 0,n2 = 0,same = 0;
        string F1[100000],F2[100000];
        while(ptr < strlen(File[f1])){
            extractword(File[f1],&ptr); //每次提取出一个单词
            if(strlen(word) >= 3 && !Search(word,F1,n1))
                F1[n1++].append(word);//代表文件一的合法单词集
                sort(F1,F1+n1);//排序后才能利用二分查找法
        }
        ptr = 0;
        while(ptr < strlen(File[f2])){
            extractword(File[f2],&ptr);
            if(strlen(word) >= 3 && !Search(word,F2,n2))
                F2[n2++].append(word);//文件二的合法单词集
                sort(F2,F2+n2);
        }
        for(int j = 0;j < n2;j++){
            if(Search(F2[j].c_str(),F1,n1)){
                same++;
            }
        }
        double x = same,y = n1 + n2 - same;
        printf("%.1lf%%\n",x/y*100);
    }
    return 0;
}

虽然很想继续优化下去不过卡了太久了,不得不换个方法,然后想到了c++的关联容器set,代码变得非常简洁,看来以后要多熟悉c++中的容器了

改进后的代码:

#include<iostream>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<string>
#include<set>
using namespace std;
int N,M;
set<string> File[110];

void extractword(string word,set<string> &File)
{
    for(int i=0;i < word.length();i++){//全部小写化
        if(isalpha(word[i])){
            word[i] = tolower(word[i]);
        }
    }
    for(int i=0;i < word.length();i++){//给每个文件加入合法单词
        int len = 0,ptri = i;
        if(isalpha(word[i])){
            while(isalpha(word[i])){
                if(len >= 10){
                    word[i] = ' ';
                }
                else
                    len++;
                i++;
            }
            if(len >= 3 && len <= 10){
                File.insert(word.substr(ptri,len));
            }
        }
    }
}

int main()
{
    cin >> N;
    for(int i=1;i <= N;i++){
        string word;
        while((getline(cin,word) && word != "#")){
            extractword(word,File[i]); 
        }
    }
    cin >> M;
    for(int i=0;i < M;i++){
        int f1,f2;
        int same = 0,n1,n2;
        scanf("%d%d",&f1,&f2);
        n1 = File[f1].size();
        n2 = File[f2].size();
        for(set<string>::iterator it = File[f1].begin();it != File[f1].end();it++){
            if(File[f2].find(*it) != File[f2].end()){
                same++;
            }
        }
        double x = same,y = n1 + n2 - same;
        printf("%.1lf%%\n",x/y*100);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43189757/article/details/88857975