diff算法学习-cnblog

diff算法学习

diff在linux、git中都可以经常被看到,用来对比文件差异,特别是用过git的同学,对此肯定深有体会,那他究竟是如何做到的呢?

这里有一张github上面的图:

image-20260821105144982

红色部分是删除部分,绿色部分是增加部分,剩下没有标记的则是没有改变部分。

在设计这个diff算法时,我们尽量遵循下面约定(从上到下优先级递增):

  1. 每个操作部分总是尽可能成块;
  2. 删除操作在增加操作之前;
  3. 整个操作尽可能少;

下面我们主要学习Myers Diff算法。

这还和算法比赛中的最短编辑距离不同,本质都是使用动态规划,但是Myers Diff算法使用了一定的启发式操作,用来平衡检查差异程度和生成速度。

Git Diff 算法详解:Myers Diff Algorithm-腾讯云开发者社区-腾讯云

场景 推荐算法 原因
Git diff、文件对比 Myers 文件通常差异小,速度快
DNA 序列比对 Myers 或 专业算法 序列长,差异可能大
拼写检查(短词) 经典 DP 实现简单,长度短
文本编辑器 diff Myers 交互式需要实时响应
计算最短距离值 DP 或 Myers 两者都能,看需求

所以对于长序列,我们还是不能使用传统的DP算法来写,但是对于长度较短和快速开发时,我们可以选择使用DP。

最经典的就是Leetcode上的编辑距离那道题,就是使用的动态规划。

DP Myers
最好情况 O(N×M) O(D²)
最坏情况 O(N×M) O(N×M)
空间 通常 O(min(N,M)) O(N+M)
输出 需要额外处理 天然输出
适用 短序列、小规模 长序列、版本控制

72. 编辑距离 - 力扣(LeetCode)

题目描述:

给定两个字符串\(a\)\(b\),我们要用最少的字符操作次数,将字符串\(a\)转换为字符串\(b\)。这里所说的字符操作共有三种:

  • 删除一个字符;
  • 增加一个字符;
  • 将一个字符替换成另一个字符;

其实默认还有一种操作就是保持不变。

因为字符串的长度都小于等于500,所以我们有很大的操作空间。

状态定义:\(dp[i][j]\)表示考虑到\(a\)的前\(i\)个字符,\(b\)的前\(j\)个字符时,通过三种操作使得他们相同的最小操作次数;

转移方程:我们先考虑当前\(dp[i][j]\),他可以由什么转移过来呢?如果是删除一个字符\(a\)的最后一个字符,那么就是\(dp[i][j]=dp[i-1][j]+1\),也就是\(a[1\dots i-1]=b[1\dots j]\),那么此时对于\(a[i]\)就是多余的,我们把它删了;如果是增加一个字符,那么就是\(dp[i][j]=dp[i][j-1]+1\),也就是\(a[1\dots i]=b[1\dots j-1]\),现在增加一个\(b[j]\)在末尾;如果是替换,那么简单,\(dp[i][j]=dp[i-1][j-1]+1\),也即将\(a[i]\)替换成\(b[j]\)即可,但是如果\(a[i]=b[j]\),那么这个替换操作就是不用的。

综上:\(dp[i][j]=\min{(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+[a[i]\ne b[j]])}\)

初始化:\(dp[i][0]=i,dp[0][j]=j\)

class Solution {
public:
    int minDistance(string word1, string word2) {
        auto& a=word1,&b=word2;
        int n=a.size(),m=b.size();
        a=" "+a;
        b=" "+b;
        vector<vector<int>> dp(n+1,vector<int>(m+1,0));
        for(int i=1;i<=n;i++) dp[i][0]=i;
        for(int j=1;j<=m;j++) dp[0][j]=j;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                dp[i][j]=min({dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+(a[i]!=b[j])});
            }
        }
        return dp[n][m];
    }
};

其实处理一般的最短距离,我们只需要按照这样去实现就好。剩下的Meyer Diff算法我只是看了一下,还没有具体去自己写代码,等后面补一下。

大致原理是这样的:

常见的diff算法都是按照行为最小单位去处理的,我们把每一行算一个哈希值,作为这一行的指纹,这样对于新旧文件,我们就得到了两个序列,之后便是使用算法来处理了,直接使用dp主要是复杂度比较高,是\(O(nm)\)的,相对来说不够优秀,后面的其他算法主要思想都差不多,主要是启发式的策略可能不同。

后面可以自己实现一下这个算法,看一下效果。

posted @ 2026-08-22 21:06  alij  阅读(4)  评论(0)    收藏  举报