【问题标题】:Can the memoization table used to find the longest common subsequence of two strings, also be used to find the indices of differences?用于查找两个字符串的最长公共子序列的记忆表是否也可以用于查找差异索引?
【发布时间】:2026-02-05 01:00:02
【问题描述】:

我正在编写一个 GitHub 浏览器扩展,它以另一种方式显示一些差异。 GitHub 只是显示预先计算的差异,所以我需要自己重新比较。

UNIX diff 实用程序基于查找Longest Common Subsequence。我找到了an implementation in javascript-algorithms。但是,这只显示 LCS 结果,而不是出现差异的索引。

以*为例,调用上述实现

longestCommonSubsequence('abcdfghjqz', 'abcdefgijkrxyz');

产生一个数组,

(8) ["a", "b", "c", "d", "f", "g", "j", "z"]

但我需要的是能让我弄清楚的东西:

abcd fgh j    z
abcdefg ijkrxyz
    +  -+ ++++

我不相信它像*文章中所说的那么简单......

从最长的公共子序列获得类似 diff 的输出只是一小步:如果一个项目在子序列中不存在但出现在第一个原始序列中,则它必须已被删除(如“-”所示标记,如下)。如果它在子序列中不存在但在第二个原始序列中存在,则它必须已插入(如“+”标记所示)。

...因为对于更复杂的字符串(即代码),会有重复的元素,需要大量回溯才能找出“真正的”差异从哪里开始和结束。

但我注意到 DP 实现留下了一个记忆表 lcsMatrix,对于 abcd... 示例留下了:

最后一行和最后一列可以用来准确地收集差异所在吗?

要生成上表并输出结果,只需添加

  console.table(lcsMatrix);
  console.log(longestSequence);

在链接实现结束时。

如果我弄明白了,我会发布一个自我回答。不过,到目前为止,我一直在躲避。

【问题讨论】:

    标签: javascript algorithm diff lcs


    【解决方案1】:

    看看下面...https://github.com/jonTrent/PatienceDiff

    以您的数据为例...

    diff = patienceDiff('abcdfghjqz'.split(''), 'abcdefgijkrxyz'.split(''));
    

    ...返回...

    {lines: Array(16), lineCountDeleted: 2, lineCountInserted: 6, lineCountMoved: 0}
    
    lineCountDeleted: 2
    lineCountInserted: 6
    lineCountMoved: 0
    lines: Array(16)
    0: {line: "a", aIndex: 0, bIndex: 0}
    1: {line: "b", aIndex: 1, bIndex: 1}
    2: {line: "c", aIndex: 2, bIndex: 2}
    3: {line: "d", aIndex: 3, bIndex: 3}
    4: {line: "e", aIndex: -1, bIndex: 4}
    5: {line: "f", aIndex: 4, bIndex: 5}
    6: {line: "g", aIndex: 5, bIndex: 6}
    7: {line: "h", aIndex: 6, bIndex: -1}
    8: {line: "i", aIndex: -1, bIndex: 7}
    9: {line: "j", aIndex: 7, bIndex: 8}
    10: {line: "q", aIndex: 8, bIndex: -1}
    11: {line: "k", aIndex: -1, bIndex: 9}
    12: {line: "r", aIndex: -1, bIndex: 10}
    13: {line: "x", aIndex: -1, bIndex: 11}
    14: {line: "y", aIndex: -1, bIndex: 12}
    15: {line: "z", aIndex: 9, bIndex: 13}
    length: 16
    

    请注意,结果是指“行”,因为该算法在构建时考虑了 github 风格的差异,即逐行比较。但是将样本数据字符串拆分为一个字符“行”的数组允许该算法也可以用于字符串......

    其中aIndex === -1 表示该字符是从第二个字符串中添加的,其中bIndex === -1 表示该字符是从第一个字符串中删除的。

    还包括一个名为 PatientDiffPlus 的版本,它可以识别可能行/字符的移动...(另请参阅 Find difference between two strings in JavaScript

    【讨论】:

      最近更新 更多