算法介绍:
算法用途:
查询字符串之间相似度
算法问题:
对于“abcdef”和“higabc”算法计算结果为0,不符合实际,“abc”为相似字符串
优化方法:
原来方法最后计算结果是(1-最长不同字符串长度)/ 最长字符串长度,优化后的方法将最长不同字符串长度的结果由d[n][m]
改为数组最后一行或者最后一列的最小值(后面优化后的代码中的getRowColumnMin函数实现)
优化前算法Java实现:
import org.junit.Test;
/**
* <h3>JavaAlgorithm</h3>
* <p></p>
*
* @author : 张智顺
* @date : 2020-08-03 20:28
**/
public class MyLevenshtein {
public static float getSimilarityRatio(String str, String target) {
int[][] d; // 矩阵
int n = str.length();
int m = target.length();
int i; // 遍历str的
int j; // 遍历target的
String ch1; // str的
String ch2; // target的
int temp; // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
if (n == 0 || m == 0) {
return 0;
}
d = new int[n + 1][m + 1];
// 初始化第一列
for (i = 0; i <= n; i++) {
d[i][0] = i;
}
// 初始化第一行
for (j = 0; j <= m; j++) {
d[0][j] = j;
}
// 遍历str
for (i = 1; i <= n; i++) {
ch1 = str.substring(i - 1, i);
// 去匹配target
for (j = 1; j <= m; j++) {
ch2 = target.substring(j - 1, j);
if (ch1.equals(ch2)) {
temp = 0;
} else {
temp = 1;
}
// 左边+1,上边+1, 左上角+temp取最小
d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + temp);
}
}
System.out.println("最长不同字符数:" + d[n][m]);
System.out.println("字符串最长数:" + Math.max(str.length(), target.length()));
return (1 - (float) d[n][m] / Math.max(str.length(), target.length())) * 100F;
}
@Test
public void main() {
String str1 = "观音堂古塔公园北门北京市朝阳区";
String str2 = "北京市朝阳区观音堂";
System.out.println(getSimilarityRatio(str1, str2));
String string1 = "观音堂古塔公园";
String string2 = "北京市朝阳区观音堂";
System.out.println(getSimilarityRatio(string2, string1));
}
}
优化后算法Java实现:
import org.junit.Test;
/**
* <h3>JavaAlgorithm</h3>
* <p></p>
*
* @author : 张智顺
* @date : 2020-08-03 20:28
**/
public class Main {
public static float getSimilarityRatio(String str, String target) {
int[][] d; // 矩阵
int n = str.length();
int m = target.length();
int i; // 遍历str的
int j; // 遍历target的
String ch1; // str的
String ch2; // target的
int temp; // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
if (n == 0 || m == 0) {
return 0;
}
d = new int[n + 1][m + 1];
// 初始化第一列
for (i = 0; i <= n; i++) {
d[i][0] = i;
}
// 初始化第一行
for (j = 0; j <= m; j++) {
d[0][j] = j;
}
// 遍历str
for (i = 1; i <= n; i++) {
ch1 = str.substring(i - 1, i);
// 去匹配target
for (j = 1; j <= m; j++) {
ch2 = target.substring(j - 1, j);
if (ch1.equals(ch2)) {
temp = 0;
} else {
temp = 1;
}
// 左边+1,上边+1, 左上角+temp取最小
d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + temp);
}
}
System.out.println("最长不同字符数:" + getRowColumnMin(d));
System.out.println("字符串最长数:" + Math.max(str.length(), target.length()));
return (1 - (float) getRowColumnMin(d) / Math.max(str.length(), target.length())) * 100F;
}
public static int getRowColumnMin(int[][] d) {
int min = Integer.MAX_VALUE;
if (d.length <= d[0].length) {
// 最后一列中的最小值
for (int i = 0; i < d.length; i++) {
min = Math.min(d[i][d[0].length - 1], min);
}
}
if (d.length >= d[0].length) {
// 最后一行中的最小值
for (int i = 0; i < d[0].length; i++) {
min = Math.min(d[d.length - 1][i], min);
}
}
return min;
}
@Test
public void main() {
String str1 = "观音堂古塔公园北门北京市朝阳区";
String str2 = "北京市朝阳区观音堂";
System.out.println(getSimilarityRatio(str1, str2));
String string1 = "观音堂古塔公园";
String string2 = "北京市朝阳区观音堂";
System.out.println(getSimilarityRatio(string2, string1));
}
}