1. 问题描述
在做自然语言处理的时候,我们有可能会搭建到语音转换文字的模型。为了训练这个模型,我们需要设计一个相似度模型用于匹配目标输出和模型输出的相似度。
Input
输入两行,每行一个句子,第一行是目标输出,第二行是模型输出。
Output
输出它们的相似度,保留两位小数。
相似度=目标输出和模型输出单词元素的交集的元素个数 / 目标输出和模型输出单词元素的并集的元素个数。
样例
Input:
I am a college student
I am an college students
Output:
0.43
2. 思路
题目说得很清楚了,就是求集合的交集和并集。但是,处理输入的数据有一点难点:没有告诉每行的单词数,一行的输入以换行结束,所以怎么把两个句子里的单词分开存有点难。C++没有像Python中的split那样的神器,要把句子中的单词分割出来可以用find()定位出空格字符的位置,再用substr()截出来,不过这样有点麻烦,这里用stringstream来解决。先看个例子:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
string s;
stringstream ss;
getline(cin, s); // 输入以回车结束,可以输入空格
ss << s; // 将s输出到ss对象中
string st;
while(ss >> st) { // 一个单词一个单词输出
cout << st << endl;
}
return 0;
}
Input:
I am a college student
output:
I
am
a
college
student
3. 参考代码
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;
/*统一输入*/
void input(set<string>& st)
{
string line;
getline(cin, line);
stringstream ss;
ss << line;
string temp;
// 将句子中的单词放到set中
while (ss >> temp) st.insert(temp);
}
int main()
{
set<string> a;
set<string> b;
input(a); // 第一行输入
input(b); // 第二行输入
vector<string> res_i; // 交集结果
vector<string> res_u; // 并集结果
set_intersection(a.begin(), a.end(), b.begin(), b.end(), back_inserter(res_i));
set_union(a.begin(), a.end(), b.begin(), b.end(), back_inserter(res_u));
#define NDEBUG
#ifndef NDEBUG
cout << "intersection number=" << res_i.size() << "\t"
<< "union number=" << res_u.size() << endl;
#endif
printf("%.2f", res_i.size()*1.0 / res_u.size());
return 0;
}
4. 笔记
求交集set_intersection()和求并集set_union()函数:在上面代码中,两个set对象的处理结果最后放在了vector中,为什么不用set来存放结果呢?
set<string> res_ii; // 用set对象来存放结果
set_intersection(a.begin(), a.end(), b.begin(), b.end(), back_inserter(res_ii));
运行一下,报错了:大意是说set类没有push_back()操作。那就定义一个自己的MySet实现一下:
template <class Ty>
class MySet :public set<Ty>
{
public:
// 继承set类,添加一个push_back函数并实现
inline void push_back(const Ty& _Val) {
this->insert(_Val);
}
}
使用自己定义的MySet类就可以使用set来存放结果了:
MySet<string> mst; // 用自己定义的MySet对象来存放结果
set_intersection(a.begin(), a.end(), b.begin(), b.end(), back_inserter(mst));
*补充:*发现一个插入迭代器insert_iterator
可以用,C++文档这么写的:
The container needs to have an insert member function (such as most standard containers).
所以求交集和并集可以这样用:
// 要加上头文件#include <iterator>
#include <iterator>
...
set<string> res_st;
set_intersection(a.begin(), a.end(), b.begin(), b.end(), insert_iterator<set<string>>(res_st,res_st.begin()));