字符串差異比較算法分析

字符串差異比較算法通常應(yīng)用于比較同一個(gè)文件的不同版本,或者兩篇雷同的文章的相同部分。下面將問題描述如下:

給定兩個(gè)字符串a(chǎn),b。編寫程序?qū)與b相同的部分用空格替代,不同的部分保留。

舉例說明:設(shè)a=“一輩子只做一件事”,b=“生來只做一件事”。經(jīng)過處理后,字符串a(chǎn)變?yōu)椤耙惠呑? ”,字符串b變?yōu)椤吧鷣? ”。

經(jīng)過如上處理后,我們僅需要將不為空格部分的高亮就可以對(duì)兩個(gè)文本的不同一目了然了。

上面的問題,比較直接的思路是將兩個(gè)字符串拆分為字符的集合,求兩個(gè)字符集合的交集。然后將在交集中的字符替換為空格。但并不能完美解決問題。比如,字符串a(chǎn)中“一”出現(xiàn)了兩次,而b中出現(xiàn)了一次。程序會(huì)誤將a中的兩個(gè)“一”都當(dāng)做相同部分。從而得到a=“ 輩子 ”。

產(chǎn)生上面問題的原因是單個(gè)字太容易在字符串中重復(fù)了,這就讓我們考慮把字符串分解為長度為2的子串。比如a分解為:一輩,輩子,子只,只做,做一,一件,件事。而b分解為:生來,來只,只做,做一,一件,件事。可以看出,兩個(gè)字符串都有只做,做一,一件,件事。去掉相同部分后可以得到正確的結(jié)果。

然而,當(dāng)文章很長時(shí),長度為二的子串也會(huì)產(chǎn)生重復(fù)。這就提示我們要從最長的子串開始來找重復(fù)項(xiàng)。

解決思路:假設(shè)a、b中較短的字符串為a,假設(shè)其長度為$l_a$,則:

  1. l=$l_a$
  2. 窮舉字符串長度為l的子串,針對(duì)每個(gè)子串看字符串b是否包含該子串
  3. 若包含則將a,b相應(yīng)部分設(shè)置為空格。a中空格區(qū)域左邊若不為空串,則與b進(jìn)行進(jìn)一步遞歸比較。同理,a中空格區(qū)域右邊若不為空串,則與b進(jìn)行進(jìn)一步遞歸比較。(分為左右遞歸是為了窮舉a的子串時(shí)避開已經(jīng)設(shè)置為空串的部分),直接返回結(jié)果。
  4. 2步驟中的所有子串b都不包含,則l=l/2

注意:當(dāng)a與b比較相似時(shí),該算法的效率較高。由于l從最大可能的子串開始窮舉,其可以很快將大量相同部分設(shè)置為空格,從而減少后續(xù)窮舉子串的計(jì)算量。若a與b幾乎完全不同,則窮舉加比較的復(fù)雜度就會(huì)正比于a的字符數(shù)*b的字符數(shù)

算法的關(guān)鍵部分如下(java語言描述),算法的入口是第一個(gè)getDiff方法。


    
    //獲取兩個(gè)字符串的差異,將相同部分設(shè)置為空格,返回的字符串?dāng)?shù)組為處理后的結(jié)果
    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進(jìn)行比較生成比對(duì)結(jié)果
    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) {
                        //遞歸獲取空白區(qū)域左邊差異
                        result = getDiff(result[0], result[1], 0, i);
                    }
                    if (i + len < end) {
                        //遞歸獲取空白區(qū)域右邊差異
                        result = getDiff(result[0], result[1], i + len, end);
                    }
                    len=0;//退出while循環(huán)
                    break;
                }
            }
            len = len / 2;
        }
        return result;
    }

    //將字符串s指定的區(qū)域設(shè)置成空格
    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);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,477評(píng)論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,960評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,200評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,617評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,807評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,049評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評(píng)論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,432評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,769評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容