第二章:set字符串string的substr截取函数 题目:基于词频的文件相似度

PTA 基于词频的文件相似度

题目:
实现一种简单原始的文件相似度计算,即以两文件的公共词汇占总词汇的比例来定义相似度。为简化问题,这里不考虑中文(因为分词太难了),只考虑长度不小于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%

思路:
很容易看出就是找两个字符串中相同的单词的个数,而且每个字符串中每个单词都是唯一的,不存在重复,可以想到set的特点。难点在于如何根据题意处理字符串。

#include <cstdio>
#include <cmath>
#include <string.h>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue> 
using namespace std;
set<string> s[105];//二维 想象成每一行是一个文件,这一行的每一列的元素是文件中的单词。
int main()
{
	int n;
	cin>>n;
	getchar();
	for(int i=0; i<n; i++)
	{
		string ss="";
		while(1)
		{//利用了string的"+"拼接。
			char c=getchar();
			if(c=='#') 
			{
				break;	
			}
			//只包括仅由英文字母组成的、长度不小于3、且不超过10的英文单词,长度超过10的只考虑前10个字母。单词间以任何非英文字母隔开。
			else if((c>='a'&&c<='z')||(c>='A'&&c<='Z'))
			{
				c=tolower(c);//大小写
				ss+=c;
			}else //如果在英文字母中发现其他字符可以分割,并进行长度判断。
			{
				if(ss.length()>=3){
					if(ss.length()>10)
					{
						ss=ss.substr(0,10);//截取函数用法,从第0个开始截取10个字符。
					}
					s[i].insert(ss);
				}
				ss="";//注意更新!!!每次结束一个单词的判断要清空string。
			}
		}
	}
	
	int m;
	cin>>m;
	int a,b;
	while(m--)
	{
		cin>>a>>b;
		int sum=0;
		for(set<string>::iterator it=s[a-1].begin(); it!=s[a-1].end(); it++){//迭代器实现元素访问
			if(s[b-1].find(*it)!=s[b-1].end()){//找相同的个数 
				sum++;			
			}		
		}
		int cnt=s[a-1].size()+s[b-1].size()-sum; 
		printf("%.1lf%%\n",sum*1.0/cnt*100.0);
	} 
}

知识点:

1.string函数“substr”截取函数:

s.substr(begin,len);//从第begin个字符开始截取,截取长度为len,begin最小为0.`在这里插入代码片`

begin的默认值是0,len的默认值是s.size() - begin
通过某个字符的位置进行截取

string s;
getline(cin,s);
string a=s.substr(0,s.find(' '));
//从第一个开始到第一个' '字符出现此时的s.find(' ')返回的值是下标,正好可以看作是截取字符的长度(如果是中间的话,不要忘记减去开始字符的下标才是长度)
string b=s.substr(s.find(' ')+1);
//此时默认len为s.size()-s.find(' ')+1

2.set容器简单运用:
优点:

set中每个元素都唯一,就像集合;
set中每个元素都是排好序的(默认从小到大),内部采用红黑树实现;
set区别与vector,它不能通过下标访问,必须用迭代器;

定义:

set<string> s[N];//定义二维,类似二维数组,也可以看成有N个set。
set<int> a;//一维
set<int> a(10);//初始大小为10个长度

常用函数:
(一维)

s.insert(x);   //插入元素x
s.size()//集合大小
s.erase(x)//删除元素x
s.clear()//清空集合
s.count(x)//集合中x元素的个数(1或0)可以实现某元素是否存在的判断
s.empty();  //判断set容器是否为空
s.begin()//返回set容器的第一个元素的迭代器(必须用迭代器接收)
s.end(); // 返回set容器的最后一个元素的迭代器(必须用迭代器接收)

(二维)可以想象成二维数组

s[i].size();      //第i行有多少列元素。
s[i].insert(x);   //在第i行插入元素x
s[i].erase(x)//删除第i行的元素x(不能直接删除一行)
s[i].clear()//清空第i行的集合
s[i].count(x)//第i行中x元素的个数(1或0)可以实现某元素是否存在的判断
s[i].empty();  //判断第i个set容器是否为空
s[i].begin()//返回第i个set容器的第一个元素的迭代器(必须用迭代器接收)
s[i].end(); // 返回第i个set容器的最后一个元素的后一个的迭代器(必须用迭代器接收)

遍历:

//采用iterator迭代
set<int>::iterator it;
for (it=s.begin(); it!=s.end(); it++){
    cout << ' ' << *it;//用*可是实现元素的输出
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值