Java解決LCS(Longest Common Sequence/Set)問(wèn)題

問(wèn)題描述

LCS問(wèn)題可以分作最長(zhǎng)公共子序列問(wèn)題和最長(zhǎng)公共子集問(wèn)題参咙,其區(qū)別在于前者要求的是連續(xù)的屬于兩個(gè)字符串序列的子集,而后者則不要求連續(xù)硫眯。如:
字符串一:桃李漫山過(guò)眼空蕴侧。也宜惱損杜陵翁。若將玉骨冰姿比两入,李蔡為人在下中净宵。
字符串二:過(guò)眼滔滔云共霧,算人間知己吾和汝裹纳。人有病择葡,天知否?
一時(shí)書袋一時(shí)爽剃氧,一直吊一直爽敏储!

公共子集

image.png

公共子序列

image.png

問(wèn)題解析

公共子集

現(xiàn)有兩個(gè)字符串str_1,str_2,str_1.subString[0,m+1]和str.subString[0,n+1]代表這兩個(gè)字符串的前m項(xiàng)和前n項(xiàng)她我。LCS_1(String,String)方法返回兩個(gè)字符串的最長(zhǎng)公共子集虹曙。傳參中兩個(gè)字符串可以分立到兩個(gè)互補(bǔ)的場(chǎng)景中考慮即兩個(gè)字符串的尾項(xiàng)是否相等迫横。
尾項(xiàng)相等
由公共子集的特性可知番舆,相同的尾項(xiàng)一定會(huì)給最終的LCS結(jié)果作出+1的貢獻(xiàn),所以在這種情況下數(shù)學(xué)表達(dá)式為:
LCS_1(str_1.subString(0,m+1),str.subString(0,n+1))= LCS_1(str_1.subString(0,m),str.subString(0,n))+1
尾項(xiàng)不相等
尾項(xiàng)不相等時(shí)我們分別考慮兩個(gè)字符串除去尾項(xiàng)的情況矾踱。所以表達(dá)式為:
LCS_1(str_1.subString(0,m+1),str.subString(0,n+1))= max(LCS_1(str_1.subString(0,m+1),str.subString(0,n))恨狈,LCS_1(str_1.subString(0,m),str.subString(0,n+1)))
最后加入初始條件和邊界條件即構(gòu)成了此題的動(dòng)態(tài)規(guī)劃算法。

公共子序列

本題需要構(gòu)建兩個(gè)字符串在每個(gè)位置上的重合矩陣呛讲。如"12345"和"34567":
00100
00010
00001
00000
00000
此時(shí)矩陣只保存了位置重合與否信息禾怠,我們對(duì)其進(jìn)行優(yōu)化,當(dāng)str_2[m]str_2[n]為相同字符時(shí)贝搁,arr[m][n]的值為arr[m-1][n-1]+1吗氏。此時(shí)矩陣變?yōu)?
00100
00020
00003
00000
00000
現(xiàn)在矩陣中已經(jīng)包含有公共子串的長(zhǎng)度信息,于是我們維護(hù)一個(gè)整型保存當(dāng)前循環(huán)中的LCS長(zhǎng)度并維護(hù)一個(gè)Stack<Integer>(為了兼容同時(shí)存在多個(gè)LCS解的情況)以獲得該子串尾項(xiàng)在矩陣中的坐標(biāo)雷逆。到了這一步我們犧牲了O(nm)的空間復(fù)雜度換得了O(nm)的時(shí)間復(fù)雜度弦讽。但是仍有方法進(jìn)一步減少內(nèi)存空間的損耗。上述前提中我們已經(jīng)通過(guò)開辟整型和棧在當(dāng)前循環(huán)中保存了最長(zhǎng)長(zhǎng)度以及結(jié)果坐標(biāo),因此我們無(wú)需再維護(hù)一個(gè)完整而冗雜的矩陣往产,而只需要維護(hù)矩陣中當(dāng)前循環(huán)中使用的每一行(即單行)即可被碗。唯一需要注意的問(wèn)題是算法要求保存前一行中arr[m-1][n-1]的狀態(tài),因此我們通過(guò)逆序刷新的方式仿村,如此一來(lái)在循環(huán)到arr[m]時(shí)锐朴,arr[m-1]保存的正是上一個(gè)循環(huán)中的字符重合狀態(tài)。

不嚴(yán)謹(jǐn)代碼

import java.util.Scanner;
import java.util.Stack;
/**
 * 任意輸入兩個(gè)字符串蔼囊,求出這兩個(gè)字符串的公共子序列
 * */
public class LCS1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String x = sc.next();
        String y = sc.next();
        getLCS(x,y);
        sc.close();
    }
    
    public static void getLCS(String x, String y){
        
        char[] s1 = x.toCharArray();
        char[] s2 = y.toCharArray();
        int her = x.length();
        int ver = y.length();
        int[][] array = new int[her][ver];
        
        for(int m = 0; m < her; m++){//filling the LCS matrix using dynamic planning
            for(int n = 0; n < ver; n++){
                if(s1[m] == s2[n]){
                    if(m==0 || n==0) array[m][n] = 1;//default case
                    else array[m][n] = array[m-1][n-1] + 1;
                }else{
                    if(m==0 || n==0) array[m][n] = 0;//default case
                    else array[m][n] = max(array[m -1][n], array[m][n -1]);
                }
            }
        }
//      for(int m = 0; m < her; m++){//output the auxiliary matrix
//          for(int n = 0; n < ver; n++){
//              System.out.print(array[m][n]);
//          }
//          System.out.println();
//      }
        Stack<Character> stack = new Stack<>();
        int i = x.length() - 1;
        int j = y.length() - 1;
        
        while((i >= 0) && (j >= 0)){//push result into stack
            if(s1[i] == s2[j]){
                stack.push(s1[i]);
                i--;
                j--;
            }else{
                if(i==0) j--;
                else if(j==0) i--;
                else if(array[i][j-1] > array[i-1][j]){
                    j--;
                }
                else{
                    i--;
                }
            }
        }
        
        while(!stack.isEmpty()){
            System.out.print(stack.pop());
        }           
    }
    
    public static int max(int a, int b){
        return (a > b)? a : b;
    }
}
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;

public class LCS2 {
    public static List<String> findLongestCommonSet(String str1,String str2){
        char[] chArr1 = str1.toCharArray();
        int len1 = chArr1.length;
        char[] chArr2 = str2.toCharArray();
        int len2 = chArr2.length;
        Stack<Integer> indexes = new Stack<>();
        List<String> res = new ArrayList<String>();
        int maxLen = 0;
        int[] lenArr = new int[len1>len2?len1:len2];
        for(int i=0;i<len1;i++) {
            for(int j=len2-1;j>=0;j--) {//fill and flush the single array by reversed order
                if(chArr1[i]==chArr2[j]) {
                    if(i==0 || j==0) lenArr[j] = 1;//default case
                    else lenArr[j] = lenArr[j-1]+1;
                }
                else lenArr[j]=0;
                
                /*record every largest length
                 * with corresponding indexes of last char
                  */
                if(lenArr[j]>maxLen) {
                    indexes.clear();
                    maxLen = lenArr[j];
                    indexes.push(j);
                    
                }
                else if(lenArr[j]==maxLen) indexes.push(j);
            }
        }
        while(!indexes.isEmpty()) {
            int term = indexes.pop();
            res.add(str2.substring(term-maxLen+1,term+1));
        }
        System.out.println("Longest Common Sequence:"+maxLen);
        return res;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String x = sc.next();
        String y = sc.next();
        List<String> list = findLongestCommonSet(x, y);
        for (int i = 0; i < list.size(); i++) {
            System.out.println("第" + (i + 1) + "個(gè)公共子串:" + list.get(i));
        }

        sc.close();
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末焚志,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子压真,更是在濱河造成了極大的恐慌娩嚼,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滴肿,死亡現(xiàn)場(chǎng)離奇詭異岳悟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)泼差,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門贵少,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人堆缘,你說(shuō)我怎么就攤上這事滔灶。” “怎么了吼肥?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵录平,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我缀皱,道長(zhǎng)斗这,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任啤斗,我火速辦了婚禮表箭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钮莲。我一直安慰自己免钻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布崔拥。 她就那樣靜靜地躺著极舔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪链瓦。 梳的紋絲不亂的頭發(fā)上拆魏,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼稽揭。 笑死俺附,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溪掀。 我是一名探鬼主播事镣,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼揪胃!你這毒婦竟也來(lái)了璃哟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤喊递,失蹤者是張志新(化名)和其女友劉穎随闪,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骚勘,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铐伴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俏讹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片当宴。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖泽疆,靈堂內(nèi)的尸體忽然破棺而出户矢,到底是詐尸還是另有隱情,我是刑警寧澤殉疼,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布梯浪,位于F島的核電站,受9級(jí)特大地震影響瓢娜,放射性物質(zhì)發(fā)生泄漏挂洛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一恋腕、第九天 我趴在偏房一處隱蔽的房頂上張望抹锄。 院中可真熱鬧逆瑞,春花似錦荠藤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至念秧,卻和暖如春淤井,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工币狠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留游两,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓漩绵,卻偏偏與公主長(zhǎng)得像贱案,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子止吐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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

  • 前言 最先接觸編程的知識(shí)是在大學(xué)里面碍扔,大學(xué)里面學(xué)了一些基礎(chǔ)的知識(shí)瘩燥,c語(yǔ)言,java語(yǔ)言不同,單片機(jī)的匯編語(yǔ)言等厉膀;大學(xué)畢...
    oceanfive閱讀 3,087評(píng)論 0 7
  • 在C語(yǔ)言中,五種基本數(shù)據(jù)類型存儲(chǔ)空間長(zhǎng)度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來(lái)閱讀 3,345評(píng)論 0 2
  • 【程序1】 題目:古典問(wèn)題:有一對(duì)兔子,從出生后第3個(gè)月起每個(gè)月都生一對(duì)兔子二拐,小兔子長(zhǎng)到第三個(gè)月后每個(gè)月又生一對(duì)兔...
    開心的鑼鼓閱讀 3,320評(píng)論 0 9
  • 2019年1月25日 姓名 :曹靜杰 企業(yè)名稱 : 遼寧遼陽(yáng)叢迪服裝 組別 388期 反省1組 【日精進(jìn)打卡第25...
    eddd166e28ad閱讀 172評(píng)論 0 0
  • 睡到8點(diǎn)后站蝠,因?yàn)槟箍七@邊10點(diǎn)才天亮,我就在這玩了會(huì)兒手機(jī)和朋友發(fā)了發(fā)消息卓鹿。磨到中午后菱魔,伙伴們說(shuō)到飯點(diǎn)了,然后就...
    漂流的小瓶子閱讀 290評(píng)論 0 2