众所周知,很多社区都有内容审核机制。除了第一次发布,后续的修订也需要审核。当然,最残忍的办法就是从头再读一遍,但是小编肯定想弄死你。显然,这是相对低效的。比如你改了一个错字,可能看几遍就看不出来了,所以如果每次都能知道修改了什么,就像gitdiff那样,那就方便多了,而这个文章将简单地实现一个。寻找最长公共子序列要知道两个文本之间的区别,我们可以先找到它们的公共内容,其余的删除或添加。在算法中,这是一道经典题。有这道题1143.力口上的最长公共子序列。像推理题,可以用递归自上而下求解,也可以用for循环自下而上求解。使用for循环一般使用一个叫做dp的memo来存储信息。使用的维数组的具体数量取决于主题。这道题有两个变量(两个字符串的长度),所以我们用二维数组。我们定义dp[i][j]表示text1的子串从0-i和text2的子串从0-j的最长公共子序列的长度,然后我们需要考虑边界条件。首先,当i为0时,text1的子串为空串,所以不管j是什么,最长公共子序列的长度都是0,j为0。同样如此,所以我们可以初始化一个dp初值为0的数组:letlongestCommonSubsequence=function(text1,text2){letm=text1.lengthletn=text2.lengthletdp=newArray(m+1)dp.forEach((item,index)=>{dp[index]=newArray(n+1).fill(0)})}当i和j都不为0时,需要分几种情况看:1.当text1[i-1]===text2[j-1],表示这两个位置的字符相同,那么它们一定在最长的子序列中,而当前最长的子序列取决于前面的子串,即dp[i][j]=1+dp[i-1][j-1];2、当text1[i-1]!==text2[j-1]时,显然dp[i][j]完全取决于前面的情况,一共有三种:dp[i-1][j-1],dp[i][j-1],dp[i-1][j],但是可以排除第一种情况,因为显然没有后两种情况那么长,因为后两种情况有一个比第一种情况多了一个字符,所以长度可能多了1,那么我们取后两种情况下两种情况的最优值就够了;那么我们只需要一个双循环遍历二维数组的所有情况:letlongestCommonSubsequence=function(text1,text2){letm=text1.lengthletn=text2.length//初始化一个二维数组letdp=newArray(m+1).fill(0)dp.forEach((item,index)=>{dp[index]=newArray(n+1).fill(0)})for(leti=1;i<=m;i++){//由于i和j都是从1开始,所以我们需要减去1lett1=text1[i-1]for(letj=1;j<=n;j++){lett2=text2[j-1]//情况1if(t1===t2){dp[i][j]=1+dp[i-1][j-1]}else{//case2dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1])}}}dp[m][n]的值是最长公共子序列的长度,但是只知道长度是没有用的。我们需要知道具体的位置,我们需要再次递归。为什么我们不能在上面的循环中使用t1?===t2分支中的集合位置,因为两个字符串的所有位置都会两两比较,当有多个相同的字符时,会出现重复,如下:我们定义一个collect函数,递归判断i和j位置是否在最长子序列中,比如对于i和j位置,如果text1[i-1]===text2[j-1],那么显然这两个位置在最长子序列中,那么只要确定i-1和j-1的位置,以此类推。如果当前位置不一样,我们可以根据dp数组来判断,因为此时我们已经知道了整个dp数组的值:所以不需要每个位置都去尝试,不会造成重复,这样如dp[i-1]>dp[j],那么接下来要判断的是i-1和j的位置,否则判断i和j-1的位置的条件是i和j有一个位置已经达到0:letarr1=[]letarr2=[]letcollect=function(dp,text1,text2,i,j){if(i<=0||j<=0){return}if(text1[i-1]===text2[j-1]){//收集两个字符串中相同字符的索引arr1.push(i-1)arr2.push(j-1)returncollect(dp,text1,text2,i-1,j-1)}else{if(dp[i][j-1]>dp[i-1][j]){returncollect(dp,text1,text2,i,j-1)}else{returncollect(dp,text1,text2,i-1,j)}}}结果如下:可以看到倒序了,不喜欢也可以排序:arr1.sort((a,b)=>{返回a-b});arr2.sort((a,b)=>{返回a-b});到这里还没结束,我们还要根据最长的子序列来计算删除和添加的位置,这个比较简单,直接遍历两个字符串,不在arr1和arr2中的字符删除或添加:letgetDiffList=(text1,text2,arr1,arr2)=>{letdelList=[]letaddList=[]//遍历旧字符串for(leti=0;i
