leetcode 17.26. 稀疏相似度
两个(具有不同单词的)文档的交集(intersection)中元素的个数除以并集(union)中元素的个数,就是这两个文档的相似度。例如,{1, 5, 3} 和 {1, 7, 2, 3} 的相似度是 0.4,其中,交集的元素有 2 个,并集的元素有 5 个。给定一系列的长篇文档,每个文档元素各不相同,并与一个 ID 相关联。它们的相似度非常“稀疏”,也就是说任选 2 个文档,相似度都很接近 0。请设计一个算法返回每对文档的 ID 及其相似度。只需输出相似度大于 0 的组合。请忽略空文档。为简单起见,可以假定每个文档由一个含有不同整数的数组表示。
输入为一个二维数组 docs,docs[i] 表示 id 为 i 的文档。返回一个数组,其中每个元素是一个字符串,代表每对相似度大于 0 的文档,其格式为 {id1},{id2}: {similarity},其中 id1 为两个文档中较小的 id,similarity 为相似度,精确到小数点后 4 位。以任意顺序返回数组均可。
示例:
输入:
[
[14, 15, 100, 9, 3],
[32, 1, 9, 3, 5],
[15, 29, 2, 6, 8, 7],
[7, 10]
]
输出:
[
“0,1: 0.2500”,
“0,2: 0.1000”,
“2,3: 0.1429”
]
提示:
docs.length <= 500
docs[i].length <= 500
相似度大于 0 的文档对数不会超过 1000
解题思路
暴力枚举 ,O(n^2*c), 勉强k过,精度卡的让我怀疑人生
也可以
枚举对于每个数子的相同组
代码
枚举每对
class Solution {
public:
using ve2 = vector<vector<int>>;
using ve1 = vector<int>;
using si = ve1::size_type;
vector<string> ans;
inline string itoa(int a) {
string s;
if (a == 0) return "0";
while (a) {
s += (a%10)+'0';
a/=10;
}
reverse(s.begin(), s.end());
return s;
}
string out(int a) {
string s = ": ";
s += itoa(a/10000);
s += '.';
a %= 10000;
string ss;
for (int i = 0; i < 4; ++i) {
ss += ((a%10)+'0');
a/=10;
}
reverse(ss.begin(), ss.end());
return s+ss;
}
void similarity(ve1 &a, ve1 &b, string &s) {
int k = 0;
for (si i = 0, j = 0; i < a.size() && j < b.size();) {
if (a[i] == b[j]) k++,i++,j++;
else if (a[i] > b[j]) j++;
else i++;
}
if (k == 0) return ;
double an = k*1./(a.size()+b.size()-k);
k = an*100000;
if (k%10 > 5 || (k%10 == 5 && k/10 > 0))
k+=10;
k/=10;
if (k == 0) return;
s += out(k);
ans.push_back(s);
return ;
}
void sol(ve2 &v) {
for (si i = 0; i < v.size(); ++i) {
for (si j = i+1; j < v.size(); ++j) {
string a = itoa(i)+","+itoa(j);
similarity(v[i], v[j], a);
}
}
}
vector<string> computeSimilarities(vector<vector<int>>& docs) {
for (auto & i : docs)
sort(i.begin(), i.end());
sol(docs);
return ans;
}
};
AC 代码2 :枚举对于每个数子的相同组
class Solution {
public:
vector<string> computeSimilarities(vector<vector<int>>& docs) {
map<int, vector<int>> ma;
map<pair<int, int>, int> counts;
vector<int>cnt;
for (int i = 0; i < docs.size(); ++i) {
cnt.push_back(docs[i].size());
for (auto &d : docs[i]) {
ma[d].push_back(i);
}
}
for (const auto &[a, b] : ma) {
for (int i = 0; i < b.size(); ++i) {
for (int j = i+1; j < b.size(); ++j) {
++counts[{b[i],b[j]}];
}
}
}
vector<string>ans;
for (const auto &[a, b] : counts) {
int fm = cnt[a.first]+cnt[a.second]-b;
double f = b*1./fm;
char s[20];
sprintf(s, "%d,%d: %.4f", a.first, a.second, f+1e-9);
ans.push_back(s);
}
return ans;
}
};