計算兩個字串最大公有子串

min.jiang發表於2017-01-23

背景

對演算法一直應用的比較少,最近看到一些典型的演算法想練練手,想看看到底有多麼讓人討厭。其實發現演算法都有一定的套路,一般並不是臨時憑空想出來的,大都建立在一些已經存在的經典演算法知識以及資料結構上。換句話來說,如果某些玩法之前未接觸過,那麼讓你在短時間內臨時想出來還是有一定難度的。這有點類似專案經驗,如果曾經做過一個CRM系統,下次再碰到它時你就輕鬆很多,如果你挑戰的是一個你從未遇到過的系統,你只能憑已有知識去強吃。

計算兩個字串最大公共子串

這個也是經常遇到到,給出兩個任意長度的字串,輸出最大公有字串,比如輸入abcdef,cdef,則輸出cdef。

解決方案

採用雙層迴圈,指標移動來記錄所有子串,最後取最大長度子串。利用臨時佇列來儲存迴圈過程中匹配成功的字元元素,從兩個字串首個元素開始匹配。

  • 如果a.charAt(i)=b.charAt(j),標記開始匹配,同時移動兩者指標,並將相同字串壓入臨時佇列中
  • 如果a.charAt(i)!=b.charAt(j),只移動b的指標。如果處於匹配中,則將臨時佇列儲存到結果集中,並清空臨時佇列。
  • 如果a,b任意一個到了最後一個元素,將臨時佇列中的值儲存到結果集中,並清空臨時佇列

示意圖

從元素0開始比較

字串A指標不動,B依次向後找至少找到相同的,將相同字元壓入臨時佇列中。

出現第一個匹配元素

當出現匹配元素後,兩個字串均向後移動一個元素再做比較。

匹配出現中斷

如果前面已經開始匹配成功,向後出現字元不相同時,終止。

重置索引,迴圈匹配

字串B指標向後移動,字串A的指標重置,遞迴上面的步驟。

示例程式碼

下面的示例將所有子串均記錄下來,如果只想輸出最大子串需要改下邏輯,定義一個最大子串,然後與迴圈計算的子串相比較,取兩者長度最大值即可。

String b="abcdeqwe";
String a="cdeabrwqedeqwe";
int lengthA=a.length();
int lengthB=b.length();
//標識是否開始匹配
boolean match=false;
//迴圈中用於儲存相同字元的臨時佇列
Queue tmpResult=new ArrayQueue();
//儲存所有子串
List<Queue> result=new ArrayList<>();
for(int i=0;i<lengthA;i++){
    int indexA=i;
    for(int j=0;j<lengthB;j++){
        if(a.charAt(indexA)==b.charAt(j)){
            if(!match) {
                match = true;
            }
            tmpResult.add(a.charAt(indexA));
            if(indexA<lengthA-1) {
                indexA++;
            }
        }
        else {
            if(match) {
                result.add(tmpResult);
                //重置條件
                tmpResult=new ArrayQueue();
                indexA=i;

            }
        }
        if(j==lengthB-1||i==lengthA-1){
            if(!tmpResult.isEmpty()){
                result.add(tmpResult);
                //重置條件
                tmpResult=new ArrayQueue();
            }
        }
    }

}
//取最大的子串
Queue stringResult= Collections.max(result, new Ordering<Queue>() {
    @Override
    public int compare(Queue left, Queue right) {
        return Integer.compare(left.size(),right.size());
    }
});

優點

指標移動在迴圈過程中不會產生多餘的臨時字串,如果是substring方案就需要考慮效率了。

如有其它更好的方案請分享給我

相關文章