1.题目描述:
自动语音识别(ASR)需要音频和文本的对应数据进行训练,但是通常我们无法直接拿到这样对应好的数据,因此需要一定的方法来构造。假设有一个句子列表1(长度为n),里面是既定的文本,我们要对每个文本构建一段对应的录音。方法是让录音人员一次性完成列表1中的文本的录音,规则是录完一条再录下一条。每条可能不止录一次,因为可能读错或读的不标准,所以对一条文本可再次尝试录音,最多可以再试x次,每次之间有停顿。然后对这个完整音频根据停顿切分成小音频,并对所有小音频进行语音识别(用当前ASR系统,这次识别会不太准)之后,得到列表2,长度最大为(x+1)*n,列表1和列表2都是有序的。现在要求对列表1中的每个元素,找到列表2中对应的元素(即文本相似度最高),使所有项的相似度的和最大(注意每个项的相似度最大不一定相似度的和最大),然后拿列表2中对应元素的音频作为既定文本的对应的录音。在相似度的和最大的基础上,对于既定的文本,我们倾向于选择录音人员最后一次说的比较好的录音,即尽量选择列表2中下标比较大的项。
为了简单起见,文本相似度采用 Jaccard距离进行计算,定义如下:
相似度 = s(i)和s(j)的交集的大小 / s(i)和s(j)的并集的大小,
其中s(i)和s(j)都是上述列表中的字符串,其交集是同时存在于二者中的字符组成的集合,并集是二者所有字符组成的集合。
那么你现在准备好为AI贡献自己的力量了吗?
输入输出:
编译器版本: gcc 4.8.4
请使用标准输入输出(stdin,stdout) ;请把所有程序写在一个文件里,勿使用已禁用图形、文件、网络、系统相关的头文件和操作,如sys/stat.h , unistd.h , curl/curl.h , process.h
时间限制: 3S (C/C++以外的语言为: 5 S) 内存限制: 128M (C/C++以外的语言为: 640 M)
输入:
输入数据有三行:
第一行是列表1,元素以英文逗号分隔
第二行是列表2,元素以英文逗号分隔
第三行是参数x
输出:
列表1中的每个元素对应列表2中的每个元素的下标,英文逗号分隔。
样例1:
输入:
床前明月光,疑是地上霜,举头望明月,低头思故乡
越光,床前地上霜,大地孤烟直,举头明月,低头是故乡
1
输出:
0,1,3,4
思路:
就,整呗,咱也不知道对不对
代码:
#include <iostream>
#include <vector>
#include <sstream>
#include <cstdio>
#include <map>
/*请完成下面这个函数,实现题目要求的功能*/
/*当然,你也可以不按照下面这个模板来作答,完全按照自己的想法来 ^-^ */
/******************************开始写代码******************************/
template < typename T > std::string to_string( const T& n )
{
std::ostringstream stm ;
stm << n ;
return stm.str() ;
}
float cmp(std::string A,std::string B)
{
float Jscore = 0.0,Bscore = 0.0;
std::map<char,int> m;
for(int i=0;i<A.size();i++)
{
if(m[A[i]] > 0)
;
else
m[A[i]]++,Bscore += 1;
}
for(int i=0;i<B.size();i++)
{
if(m[B[i]] > 0)
Jscore += 1;
else
Bscore += 1;
}
return Jscore/Bscore;
}
std::string audioMatch(std::vector<std::string>& list1, std::vector<std::string>& list2, int x) {
int now = 0;
float most_cmp = 0;
std::vector<int> res(list1.size()+1);
// for(int i=0;i<list1.size();i++)
// std::cout<<i<<" "<<list1[i]<<std::endl;
for(int i=0;i<list1.size();i++)
{
most_cmp = 0;
int j;
for(j=now;j<list2.size()&&j-now<=x;j++)
{
float score = cmp(list1.at(i),list2.at(j));
if(i+1<list1.size())
if(score < cmp(list1.at(i+1),list2.at(j)))
break;
if(most_cmp<score)
{
res[i] = j;
most_cmp = score;
}
}
now = j;
}
std::string resS;
for(int i=0;i<list1.size();i++)
{
resS += to_string(res[i]);
if(i<list1.size()-1)
resS += ',';
}
return resS;
}
/******************************结束写代码******************************/
void split(std::string& input_str, std::vector<std::string>& output_list) {
std::istringstream tmp_stream(input_str);
std::string tmp_str;
while (getline(tmp_stream, tmp_str, ',')) {
output_list.push_back(tmp_str);
}
}
int main() {
std::string s1;
std::cin >> s1;
std::string s2;
std::cin >> s2;
int x = 0;
std::cin >> x;
std::vector<std::string> list1;
std::vector<std::string> list2;
split(s1,list1);
split(s2,list2);
std::string res = audioMatch(list1, list2, x);
std::cout << res << std::endl;
return 0;
}
2.题目描述:
每天都有无数的人跟我厂出品的天猫精灵对话,天猫精灵为人类跟他说的每句话都打上了一个意图标签,一个人的所有对话就是这些意图标签组成的序列,这个序列里面的子序列就是一段对话,意图有查天气、查温度、查股票、放音乐、讲笑话等等。最近天猫精灵灵光一闪,想研究下人类的对话,看看人们都喜欢怎么和它说话,比如有的人喜欢先问天气,再问股票,再让它讲个笑话,再放首歌,有的人喜欢问了天气之后再问空气质量,然后再问下明天的天气,还有的人喜欢先听听歌,然后叫出租车去上班等等。天猫精灵要找出人们普遍的规律,分析出大家一般都喜欢怎么和他说话。那么首先天猫精灵必须先解决一个问题,就是给定两个用户的意图序列,找出相似(编辑距离 <= 阈值)的子意图序列的pair,并且每个子意图序列满足一定的长度要求(长度必须在闭区间 [minSeqLen, maxSeqLen] 内),一个子序列可重复出现在多个pair中。比如如下就是满足长度要求(长度区间 [5, 8])的两个相似(编辑距离为1,小于等于阈值2)的子意图序列pair:
A: weather, joke, music, stock, joke, joke, news
B: weather, joke, music, stock, joke, joke, texi
那么现在你可以帮天猫精灵完成这个任务吗?
输入输出:
编译器版本: gcc 4.8.4
请使用标准输入输出(stdin,stdout) ;请把所有程序写在一个文件里,勿使用已禁用图形、文件、网络、系统相关的头文件和操作,如sys/stat.h , unistd.h , curl/curl.h , process.h
时间限制: 3S (C/C++以外的语言为: 5 S) 内存限制: 128M (C/C++以外的语言为: 640 M)
输入:
输入数据包括五行:
第一行:一个数字,编辑距离阈值
第二行:一个数字,最小的序列长度
第三行:一个数字,最大的序列长度
第四行:用户A的意图序列,英文逗号分隔
第五行:用户B的意图序列,英文逗号分隔
输出:
一个数字,满足条件的意图序列的pair的个数
样例1:
输入:
1
3
5
weather,joke,music,stock,joke,news,taxi,temperature,pm2.5
joke,music,news,stock,joke,joke,news,taxi
输出:
14
思路:
先搞个编辑距离的函数出来,再暴力数呗,咱题目都看不懂,反正样例也没过
代码:
#include <iostream>
#include <vector>
#include <sstream>
#include <cmath>
#include <algorithm>
#include <cstdio>
using namespace std;
/*请完成下面这个函数,实现题目要求的功能*/
/*当然,你也可以不按照下面这个模板来作答,完全按照自己的想法来 ^-^ */
/******************************开始写代码******************************/
//算法
int ldistance(const string source, const string target)
{
//step 1
int n = source.length();
int m = target.length();
if (m == 0) return n;
if (n == 0) return m;
//Construct a matrix
typedef vector< vector<int> > Tmatrix;
Tmatrix matrix(n + 1);
for (int i = 0; i <= n; i++) matrix[i].resize(m + 1);
//step 2 Initialize
for (int i = 1; i <= n; i++) matrix[i][0] = i;
for (int i = 1; i <= m; i++) matrix[0][i] = i;
//step 3
for (int i = 1; i <= n; i++)
{
const char si = source[i - 1];
//step 4
for (int j = 1; j <= m; j++)
{
const char dj = target[j - 1];
//step 5
int cost;
if (si == dj){
cost = 0;
}
else{
cost = 1;
}
//step 6
const int above = matrix[i - 1][j] + 1;
const int left = matrix[i][j - 1] + 1;
const int diag = matrix[i - 1][j - 1] + cost;
matrix[i][j] = min(above, min(left, diag));
}
}//step7
return matrix[n][m];
}
int findSimilarPairs(int threshold, int minSeqLen, int maxSeqLen, std::vector<std::string>& list1, std::vector<std::string>& list2) {
int res = 0;
for(int i=0;i<list1.size();i++)
{
if(minSeqLen<=list1.at(i).length()&&list1.at(i).length()<=maxSeqLen)
for(int j=0;j<list2.size();j++)
{
if(minSeqLen<=list2.at(j).length()&&list2.at(j).length()<=maxSeqLen)
{
int dis = ldistance(list1.at(i),list2.at(j));
if(dis<=threshold)
res++;
}
}
}
return res;
}
/******************************结束写代码******************************/
void split(std::string& input_str, std::vector<std::string>& output_list) {
std::istringstream tmp_stream(input_str);
std::string tmp_str;
while (getline(tmp_stream, tmp_str, ',')) {
output_list.push_back(tmp_str);
}
}
int main() {
int threshold = 0;
std::cin >> threshold;
int minSeqLen = 0;
std::cin >> minSeqLen;
int maxSeqLen = 0;
std::cin >> maxSeqLen;
std::string s1;
std::cin >> s1;
std::string s2;
std::cin >> s2;
std::vector<std::string> list1;
std::vector<std::string> list2;
split(s1,list1);
split(s2,list2);
int res = findSimilarPairs(threshold, minSeqLen, maxSeqLen, list1, list2);
std::cout << res << std::endl;
return 0;
}