搜索里的相似度计算-最长公共字串

相似度计算的任务是根据两段输入文本的相似度返回从0到1之间的相似度值:完全不相似,则返回0,;完全相同,返回1.衡量两端文字距离的常用方法有:海明距离(Hamming distance),编辑距离,欧氏距离,文档向量的夹角余弦距离,最长公共字串。

1. 余弦相似度

把两篇文档看作是词的向量,如果x,y为两篇文档的向量,则:Cos(x, y) = (x * y) / (||x|| * ||y||)

使用Hashmap可以很方便的把这个计算出来

2. 最长公共字串(Longest Common Subsequence, LCS)

假设有串s1 = {a,b,c,b,d,a,b}, s2={b,d,c,a,b,a}, s1和s2的最长公共字串应当有3个”bdab”,”bcab”,”bcba”。

这又是一个动态规划法的应用,思维过程就简单带过,生成一个s1.size + 1 X s2.size+1的矩阵,行和列分别是s1和s2的每个字母,填充矩阵,如果对应的两个字母相同,就把斜上角的元素+1,填充到当前矩阵位置,如果不同,取该位置相邻左边及上边的最大值,一直把矩阵填满,最右下角的矩阵值就是最长公共字串的长度。

b,d,c,a,b,a

0,0,0,0,0,0,0,
a  0,0,0,0,1,1,1,
b  0,1,1,1,1,2,2,
c  0,1,1,2,2,2,2,
b  0,1,1,2,2,3,3,
d  0,1,2,2,2,3,3,
a  0,1,2,2,3,3,4,
b  0,1,2,2,3,4,4

得到最长公共字串的矩阵后,剩下的工作就是回溯。

如果当前位置的s1字符和s2字符相同,则是相同的数值。

如果不同,则要向上或向左移动,移动到大的一边,与填充矩阵的逻辑对应。

如果是相同呢?

如果只求其中一个公共字串,逻辑比较简单,随便想上或者向左

如果要求所有的公共字串,则每一边都有可能,可以简单用递归解决。

好了。说这么多,上代码。

 1 #encoding:utf-8
 2 require ‘matrix‘
 3 class Matrix
 4   def []=(i, j, x)
 5     @rows[i][j] = x
 6   end
 7 end
 8
 9 # 最长公共字串
10 def start
11   $s1 = ‘abcbdab‘
12   $s2 = ‘bdcaba‘
13   $num = Matrix.zero($s1.size + 1, $s2.size + 1)
14   puts "Row = #{$num.row_size}, col = #{$num.column_size}"
15
16   for i in 1..$s1.size
17     for j in 1..$s2.size
18       if $s1[i - 1] == $s2[j - 1]
19         $num[i, j] = $num[i-1, j-1] + 1
20       else
21         $num[i, j] = [$num[i-1, j], $num[i, j-1]].max
22       end
23     end
24   end
25
26   puts "最长公共字串的长度是#{$num[$s1.size, $s2.size]}"
27   $num.each_with_index { |val, row, col| print val,‘,‘; puts if (col + 1) % $num.column_size == 0}
28
29   # 回溯路径
30   $result = []
31   $lcs_length = $num[$s1.size, $s2.size]
32   s1position = $s1.size
33   s2position = $s2.size
34   loop_path(s1position, s2position, ‘‘)
35   $result.each {|x| puts "lcs: #{x}"}
36
37   puts "one path is: #{one_loop_path(s1position,s2position, ‘‘)}"
38 end
39
40 def one_loop_path(s1position, s2position, result)
41   while s1position != 0 and s2position != 0
42     if $s1[s1position - 1] == $s2[s2position - 1]
43       result << $s1[s1position - 1]
44       s2position -= 1
45       s1position -= 1
46       next
47     end
48
49     if $num[s1position, s2position - 1] >= $num[s1position - 1, s2position]
50       s2position -= 1
51     else
52       s1position -= 1
53     end
54   end
55   result
56 end
57
58 def loop_path(s1position, s2position, result)
59   while s1position != 0 and s2position != 0
60     if $s1[s1position - 1] == $s2[s2position - 1]
61       result << $s1[s1position - 1]
62       s2position -= 1
63       s1position -= 1
64       next
65     end
66
67     if $num[s1position, s2position - 1] > $num[s1position - 1, s2position]
68       s2position -= 1
69     elsif $num[s1position, s2position - 1] < $num[s1position - 1, s2position]
70       s1position -= 1
71     elsif $num[s1position, s2position - 1] == $num[s1position - 1, s2position]
72       leftpath = result.clone
73       uppath = result.clone
74       loop_path(s1position, s2position - 1, leftpath)
75       loop_path(s1position - 1, s2position, uppath)
76       break
77     end
78   end
79   $result << result.reverse! if result.size == $lcs_length
80   # $result << result.reverse! if result.size == $lcs_length
81 end
82
83 start

搜索里的相似度计算-最长公共字串

时间: 2024-10-18 14:54:49

搜索里的相似度计算-最长公共字串的相关文章

最长递归子序列、最长公共字串、最长公共子序列、编辑距离

[TOC]   ### 最长递归子序列 #### 题目 给定数组arr,返回arr中的最长递增子序列,如`arr=[2,1,5,3,6,4,8,9,7]`,返回的最长递增子序列为`[1,3,4,8,9]` #### 题解思路 先用DP来求解子序列递增的最大长度,如arr的长度序列为`dp=[1,1,2,2,3,3,4,5,4]`,然后对这个长度序列dp从右到左遍历,得到最长递增子序列. 1. 求解长度序列,令dp[i]表示在以arr[i]这个数结尾的情况下,arr[0...i]中的最大递增子序列

URAL 1517 Freedom of Choice(后缀数组,最长公共字串)

题目 输出最长公共字串 #define maxn 200010 int wa[maxn],wb[maxn],wv[maxn],ws[maxn]; int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];}//yuan lai zhi qian ba zhe li de l cuo dang cheng 1 le ... void da(int *r,int *sa,int n,int m) { int i,j

【编程题目】最长公共字串

56.最长公共字串(算法.字符串).题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串二的子串.注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中.请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串.例如:输入两个字符串 BDCABA 和 ABCBDAB,字符串 BCBA 和 BDAB 都是是它们的最长公共子串,则输出它们的长度 4,并打印任意一个子串. 经典动态规划题. #include <stdio.h> #i

最长公共子序列与最长公共字串

显然最长公共子序列不一定需要连续的,只要字符的顺序严格递增即可.最长公共字串需要字符连续 子序列代码: package test; import java.util.*; /* * 本题是求最长公共子序列,子序列未必连续,只需要严格递增即可 * 如 abcdeeeeeeeee和atttbggcd 最长公共子序列为abcd 长度为4 * * */ public class Main4{ public static void main(String... args){ try(Scanner in

(字符串)最长公共字串(Longest-Common-SubString,LCS)

题目: 给定两个字符串X,Y,求二者最长的公共子串,例如X=[aaaba],Y=[abaa].二者的最长公共子串为[aba],长度为3. 子序列是不要求连续的,字串必须是连续的. 思路: 1.简单思想: 遍历两个字符串X.Y,分别比较X的字串与Y的字串,求出最长的公共字串. #include <iostream> #include <vector> using namespace std; int getComLen(char *str1,char *str2){ int len=

lintcode_79最长公共字串

给出两个字符串,找到最长公共子串,并返回其长度. 样例 给出A="ABCD",B="CBCE",返回 2 class Solution: """ @param: A: A string @param: B: A string @return: the length of the longest common substring. """ def longestCommonSubstring(self, A,

poj 3080 kmp求解多个字符串的最长公共字串,(数据小,有点小暴力 16ms)

Blue Jeans Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14113   Accepted: 6260 Description The Genographic Project is a research partnership between IBM and The National Geographic Society that is analyzing DNA from hundreds of thousa

Problem 2902 - palindrome(最长公共字串)

Longest PalindromeTime Limit:3000MS    Memory Limit:0KB    64bit IO Format:%lld & %llu SubmitStatus Description Problem D: Longest Palindrome Time limit: 10 seconds A palindrome is a string that reads the same from the left as it does from the right.

POJ 2774 (后缀数组 最长公共字串) Long Long Message

用一个特殊字符将两个字符串连接起来,然后找最大的height,而且要求这两个相邻的后缀的第一个字符不能在同一个字符串中. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 200000 + 10; 7 8 char s[maxn]; 9 int n; 10 int sa[maxn], rank[maxn],