字符串相似度匹配算法_莱茵斯坦距离算法

package day0330;

public class LevenshteinDistanceUtil {

	public static void main(String[] args) {
		String a = "WN64 F98";
		String b = "WN64 F98 ";
		System.out.println("相似度:" + getSimilarityRatio(a, b));
	}

	/**
	 * 获取两字符串的相似度
	 * 
	 * @param str
	 * @param target
	 * @return
	 */
	public static int getSimilarityRatio(String str, String target) {
		int max = Math.max(str.length(), target.length());
		System.out.println("两个字符串中最大长度:" + max);
		System.out.println("莱茵斯坦距离:" + compare(str, target));
		return Math.round((1 - (float) compare(str, target) / max) * 100);
	}

	/**
	 * 获取莱茵斯坦距离d[n,m]
	 * 
	 * @param str
	 * @param target
	 * @return
	 */
	private static int compare(String str, String target) {
		int d[][];// 矩阵
		int n = str.length();
		int m = target.length();
		int i; // 遍历str的
		int j; // 遍历target的
		char ch1;// str的
		char ch2;// target的
		int temp;// 记录相同字符在某个矩阵位置值的增量,不是O就是1
		if (n == 0) {
			return m;
		}
		if (m == 0) {
			return n;
		}
		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.charAt(i - 1);
			// 去匹配target
			for (j = 1; j <= m; j++) {
				ch2 = target.charAt(j - 1);
				// 这里加32是为了不区分大小写
				if (ch1 == ch2 || ch1 == ch2 + 32 || ch1 + 32 == ch2) {
					temp = 0;
				} else {
					temp = 1;
				}
				// 左边+1,上边+1,左上角+temp取最小
				d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + temp);
			}
		}
		return d[n][m];
	}

	/**
	 * 获取最小值
	 * 
	 * @param one
	 * @param two
	 * @param three
	 * @return
	 */
	private static int min(int one, int two, int three) {
		return (one = one < two ? one : two) < three ? one : three;
	}
}


原理

两个字符串之间的Levenshtein Distance莱文斯坦距离指的是将一个字符串变为另一个字符串需要进行编辑操作最少的次数。其中,允许的编辑操作有以下三种。

  • 「替换」:将一个字符替换成另一个字符
  • 「插入」:插入一个字符
  • 「删除」:删除一个字符

两个字符串均不为空串

当两个字符串均不为空串时,这里假设字符串A为horse、字符串B为ros进行举例分析。由于上述三种类型的操作不会改变字符串中各字符的相对顺序,故我们可以这样进行思考。每次仅对字符串A末尾进行操作,即只考虑 字符串A的前i个字符 和 字符串B的前j个字符 的莱文斯坦距离。其中。这里的i、j均为从1开始计数。则 字符串A的前5个字符 和 字符串B的前3个字符 的莱文斯坦距离lev(5,3),就是最终我们所求的字符串A、字符串B之间的莱文斯坦距离

  • 「插入」

假设我们把 horse 变为 ro 的莱文斯坦距离记为u,即:

# 字符串A的前5个字符 和 字符串B的前2个字符 的莱文斯坦距离为 u
lev(5,2) = u

则 horse 期望变为 ros,其所需的编辑次数不会超过 u+1。因为 horse 只需先经过u次编辑操作变为 ro,然后在尾部插入s字符即可变为 ros

  • 「删除」

假设我们把 hors 变为 ros 的莱文斯坦距离记为v,即:

# 字符串A的前4个字符 和 字符串B的前3个字符 的莱文斯坦距离为 v
lev(4,3) = v

则 horse 期望变为 ros,其所需的编辑次数不会超过 v+1。因为 horse 只需先进行一次删除操作变为 hors,再经过v次编辑操作即可变为 ros

  • 「替换」

假设我们把 hors 变为 ro 的莱文斯坦距离记为w,即

# 字符串A的前4个字符 和 字符串B的前2个字符 的莱文斯坦距离为 w
lev(4,2) = v

则 horse 期望变为 ros,其所需的编辑次数不会超过 w+1。因为 horse 只经过w次编辑操作即可变为 roe,然后通过一次替换操作,将尾部的e字符替换为s字符即可

至此,在这个例子中不难看出,horse、ros的莱文斯坦距离满足如下的递推公式

lev(horse, ros) = lev(5,3) 
                = min( lev(5,2)+1, lev(4,3)+1, lev(4,2)+1 )
                = min(u+1, v+1, w+1)

特别地,这里对通过替换途径实现的方式做一定的说明。如果 某字符串A的第i个字符 与 某字符串B的第j个字符 完全相同,则其所需的编辑次数肯定不会超过 lev(i-1, j-1)。因为无需进行替换

通过上面的分析过程,我们其实不难看出。如果期望 字符串A的前i个字符 与 字符串B的前j个字符 完全相同。可以有如下三种途径操作方式进行实现。而最终的莱文斯坦距离就是下面三种实现方式中次数最小的一个

  1. 在 字符串A的前i个字符 与 字符串B的前j-1个字符 完全相同的基础上,进行一次**「插入」**操作
  2. 在 字符串A的前i-1个字符 与 字符串B的前j个字符 完全相同的基础上,进行一次**「删除」**操作
  3. 在 字符串A的前i-1个字符 与 字符串B的前j-1个字符 完全相同的基础上,如果字符串A的第i个字符与字符串B的第j个字符不同,则需要进行一次**「替换」**操作;如果字符串A的第i个字符与字符串B的第j个字符相同,则无需进行任何操作

推演过程

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/204632.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

扫码听音乐该如何制作?音乐的二维码生成方法

多个音频文件怎么做成一个二维码显示&#xff1f;二维码在现在的生活中拥有丰富的使用场景&#xff0c;可以用来作为多种内容类型的载体&#xff0c;比如音频二维码就是经常被使用的一种二维码类型。通过扫秒二维码来听音频文件&#xff0c;更加的灵活方便&#xff0c;那么音频…

六、shell编程

详见 《shell编程超详细入门教程》

队列基础(循环队列)

1.队列的定义: 和栈相反,队列(queue)是一种先进先出(first in first out,缩写为FIFO)的线性表.它只允许在表的一端进行插入,而在另一端删除元素. 在队列中,允许插入的一端叫做队尾(rear),允许删除的一端则称为队头(front). 2.循环队列的设计图示: 3.循环队列的结构设计: ty…

电话销售如何提高成功率

电话销售是一种非常有效的销售方式&#xff0c;睡着通信技术&#xff0c;互联网的发展&#xff0c;现在电话销售已经成为一种重要的销售方式&#xff0c;很多行业和领域都有使用。 虽然最终目的都是为了将产品卖出去&#xff0c;但是对于电话销售来说&#xff0c;前期寻找客户…

MySQL进阶知识:锁

目录 前言 全局锁 表级锁 表锁 元数据锁&#xff08;MDL&#xff09; 意向锁 行级锁 行锁 行锁演示 间隙锁/临界锁 演示 前言 MySQL中的锁&#xff0c;按照锁的粒度分&#xff0c;分为以下三类 全局锁&#xff1a;锁定数据库中的所有表。表级锁&#xff1a;每次操…

11-@Transaction与AOP冲突解决

如题&#xff0c;最近碰到了一个问题&#xff0c;在public方法上添加Transaction没有生效&#xff0c;事务没有回滚。 我自己模拟了一个功能&#xff0c;向数据库表User里面插入用户数据。说一下代码背景&#xff0c; 数据库MySQL&#xff0c;持久化层Mybatis&#xff0c;项目使…

Linux系统编程 day07 信号

Linux系统编程 day07 信号 1. 信号的介绍以及信号的机制2. 信号相关函数2.1 signal2.2 kill2.3 abort和raise2.4 alarm2.5 setitimer 3. 信号集4. 信号捕捉函数6. SIGCHLD信号7. SIGUSR1与SIGUSR2 1. 信号的介绍以及信号的机制 信号是信息的载体&#xff0c;在Linux/Unix环境下…

行业追踪,2023-11-30

自动复盘 2023-11-30 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

企业数字化转型应对传统网络挑战的关键策略

数字化变革正在以前所未有的速度和规模改变着我们的生活和工作方式&#xff0c;使得传统网络架构面临着巨大的挑战。其中包括带宽需求增加、多云应用增加、安全威胁增加以及传统网络设备无法满足需求等问题。 数字化时代需要更高速、更可靠、更安全的网络支持&#xff0c;传统网…

C语言必备知识--函数返回局部变量

0.总结 1. 不能以局部变量的方式创建字符串数组的首地址 2.如果函数的返回值非要是一个局部变量的地址&#xff0c;那么该局部变量一定要申明为static类型 3.返回指向字符串常量的指针 4.数组不能作为函数返回值 5.在函数中可以返回局部变量的值&#xff0c;但是不能返回…

如何安装鸿蒙Harmony 4.0低版API9三方库

比如我要用下拉刷新三方库pulltorefresh 安装命令如下 ohpm install ohos/pulltorefresh 安装完后然后运行Demo报错,说没有isAtEnd方法 然后查看pulltorefresh 最新版2.0.4对应Harmony API10,然而我的手机是API9,所以必须找到API9的库&#xff0c;然后查看2.0.1是还是API9 所…

docker集群的详解以及超详细搭建

文章目录 一、问题引入1. 多容器位于同一主机2. 多容器位于不同主机 二、介绍三、特性四、概念1. 节点nodes2. 服务(service)和任务(task)3. 负载均衡 五、docker网络1. overlay网络 六、docker集群搭建1. 环境介绍2. 创建集群3. 集群网络4. 加入工作节点 七、部署可视化界面po…

建设中国版MBA在线教育网站,群硕为Quantic敲开中国大门

2024考研即将拉开序幕&#xff0c;一个令人胆寒的问题出现在问答社区热榜—— 从现实来看&#xff0c;学历贬值已经成为一种全球现象。在卷学历的也不仅是大学生&#xff0c;还有很多职场人士&#xff0c;渴望通过获得MBA学位成为精英人才、商业领袖。 Quantic是交互式MBA线上…

热部署怎么部署

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言操作流程&#xff1a;在这里插入图片描述 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a832d83c091742eda9d9325931a89df4.png) 这里的跟上面的…

【自动化测试】pytest 用例执行中print日志实时输出

author: jwensh date: 20231130 pycharm 中 pytest 用例执行中 print 日志 standout 实时命令行输出 使用场景 在进行 websocket 接口进行测试的时候&#xff0c;希望有一个 case 是一直执行并接受接口返回的数据 def on_message(ws, message):message json.loads(message)…

Liunx配置Tomcat自启动

Liunx配置Tomcat自启动 Tomcat安装配置Tomcat开机启动 Tomcat安装 下载tomcat软件安装包&#xff0c;上传软件包到Liunx服务器。 解压软件包到opt目录下 tar -xvf apache-tomcat-9.0.76.tar.gz -c /opt配置Tomcat开机启动 &#xff08;1&#xff09;修改Tomcat bin目录下的ca…

有”亿“点强,抖音的服务器带宽是如何应对亿人同时刷屏的?

在当今这个“网络横行”的时代&#xff0c;刷短视频已然成为许多人日常生活的一部分。 当我们在刷短视频的时候&#xff0c;尽管家里的网速并不慢&#xff0c;但短视频播放的卡顿却让人难以忍受&#xff0c;有时候真的让人想扔掉手机。 那么&#xff0c;为什么会出现这种情况…

Elk+Filebeat+Kafka实现日志收集

ElkFilebeatKafka实现日志收集(本机nginx) 部署Zookeeper 1.实验组件 #准备3台服务器做Zookeeper集群 20.0.0.10 20.0.0.20 20.0.0.30 2.安装前准备 #关闭防火墙 systemctl stop firewalld systemctl disable firewalld setenforce 0#安装JDK yum install -y java-1.8.0-o…

【LeetCode】每日一题 2023_11_29 无限集中的最小数字(哈希/堆)

文章目录 刷题前唠嗑题目&#xff1a;无限集中的最小数字题目描述代码与解题思路偷看大佬题解 结语 刷题前唠嗑 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 今天的题目也比较的简单&#xff0c;因为数据量不大&#xff0c;所以什么做法都能过的去 题目&a…

Ruoyi-Vue或者Ruoyi-Cloud登录进去之后的第一个页面如何修改(即如何去掉首页或者如何修改首页)

其实大家如果看过最近的码云上的issues 就能知道这个问题的答案了。 我这里给出一下链接&#xff1a;https://gitee.com/y_project/RuoYi-Vue/issues/I60JIY 开始 第一步&#xff0c;把router/index.js里面关于首页的路由给注释掉或者删除掉&#xff0c;如图&#xff1a; 第…