動態(tài)規(guī)劃(Dynamic Programming)

題目描述

我們有兩個字符串m和n蜕着,如果它們的子串a(chǎn)和b內(nèi)容相同躺枕,則稱a和b是m和n的公共子序列家制。子串中的字符不一定在原字符串中連續(xù)暂雹。
例如字符串“abcfbc”和“abfcab”,其中“abc”同時出現(xiàn)在兩個字符串中脓魏,因此“abc”是它們的公共子序列兰吟。此外,“ab”茂翔、“af”等都是它們的字串混蔼。
現(xiàn)在給你兩個任意字符串(不包含空格),請幫忙計算它們的最長公共子序列的長度珊燎。

輸入描述:

輸入包含多組數(shù)據(jù)惭嚣。

每組數(shù)據(jù)包含兩個字符串m和n,它們僅包含字母悔政,并且長度不超過1024晚吞。

輸出描述:

對應(yīng)每組輸入,輸出最長公共子序列的長度卓箫。

實例

輸入

abcfbc abfcab

programming contest

abcd mnp

輸出

4

2

0

解題思路

這道題载矿,要想在本地測試通過自己的測試用例是不難的。但是要完全AC就要注意烹卒,作者就是因為踩了坑闷盔,所以才特地記錄,并稍微深入找了下踩坑原因旅急。先來說一下大致思路:

  • 第一點逢勾,動態(tài)規(guī)劃的老套路:畫表格找規(guī)律。至于具體怎么畫表格藐吮,作者也是半瓶水溺拱,這里不展開叫惊,不清楚的可以網(wǎng)上找資料氯材,已經(jīng)有比較多了,或者私信留言作者汤踏。
  • 第二點泥从,找邊界條件(或者說出口條件)句占。因為動態(tài)規(guī)劃往往是將大問題分成各個不獨立的子問題,也就是說這個子問題總要有一個是最小的那個子問題躯嫉,然后才去遞歸或者公式推導(dǎo)(這就需要上面的找規(guī)律結(jié)論)纱烘。一般來講,出口條件也基本上是一些邊界值祈餐,比如數(shù)組0,1
  • 第三點擂啥,選擇解題方法,主要有兩種方式:(1)遞歸帆阳;(2)矩陣標記值哺壶,推導(dǎo)的方式。

拿這道題舉例來說蜒谤,假設(shè)m,n分別為字符串1(str1)和字符串2(str2)的長度, 設(shè)(m,n)表示str1前m個字符和str2前n個字符的最長子序列.通過找規(guī)律山宾,發(fā)現(xiàn)要求(m,n),則先求解子問題。即這個問題轉(zhuǎn)換為:當兩個字符串長分別為m-1芭逝,n-1求得最長公共子序列塌碌,然后在各自添加一個字符,求解旬盯,即求解(m,n)台妆。這樣一來,問題被分成兩個子問題胖翰,也就是兩種情況接剩,str1新添加的字符與str2新添加的字符是否相等?

相等的情況

(m,n) = (m-1,n-1) + 1(這個1萨咳,表示在原有基礎(chǔ)上有多了一個相等字符懊缺,總數(shù)加1)

不相等的情況

通過規(guī)律發(fā)現(xiàn),如果各自新加入一個字符字之后不相等,那么此時取該空格處左邊鹃两、上邊兩處空格中的較大值(具體可以先去畫個表格研究下)遗座,即(m,n) = max( (m-1,n), (m,n-1) )

分析完之后是不是比較清晰了呢?下面簡要說一下兩種解決此問題的方法:遞歸俊扳、矩陣標記值(為了好記)

遞歸解題

自頂向下途蒋,比如讓你求(m,n),然后你要知道(m-1,n-1)(m-2,n-2)...這樣逐層遞歸馋记,知道上面說的跳出條件号坡,這個遞歸才結(jié)束,最后以調(diào)用棧的方式逐層返回值

矩陣標記值

自底向上梯醒。首先從邊界值開始然后填滿 dp(m,n)的矩陣宽堆,最后那個就是要求的值。

我的解題歷程

  • 首先茸习,作者習(xí)慣用遞歸來解畜隶,所以一上來就用遞歸走了一波,代碼如下:

import java.util.Scanner;

public class LCSS {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String str1 = sc.next();
            String str2 = sc.next();
            long start = System.currentTimeMillis();
            int m = str1.length();
            int n = str2.length();
            boolean flag = str1.charAt(0) == str2.charAt(0);
            System.out.println(num(str1,str2,m-1,n-1, flag));
            System.out.println(System.currentTimeMillis()-start);
        }
    }
    public static int num(String str1, String str2, int m, int n, boolean flag) {
        if (m < 1 || n < 1) {
            if (flag) {
                return 1;
            }
            else {
                return 0;
            }
        }
        if (str1.charAt(m) == str2.charAt(n)) {
            return num(str1, str2, m-1, n-1, flag) +1;
        } else {
            return Math.max(num(str1, str2, m-1, n, flag),num(str1, str2, m, n-1, flag));
        }
    }
}


但是后來一運行發(fā)現(xiàn)本地用例都ok逮光,但是并沒有AC代箭,因為超時!
后來采用后者涕刚,原因是遞歸的話嗡综,每次計算的結(jié)果并沒有保存下來,會反復(fù)計算(當然也可以通過其他方式優(yōu)化)杜漠,后來作者直接采用矩陣標記計算結(jié)果的方式极景,然后提交就AC了,直接上代碼:

import java.util.Scanner;

public class LCSS2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()) {
            String str1 = sc.next();
            String str2 = sc.next();
            System.out.println(length(str1.toCharArray(), str2.toCharArray()));
        }
    }
    private static int length(char[] str1, char[] str2) {
        int m = str1.length;
        int n = str2.length;
        int[][] dp = new int[m][n];
        for (int i = 0; i < m;i++) {
            for (int j = 0;j < n; j++) {
                if ( i < 1) {
                    if (str1[0] == str2[j] || str1[0] == str2[0]) {
                        dp[i][j] = 1;
                    } else {
                        dp[i][j] =0;
                    }
                } else if (j < 1) {
                    if (str1[i] == str2[j] || str2[0] == str1[0] || dp[i-1][0] == 1) {
                        dp[i][j] = 1;
                    } else {
                        dp[i][j] =0;
                    }
                } else {
                    if (str1[i] == str2[j]) {
                        dp[i][j] = dp[i-1][j-1] + 1;
                    } else {
                        dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                    }
                }
                
            }
        }
        return dp[m-1][n-1];
    }
}

踩坑總結(jié)

  • 時間復(fù)雜度

  • 邊界值

適當注意一下邊界值驾茴,有時候自己容易想當然的認為盼樟!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市锈至,隨后出現(xiàn)的幾起案子晨缴,更是在濱河造成了極大的恐慌,老刑警劉巖峡捡,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件击碗,死亡現(xiàn)場離奇詭異,居然都是意外死亡们拙,警方通過查閱死者的電腦和手機稍途,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砚婆,“玉大人械拍,你說我怎么就攤上這事。” “怎么了坷虑?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵甲馋,是天一觀的道長。 經(jīng)常有香客問我猖吴,道長摔刁,這世上最難降的妖魔是什么挥转? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任海蔽,我火速辦了婚禮,結(jié)果婚禮上绑谣,老公的妹妹穿的比我還像新娘党窜。我一直安慰自己,他們只是感情好借宵,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布幌衣。 她就那樣靜靜地躺著,像睡著了一般壤玫。 火紅的嫁衣襯著肌膚如雪豁护。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天欲间,我揣著相機與錄音楚里,去河邊找鬼。 笑死猎贴,一個胖子當著我的面吹牛班缎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播她渴,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼达址,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了趁耗?” 一聲冷哼從身側(cè)響起沉唠,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苛败,沒想到半個月后满葛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡著拭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年纱扭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儡遮。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡乳蛾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肃叶,我是刑警寧澤蹂随,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站因惭,受9級特大地震影響岳锁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蹦魔,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一激率、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧勿决,春花似錦乒躺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至咆繁,卻和暖如春讳推,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背玩般。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工银觅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人壤短。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓设拟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親久脯。 傳聞我的和親對象是個殘疾皇子纳胧,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

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

  • 動態(tài)規(guī)劃(programming在這里是規(guī)劃的意思)算法設(shè)計技術(shù)由二十世紀五十年代的美國卓越數(shù)學(xué)家理查德.貝爾曼發(fā)...
    alonwang閱讀 2,125評論 0 3
  • 算法思想貪心思想雙指針排序快速選擇堆排序桶排序荷蘭國旗問題二分查找搜索BFSDFSBacktracking分治動態(tài)...
    第六象限閱讀 3,057評論 0 0
  • 本想寫成議論文,或者抒情帘撰,或者散文跑慕,可每每總以記敘文收場。關(guān)鍵還是流水賬的形式摧找。 我覺得自己最大的缺點就是不夠自信...
    小蓮蓬兒閱讀 118評論 0 0
  • 想必所有家長現(xiàn)在培養(yǎng)孩子的目標都朝著馬云和馬化騰的方向靠攏核行,指望有朝一日自己的孩子也可以呼風(fēng)喚雨,成就一個商業(yè)帝國...
    唐風(fēng)客閱讀 324評論 0 4
  • 夏天來了,很多小朋友都會寫一些和夏天相關(guān)的作文综苔,或者演講稿惩系。如何能讓你的作文和演講稿更有文采呢位岔?學(xué)習(xí)一下下面的這些...
    追夢小劇團閱讀 1,144評論 0 2