zoukankan      html  css  js  c++  java
  • LeetCode 面试题 17.26. 稀疏相似度

    地址 https://leetcode-cn.com/problems/sparse-similarity-lcci/

    两个(具有不同单词的)文档的交集(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

    解法  

    我们要使用哈希加速搜索比对的效率

    如果能快速的知道 某两个不同文档的交集数目 就比较好做了

    如何知道某个单词被那些文档包含呢?  遍历单词元素 依次去查询文档是否包含是最朴素的做法,但是效率太低。又可以考虑哈希加速保存和搜索

    两重哈希的做法如下

    首先 使用map<int, vector<int>> doc_idx 记录 某个单词被那些文档记录。

    然后使用一个稀疏矩阵的数据结构vector<unordered_map<int, int>> graph 记录 某两个文档有多少个相同的单词数目

    代码如下

    unordered_map<int, vector<int>> doc_idx;
        for (int i = 0; i < docs.size(); i++) {
            for (auto& e : docs[i]) {
                doc_idx[e].push_back(i);
            }
        }
        vector<unordered_map<int, int>> gra(510);    //稀疏矩阵图结构
    
        for (auto& e : doc_idx) {
            vector<int> &p = e.second;
            for (int i = 0; i < p.size(); i++) {
                for(int j = i+1;j < p.size();j++){
                int a = p[i]; int b = p[j];
                gra[a][b]++; gra[b][a]++;
                }
            }
        }

    两个结构的意义如下

    doc_idx{7,{2,3,5,7}} 表示 7号单词被文档2, 3,5,7 同时拥有 

    gra{{2,3},5} 表示文档2,3拥有的相同单词数目为5个  也就是该两个文档的交集

    那么 文档 2 3 的并集合数目 就是  文档[2]单词数目 + 文档[3]单词数目- 文档23交集数目 

    全部代码如下

    class Solution {
    public:
       
       
       vector<string> computeSimilarities(vector<vector<int>>& docs) {
        vector<string> vs;
        unordered_map<int, vector<int>> doc_idx;
        for (int i = 0; i < docs.size(); i++) {
            for (auto& e : docs[i]) {
                doc_idx[e].push_back(i);
            }
        }
        vector<unordered_map<int, int>> gra(510);    //稀疏矩阵图结构
    
        for (auto& e : doc_idx) {
            vector<int> &p = e.second;
            for (int i = 0; i < p.size(); i++) {
                for(int j = i+1;j < p.size();j++){
                int a = p[i]; int b = p[j];
                gra[a][b]++; gra[b][a]++;
                }
            }
        }
    
        for (int i = 0; i < docs.size(); i++) {
            for (int j = i + 1; j < docs.size(); j++) {
                if (gra[i][j] != 0) {
                    int num = docs[i].size() + docs[j].size() - gra[i][j];
                    double res = gra[i][j] * 1.0 / num;
                    char s[20];
                    sprintf(s, "%d,%d: %.4f", i, j, res + 1e-9);
                    //cout << s << endl;
                    vs.push_back(string(s, s + 20));
                }
            }
        }
    
        return vs;
    }
    
    
    };

    最后要注意的是 由于数据精度问题 最后计算出来的结果要加上1e-9 才和答案一致

    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    奇数阶魔方问题
    《DSP using MATLAB》示例9.3
    《DSP using MATLAB》示例9.2
    《DSP using MATLAB》示例9.1
    找个目标很重要
    《DSP using MATLAB》示例Example 8.30
    《DSP using MATLAB》示例Example 8.29
    《DSP using MATLAB》示例Example 8.28
    《DSP using MATLAB》示例Example 8.27
    《DSP using MATLAB》示例Example 8.26
  • 原文地址:https://www.cnblogs.com/itdef/p/12821239.html
Copyright © 2011-2022 走看看