使用求2个字符串最短编辑距离动态规划算法实现 git diff 算法 java 实现

测试类 MyDiffTest.java:
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;public class MyDiffTest {private static String path = "\\xxx\\";private static List<String> lines_v1 = readFile2List( path + "DemoClass1.java" );private static List<String> lines_v2 = readFile2List( path + "DemoClass2.java" );public static void main(String[] args) {/*lines_v1 = new ArrayList<>();lines_v2 = new ArrayList<>();lines_v1.add( "m" );lines_v1.add( "o" );lines_v1.add( "t" );lines_v1.add( "h" );lines_v1.add( "e" );lines_v1.add( "r" );lines_v2.add( "m" );lines_v2.add( "o" );lines_v2.add( "n" );lines_v2.add( "s" );lines_v2.add( "t" );lines_v2.add( "e" );lines_v2.add( "r" );*/int[][] dp =  calculateMinimumTransferWay(lines_v1, lines_v2);int index1 = lines_v1.size() - 1;int index2 = lines_v2.size() - 1;System.out.println( "最短编辑距离:" +  dp[index1][index2] );List<String> result = new ArrayList<>();while ( index1 >= 0 && index2 >= 0 ){String line_v1 = lines_v1.get(index1);String line_v2 = lines_v2.get(index2);if( line_v1.equals( line_v2 ) ){// v1:...a// v2:...a// 此时,v1 和 v2 的当前行相同,原封不懂的输出,表示没有改动result.add( "  " + line_v1 );index1--;index2--;}else {// v1:...a// v2:...b// 此时,v1版本的当前行和 v2版本的当前行不相同,所以v1转化为v2过程中,对 行a、行b的操作有3种可能:新增行b、删除行a// v1:...a// v2: ...  b// 如果此时的编辑距离是最小的,则v2版本需要新增 行bint sed1 = dp[index1][index2 - 1] + 1; // ps:sed 是 shortest edit distance 的缩写// v1: ...  a// v2:...b// 如果此时的编辑距离是最小的,则v2版本需要删除 行aint sed2 = dp[ index1 - 1 ][ index2 ] + 1;// v1: ...  a// v2: ...  b// 如果此时的编辑路基是最小的,则v2版本需要将 删除行a+新增行b( 一共2步操作 )int sed3 = dp[ index1 - 1 ][ index2 - 1 ] + 2;int sed = Math.min(Math.min(sed1, sed2), sed3);if( sed1 == sed ){result.add( "+ " + line_v2 );index2--;}else if( sed2 == sed ){result.add( "- " + line_v1 );index1--;}else if( sed3 == sed ){result.add( "+ " + line_v2 );result.add( "- " + line_v1 );index1--;index2--;}}}while ( index1 >= 0 ){// v1 还剩下的一些 "首行们" 都是需要被删除的行,因为v2版本没有result.add( "- " + lines_v1.get( index1 ) );index1--;}while ( index2 >= 0 ){// v2 还剩下的一些 "首行们" 都是需要被添加的行,因为v1版本没有result.add( "+ " + lines_v2.get( index2 ) );index2--;}for (int i = ( result.size() - 1 ); i >= 0;i-- ) {System.out.println( result.get( i ) );}}private static List<String> readFile2List( String filePath ){BufferedReader reader = null;try {List<String> lines = new ArrayList<>();reader = new BufferedReader(new FileReader(filePath));String line = reader.readLine();while (line != null) {lines.add( line );line = reader.readLine();}return lines;} catch (Exception e) {e.printStackTrace();return null;} finally {if (reader != null) {try {reader.close();} catch (Exception e) {e.printStackTrace();}}}}private static int[][] calculateMinimumTransferWay(List<String> lines_v1, List<String> lines_v2 ){int size_v1 = lines_v1.size();int size_v2 = lines_v2.size();int[][] dp = new int[ size_v1 ][ size_v2 ];for (int index1 = 0; index1 < size_v1; index1++) {String line_v1 = lines_v1.get( index1 );for (int index2 = 0; index2 < size_v2; index2++) {String line_v2 = lines_v2.get( index2 );if( index1 == 0 ){if( index2 == 0 ){if( line_v1.equals( line_v2 ) ){// v1:a// v2:a// 无需任何操作dp[ index1 ][ index2 ] = 0;}else {// 不相同,需要 1 步删除操作,1步插入操作// v1:a// v2:bdp[ index1 ][ index2 ] = 2;}}else {if( getFirstEqualIndex( lines_v2,line_v1,0,index2 ) != -1 ){// v1:      a// v2:...a...// 需要 index2 步插入操作dp[ index1 ][ index2 ] = index2;}else {// v1:      a// v2:...b...// 需要1步删除操作,index2 + 1步插入操作dp[ index1 ][ index2 ] = index2 + 2;}}}else {if( index2 == 0 ){if( getFirstEqualIndex(lines_v1, line_v2, 0, index1) != -1 ){// v1:...a...// v2:      a// 需要 index1 步删除操作dp[ index1 ][ index2 ] = index1;}else {// v1:...a...// v2:      b// 需要 index1 + 1 步删除操作,1步插入操作dp[ index1 ][ index2 ] = index1 + 2;}}else {if( line_v1.equals( line_v2 ) ){// v1:...a// v2:...adp[ index1 ][ index2 ] = dp[index1 - 1][index2 - 1];}else {// v1:...a// v2:...b// sed means "shorest edit distance"int sed1 = dp[index1 - 1][index2];int sed2 = dp[index1 ][index2 - 1];int sed3 = dp[index1 - 1][index2 - 1];int sed = Math.min( Math.min( sed1,sed2 ),sed3 );if( sed1 == sed || sed2 == sed ){dp[ index1 ][ index2 ] = sed + 1;}else {dp[ index1 ][ index2 ] = sed + 2;}}}}}}return dp;}private static int getFirstEqualIndex(List<String> lines, String targetLine, int beginIndex, int endIndex) {for (int i = beginIndex; i <=endIndex ; i++) {if( targetLine.equals( lines.get( i ) ) ){return i;}}return -1;}
}

旧版本文本文件 DemoClass1.java:

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.similarity.LevenshteinDistance;@Slf4j
public class DemoClass1 {private static final LevenshteinDistance LEVENSHTEIN_DISTANCE = LevenshteinDistance.getDefaultInstance();public static String null2emptyWithTrim( String str ){if( str == null ){str = "";}str = str.trim();return str;}public static String requiredStringParamCheck(String param, String paramRemark) {param = null2emptyWithTrim( param );if( param.length() == 0 ){String msg = "操作失败,请求参数 \"" + paramRemark + "\" 为空";log.error( msg );throw new BusinessLogicException( msg );}return param;}public static double calculateSimilarity( String str1,String str2 ){int distance = LEVENSHTEIN_DISTANCE.apply(str1, str2);double similarity = 1 - (double) distance / Math.max(str1.length(), str2.length());System.out.println("相似度:" + similarity);return similarity;}
}

新版本文本文件 DemoClass2.java:

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.similarity.LevenshteinDistance;@Slf4j
public class DemoClass2 {private static final LevenshteinDistance LEVENSHTEIN_DISTANCE = LevenshteinDistance.getDefaultInstance();private static final LevenshteinDistance LEVENSHTEIN_DISTANCE1 = LevenshteinDistance.getDefaultInstance();private static final LevenshteinDistance LEVENSHTEIN_DISTANCE2 = LevenshteinDistance.getDefaultInstance();public static String null2emptyWithTrim( String str ){// if( str == null ){//     str = "";// }// str = str.trim();return str;}public static String requiredStringParamCheck(String param, String paramRemark) {return null;}public static double calculateSimilarity( String str1,String str2 ){try {int distance = LEVENSHTEIN_DISTANCE.apply(str1, str2);double similarity = 1 - (double) distance / Math.max(str1.length(), str2.length());return similarity;}catch ( Exception e ){e.printStackTrace();return 0d;}}
}

测试输出:

import com.goldwind.ipark.common.exception.BusinessLogicException;import lombok.extern.slf4j.Slf4j;import org.apache.commons.text.similarity.LevenshteinDistance;@Slf4j
- public class DemoClass1 {
+ public class DemoClass2 {private static final LevenshteinDistance LEVENSHTEIN_DISTANCE = LevenshteinDistance.getDefaultInstance();
+     private static final LevenshteinDistance LEVENSHTEIN_DISTANCE1 = LevenshteinDistance.getDefaultInstance();
+     private static final LevenshteinDistance LEVENSHTEIN_DISTANCE2 = LevenshteinDistance.getDefaultInstance();public static String null2emptyWithTrim( String str ){
-         if( str == null ){
-             str = "";
-         }
-         str = str.trim();
+         // if( str == null ){
+         //     str = "";
+         // }
+         // str = str.trim();return str;}public static String requiredStringParamCheck(String param, String paramRemark) {
-         param = null2emptyWithTrim( param );
-         if( param.length() == 0 ){
-             String msg = "操作失败,请求参数 \"" + paramRemark + "\" 为空";
-             log.error( msg );
-             throw new BusinessLogicException( msg );
-         }
-         return param;
+         return null;}public static double calculateSimilarity( String str1,String str2 ){
-         int distance = LEVENSHTEIN_DISTANCE.apply(str1, str2);
-         double similarity = 1 - (double) distance / Math.max(str1.length(), str2.length());
-         System.out.println("相似度:" + similarity);
-         return similarity;
+         try {
+             int distance = LEVENSHTEIN_DISTANCE.apply(str1, str2);
+             double similarity = 1 - (double) distance / Math.max(str1.length(), str2.length());
+             return similarity;
+         }catch ( Exception e ){
+             e.printStackTrace();
+             return 0d;
+         }}}

求做小编辑距离的时候,我这里不允许编辑操作,通常的求最小编辑距离一共允许三种操作( 删除、新增、编辑 ),其中一个编辑操作和删除、新增操作的权重都算作一步,我这里不允许编辑操作,比如迫不得已必须用编辑操作时,例如将a 行变为b行,我们必须先删除,后增加,其实等效于允许编辑操作,但是编辑操作权重大一些,为什么这样规定呢?

如上所示,新版本相对于旧版本来说是连续的修改了多行,我们人眼比较习惯这种差异比较后的输出:

而不是这种输出( 虽然逻辑上也对 ):

如果允许编辑操作( 或者编辑操作的权重和删除、新增操作一样时 ),就可能会出现这种情况,整块整块的修改给当做每一行来一个编辑操作。如果不允许编辑操作( 其实等价于将编辑操作的权重设置为删除或者插入操作的2倍 ),那么当出现整块的修改时,差异化比较时,被当做多个单行的修改的概率就被降低了,因为那样的话编辑次数会更多,所以会优先的视为多行的删除( 块删除 )操作和多行的新增( 块新增 )。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Springboot启动原理解析

我们开发任何一个Spring Boot项目&#xff0c;都会用到如下的启动类 SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);} } 从上面代码可以看出&#xff0c;Annotation定义&#x…

Янгель杨格尔年谱

米哈伊尔 库兹米其 杨格尔 生于1911年11月7日&#xff08;旧历10月25日&#xff09;&#xff0c;沙俄伊尔库斯克省。逝世于1971年10月25日。 出生于农民家庭&#xff0c;有11个兄弟姐妹。 1926年6年级结束后前往莫斯科投奔哥哥。 1929年在学校学徒毕业&#xff08;&#xf…

网络运维与网络安全 学习笔记2023.12.3

网络运维与网络安全 学习笔记 第三十三天 今日目标 目录-文件基本管理、vim文本编辑、用户账号管理 组账号管理、归属控制、权限控制 目录-文件基本管理 ls 列目录及文档属性 ls - List 格式:ls[选项]…[目录或文件路径] 1.如果不以/开始,表示相对路径(省略了当前所在位置…

go并发编程(中)

目录 一、并发安全性 1.1 变量并发安全性 1.2 容器并发安全性 二、多路复用 三、协程常见的面试题 3.1交替打印奇数偶数 一、并发安全性 1.1 变量并发安全性 这个和C中并发安全是一样的&#xff0c;主要是多个线程对临界资源的同时访问&#xff0c;最经典的就是 n操作…

智慧公厕新风系统是什么?具体作用?

大家好&#xff0c;你们可曾在公厕里遇到那个臭味怪兽&#xff0c;闻得让人头晕目眩&#xff1f;别怕&#xff0c;我们有一把利剑&#xff0c;叫做“智慧公厕新风系统”&#xff01;不仅是空气净化器的升级版&#xff0c;还有一大堆高级功能等着你来领略&#xff01; 1. 风清气…

Node.js版本管理工具NVM(Node Version Manager)的使用

nvm简介 nvm&#xff08;Node Version Manager&#xff09;是一个用于管理 Node.js 版本的工具。它可以让你在同一台计算机上安装并切换多个 Node.js 版本&#xff0c;非常方便。 如何安装 nvm 下载 nvm 安装包&#xff1a;访问 https://github.com/nvm-sh/nvm#installing-a…

Kettle 安装配置

文章目录 Kettle 安装配置Kettle 安装Kettle 配置连接 Hive Kettle 安装配置 Kettle 安装 在安装Kettle之前&#xff0c;需要确定已经安装Java运行环境。Kettle需要Java的支持才能运行&#xff0c;JDK的版本最好是8.x的太新的也会出现bug。Kettle的7.1版本的太旧了&#xff0…

stm32 RTC时钟设置能不能用毫秒

stm32 RTC时钟设置能不能用毫秒 具体的程序里面写的是 RTC_SetAlarm(SENDTIMERTC_GetCounter()); 进入原函数看看发现是&#xff1a; void RTC_SetAlarm(uint32_t AlarmValue) {RTC_EnterConfigMode();/* Set the ALARM MSB word */RTC->ALRH AlarmValue >> 16;/* …

一段代码隐藏WordPress后台登录地址

WordPress作为全球知名内容管理系统&#xff0c;有太多的人和网站在使用&#xff0c;WordPress本身在安全方面已经是做的非常出色的&#xff0c;官方和社区也非常的活跃&#xff0c;但也并不是没有漏洞可钻&#xff0c;比如后台爆破。 正因为有太多的人在使用WordPress&#xf…

vue el-button 封装及使用

使用了 Element UI 中的 el-button 组件&#xff0c;并对其进行了封装和定制。 创建组件index.vue (src/common-ui/button/index.vue) <template><el-buttonclass"h-button":type"type":icon"hIcon":disabled"disabled"clic…

MQ - KAFKA 基础篇

##1、KAFKA的核心组件/API Producer API&#xff0c;它允许应用程序向一个或多个 topics 上发送消息记录 Consumer API&#xff0c;允许应用程序订阅一个或多个 topics 并处理为其生成的记录流 Streams API&#xff0c;它允许应用程序作为流处理器&#xff0c;从一个或多个主…

面试篇:算法(二:二叉树)

一:创建节点 class Node(public int idata; --节点public int Ddata; --节点数据public Node LeftChild; --左节点public Node RightChild; --右节点public void prints(System.out.print(Data);)二&#xff1a;遍历 1. 前序遍历。 public void preOrder&#xff08;Node n…

【springboot】启动失败 Failed to start bean ‘webServerStartStop‘

lsof -i&#xff1a;xxx 发现端口被占用 kill掉该进程

代码随想录算法训练营第五十三天【动态规划part14】 | 1143.最长公共子序列、1035.不相交的线、53. 最大子序和

1143.最长公共子序列 题目链接 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 求解思路 动规五部曲 1.确定dp数组及其下标含义&#xff1a; dp[i][j]&#xff1a;长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序…

OpenWrt作为旁路由(网关)配置

目录 背景前提条件环境操作步骤物理层连接设置与主路由同一网段禁用IPv6取消LAN接口桥接防火墙配置 背景 本文简介如何配置OpenWrt&#xff0c;使其作为旁路由&#xff08;网关&#xff09;运行。 旁路由大概有以下这几种工作方式&#xff1a; 主路由开DHCP&#xff0c;网关未…

QToolTip 是 Qt 框架中用于显示工具提示(Tooltip)的类

QToolTip 是 Qt 框架中用于显示工具提示&#xff08;Tooltip&#xff09;的类。 工具提示是一种小窗口&#xff0c;通常在用户将鼠标悬停在控件上时显示&#xff0c;提供有关该控件的额外信息或说明。QToolTip 类提供了设置和管理工具提示的方法。 以下是 QToolTip 常见的用法…

zephir 实现PHP封装成C语言扩展文件so实现demo简单案例【菜鸟级教程】

从github 安装 zephir.phar 最新网址 https://github.com/zephir-lang/zephir/releases 将文件改名 zephir.phar 改名为 zephir 放到 /bin 目录下 查看是否安装 zephir help安装 zephir_parser pecl install zephir_parser增加扩展到 php.ini .重新加载 extensionzephir_pars…

qt treeview 控制节点收缩

在Qt中&#xff0c;可以使用QTreeView控件来显示树形结构的数据。要控制节点&#xff08;树形结构中的项&#xff09;的展开和收缩&#xff0c;您可以使用QTreeView的一些方法来实现这些操作。 下面是一些常用的方法&#xff1a; 展开节点&#xff1a;使用expand方法展开一个…

一文彻底弄懂动态规划【DP】

动态规划是一种重要的算法&#xff0c;它能解决很多看似复杂的问题&#xff0c;关键在于找到问题的子问题结构&#xff0c;并根据子问题的解决方式来解决原问题。首先要了解的是动态规划的基本思想&#xff1a; 动态规划的基本思想是&#xff1a;将一个复杂的问题分解为一系列…

深层神经网络(第四周)

这里省略了深层神经网络的前向传播和反向传播&#xff0c;内容和之前相似&#xff0c;不做过多描述。若今后需要&#xff0c;可以再补习。 一、为什么使用深层表示 解决问题时其实并不需要很大的神经网络&#xff0c;但是得有深度&#xff0c;得有比较多的隐藏层。这是为什么…