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驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    摩尔定律 四
    为什么要重载new? 四
    JS 完美识别IE FIREFOX CHROME safari
    Chrome的JS调试工具
    JetBrains WebStorm 6注册码(其实版本v4, v5, v6都通用)
    require.js 入门学习
    str_replace、preg_replace、strtr比较
    获取当前IP地址,跳转到对应城市网站。
    mysql大数据高并发处理(转)
    SESSION的安全性(转)
  • 原文地址:https://www.cnblogs.com/itdef/p/12821239.html
Copyright © 2011-2022 走看看