字符串差异比较算法分析

作者: dugangabc | 来源:发表于2016-02-03 20:04 被阅读2660次

字符串差异比较算法通常应用于比较同一个文件的不同版本,或者两篇雷同的文章的相同部分。下面将问题描述如下:

给定两个字符串a,b。编写程序将a与b相同的部分用空格替代,不同的部分保留。

举例说明:设a=“一辈子只做一件事”,b=“生来只做一件事”。经过处理后,字符串a变为“一辈子 ”,字符串b变为“生来 ”。

经过如上处理后,我们仅需要将不为空格部分的高亮就可以对两个文本的不同一目了然了。

上面的问题,比较直接的思路是将两个字符串拆分为字符的集合,求两个字符集合的交集。然后将在交集中的字符替换为空格。但并不能完美解决问题。比如,字符串a中“一”出现了两次,而b中出现了一次。程序会误将a中的两个“一”都当做相同部分。从而得到a=“ 辈子 ”。

产生上面问题的原因是单个字太容易在字符串中重复了,这就让我们考虑把字符串分解为长度为2的子串。比如a分解为:一辈,辈子,子只,只做,做一,一件,件事。而b分解为:生来,来只,只做,做一,一件,件事。可以看出,两个字符串都有只做,做一,一件,件事。去掉相同部分后可以得到正确的结果。

然而,当文章很长时,长度为二的子串也会产生重复。这就提示我们要从最长的子串开始来找重复项。

解决思路:假设a、b中较短的字符串为a,假设其长度为$l_a$,则:

  1. l=$l_a$
  2. 穷举字符串长度为l的子串,针对每个子串看字符串b是否包含该子串
  3. 若包含则将a,b相应部分设置为空格。a中空格区域左边若不为空串,则与b进行进一步递归比较。同理,a中空格区域右边若不为空串,则与b进行进一步递归比较。(分为左右递归是为了穷举a的子串时避开已经设置为空串的部分),直接返回结果。
  4. 2步骤中的所有子串b都不包含,则l=l/2

注意:当a与b比较相似时,该算法的效率较高。由于l从最大可能的子串开始穷举,其可以很快将大量相同部分设置为空格,从而减少后续穷举子串的计算量。若a与b几乎完全不同,则穷举加比较的复杂度就会正比于a的字符数*b的字符数

算法的关键部分如下(java语言描述),算法的入口是第一个getDiff方法。


    
    //获取两个字符串的差异,将相同部分设置为空格,返回的字符串数组为处理后的结果
    public String[] getDiff(String a, String b) {
        String[] result = null;
        //选取长度较小的字符串用来穷举子串
        if (a.length() < b.length()) {
            result = getDiff(a, b, 0, a.length());
        } else {
            result = getDiff(b, a, 0, b.length());
            result = new String[]{result[1],result[0]};
        }
        return result;
    }
    
    //将a的指定部分与b进行比较生成比对结果
    private String[] getDiff(String a, String b, int start, int end){
        String[] result = new String[]{a, b};
        int len = result[0].length();
        while (len > 0) {
            for (int i = start; i < end - len + 1; i++) {
                String sub = result[0].substring(i, i + len);
                int idx = -1;
                if ((idx = result[1].indexOf(sub)) != -1) {
                    System.out.println(sub);
                    result[0] = setEmpty(result[0], i, i + len);
                    result[1] = setEmpty(result[1], idx, idx + len);
                    if (i > 0) {
                        //递归获取空白区域左边差异
                        result = getDiff(result[0], result[1], 0, i);
                    }
                    if (i + len < end) {
                        //递归获取空白区域右边差异
                        result = getDiff(result[0], result[1], i + len, end);
                    }
                    len=0;//退出while循环
                    break;
                }
            }
            len = len / 2;
        }
        return result;
    }

    //将字符串s指定的区域设置成空格
    public String setEmpty(String s, int start, int end) {
        char[] array = s.toCharArray();
        for (int i = start; i < end; i++) {
            array[i] = ' ';
        }
        return new String(array);
    }

相关文章

  • 字符串差异比较算法分析

    字符串差异比较算法通常应用于比较同一个文件的不同版本,或者两篇雷同的文章的相同部分。下面将问题描述如下: 给定两个...

  • 机器学习中的计时和性能

    问题描述 在机器学习中当我们比较集中算法之间的性能差异时,我们需要比较算法执行的时间,从而分析出算法的优劣,今天就...

  • kmp算法--字符串比较

    常规的比较算法(朴素比较算法) 因为朴素算法效率低采用,KMP比较算法比如说字符串,T=“abcdex”j ...

  • 算法(2)KMP算法

    1.0 问题描述 实现KMP算法查找字符串。 2.0 问题分析 “KMP算法”是对字符串查找“简单算法”的优化。 ...

  • 数据结构与算法-字符串

    字符串又被成为串 字符串的存储结构 字符串的比较 朴素的模式匹配算法 BF算法

  • 字符串匹配算法

    场景:字符串A为主串,字符串B为模式串,比较字符串B是否能够在字符串A中进行匹配? 匹配算法:BF算法和RK算法。...

  • 转录组差异分析流程三大R包比较

    总目录: 数据预处理 limma包进行差异分析 edgeR包进行差异分析 DESeq2包进行差异分析 三大R包比较...

  • 【GEO数据库挖掘】四、差异分析(limma)、绘图和富集分析

    参考代码在这: 1 差异分析 需要的数据:表达矩阵、分组矩阵、差异比较矩阵 至此获得了差异分析矩阵nrDEG 2 ...

  • 2020 蓝桥杯大学 B 组模拟赛(五)

    1、数字操作 答案:996 算法分析 直接模拟 Java 代码 2、字符串操作 算法分析 说白了就是贪心的思想,尽...

  • 第2章 字符串和日期

    1、字符串中A的数量 算法分析 直接模拟 时间复杂度 Java 代码 2、最长的名字 算法分析 直接模拟 时间复杂...

网友评论

    本文标题:字符串差异比较算法分析

    本文链接:https://www.haomeiwen.com/subject/algskttx.html