字符串差异比较算法分析

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

给定两个字符串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);
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容