国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解

這篇具有很好參考價值的文章主要介紹了(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

遇到了用動態(tài)規(guī)劃來求解最長公共子序列問題,算法這塊兒比較薄弱,便想著在網(wǎng)上找現(xiàn)成的思路和代碼,也算拾人牙慧,但有一點沒想到,都已經(jīng)22年了,關于LCS問題網(wǎng)上給出的答案如此一言難盡……,只有零散幾篇對于新手來說比較友好,但也僅僅這樣,好在自己花了點時間,勉強領悟了一番,寫以成文,以便來時溫故。

動態(tài)規(guī)劃基本思想及要點

這塊兒是看吳師兄學算法(公眾號)文章摘錄的

基本思想

動態(tài)規(guī)劃算法與分治法類似,其基本思想就是將待求解問題分解成若干子問題,先求解子問題,然后從這些問題的解得到原問題的解。與分治法不同的是,適合動態(tài)規(guī)劃求解的問題,經(jīng)分解得到的子問題往往不是相互獨立的。

在用分治法求解時,有些子問題被重復結算了很多次,如果我們能夠保存已解決子問題的答案,在需要時找出已求得答案,這樣就可以避免大量重復計算,可以用一個表來記錄所有已解決子問題的答案,不管該子問題以后是否被用到,只要它被計算過,就將其結果填入表中,而這就是動態(tài)規(guī)劃的思想。

小結
  1. 將待求解問題分成若干子問題,先求子問題,然后從這些子問題的解得到原問題的解
  2. 經(jīng)分解得到的子問題往往不是相互獨立的
  3. 保存已解決子問題的答案,避免重復計算

要點

如何判定一個問題是否可以用動態(tài)規(guī)劃來解決,就需要掌握動態(tài)規(guī)劃的兩個基本要素,最優(yōu)子結構性質和重疊子問題性質

最優(yōu)子結構性質

當問題的最優(yōu)解包含了其子問題的最優(yōu)解時,稱該問題具有最優(yōu)子結構性質。問題的最優(yōu)子結構性質提供了該問題可用動態(tài)規(guī)劃求解的重要線索。

例如,最短路徑問題有如下最優(yōu)子結構:

(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解

結點x是從源結點u到目標結點v的最短路徑上的節(jié)點,則源結點u到目標結點v的最短路徑7就等于從源結點u到結點x的最短路徑5加上從結點x到目標結點v的最短路徑2的和。源結點u到目標結點v的最短路徑就是要求解的最優(yōu)解,源結點u到結點x的最短路徑和從結點x到目標結點v的最短路徑均為子問題的最優(yōu)解,而問題的最優(yōu)解包含了其子問題的最優(yōu)解,則該問題具有最優(yōu)子結構性質。

但最長路徑問題就不具有最優(yōu)子結構性質,注意這里的最長路徑指的是從兩個結點間的最長簡單路徑(即不存在環(huán)的路徑)

從結點u到結點v有兩條最長,分別為u——> s ——> v和u ——> t ——> v,但與最短路徑問題不同,這些最長路徑不具有最優(yōu)子結構性質,比如,從結點u到結點v有兩條最長路徑u ——> s ——> v并不等于從u到s的最長路徑u ——> t ——> v ——> s與從s到v的最長路徑s ——> u ——> t ——> v的加和。

重疊子問題性質

簡單講就是子問題的解會被重復調用

LCS問題分析

字串與子序列

有圖有真相

一個長度為n的序列,其子序列個數(shù)為2n-1,所以解決LCS問題最好不使用暴力搜索方法

分解

最長公共子序列問題分解成子問題根據(jù)已造輪子可知,設A=“a0、a1、……、am-1”,B=“b0、b1、……、bn-1”,Z=“z0、z1、……、zk-1”為它們最長公共子序列,不難證明有如下性質:

1). 如果am-1 = bn-1,則zk-1 = am-1=bn-1,簡單講就是A和B最后一個字符相等,那么這個字符肯定為最長公共子序列中的最后一個字符,于是就有“z0、z1、……、zk-2”是“a0、a1、……、am-2”和“b0、b1、……、bn-2”的一個最長公共子序列

2). 如果am-1!=bn-1,則若zk-1!=am-1,那么“z0、z1、……、zk-1”是“a0、a1、……、am-2”和“b0、b1、……、bn-1”的一個最長公共子序列

3). 如果am-1!=bn-1,則若zk-1!=bn-1,那么“z0、z1、……、zk-1”是“a0、a1、……、am-1”和“b0、b1、……、bn-2”的一個最長公共子序列

由此可以獲得遞推公式

(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解

dp數(shù)組推導(圖解)

dp數(shù)組用于記錄LCS長度,下面根據(jù)遞歸公式一行行進行推導

(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
簡單演示下填表過程



(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解



(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
通過遞推公式進行LCS長度推導這個過程,可以知道dp[i][j]是從三個方向推出的,分別是左上,向左,向上

構造LCS(回溯)

得到dp數(shù)組后,為了得到LCS需要從dp[7][6]倒推出兩序列共同元素,倒退有三種方向回溯

第一種結果
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
第二種結果
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
第三種結果
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
也就是有

(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解
回溯方向以向左回溯為先

(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解

代碼實現(xiàn)

下面的代碼為dp數(shù)組及回溯方向的實現(xiàn)(向左回溯為主)

package operation.dp;

public class LCSLD {
    public static void LCS(int[][] dir, int [][] dp,String s1,String s2){
        for(int i = 1;i <= s1.length();i++){
            char c1 = s1.charAt(i - 1);
            for(int j = 1;j <= s2.length();j++){
                char c2 = s2.charAt(j - 1);
                //開始列出狀態(tài)方程
                if (c1 == c2){
                    dp[i][j] = dp[i-1][j-1]+1;
                    dir[i][j] = 1; //來源左上方
                }else{
                    if (dp[i][j-1] >= dp[i-1][j]){
                        dp[i][j] = dp[i][j-1];
                        dir[i][j] = 2; //來源左方
                    }
                    else{
                        dp[i][j] = dp[i-1][j];
                        dir[i][j] = 3; //來源上方
                    }
                }
            }
        }
    }

    public static void LCSD(int [][] dir, int i, int j, String s1){
        if(i== 0 || j == 0) {
            return;
        }
        if(dir[i][j] == 1){
            LCSD(dir,i - 1,j - 1,s1);
            System.out.print(s1.charAt(i - 1));
        }else{
            if (dir[i][j] == 2)
                LCSD(dir,i,j - 1,s1);
            else
                LCSD(dir,i - 1,j,s1);
        }
    }
}

下面的代碼為dp數(shù)組及回溯方向的實現(xiàn)(向上回溯為主)

package operation.dp;

public class LCSFD {
    public static void LCS(int[][] dir,int [][] dp,String s1,String s2){
        for(int i = 1;i <= s1.length();i++){
            char c1 = s1.charAt(i - 1);
            for(int j = 1;j <= s2.length();j++){
                char c2 = s2.charAt(j - 1);
                if (c1 == c2){
                    dp[i][j] = dp[i-1][j-1]+1;
                    dir[i][j] = 1; //來源左上方
                }else{
                    if(dp[i-1][j] >= dp[i][j-1]){
                        dp[i][j] = dp[i-1][j];
                        dir[i][j] = 2; //來源上方
                    }else{
                        dp[i][j] = dp[i][j-1];
                        dir[i][j] = 3; //來源左方
                    }
                }
            }
        }
    }
    public static void LCSD(int [][] dir,int i,int j,String s1){
        if(i == 0 || j ==0){
            return;
        }
        if(dir[i][j] == 1){
            LCSD(dir,i - 1,j - 1,s1);
            System.out.print(s1.charAt(i - 1));
        }else{
            if(dir[i][j] == 2)
                LCSD(dir,i - 1,j,s1);
            else
                LCSD(dir,i,j - 1,s1);
        }
    }
}

下面的代碼為主程序代碼

package operation.dp;

public class MainApp {
    public static void main(String[] args) {
        String s1 = "abcbdab";
        String s2 = "bdcaba";
        //先對dp數(shù)組做初始化操作
        //Java中數(shù)組靜態(tài)初始化在編譯時就已完成,而動態(tài)初始化在運行時才完成,
        //且動態(tài)初始化的初始值都為0
        int [][] dp = new int[s1.length()+1][s2.length()+1]; //i+1行j+1列
        int [][] dir = new int[s1.length()+1][s2.length()+1];

        int [][] dp1 = new int[s1.length()+1][s2.length()+1]; //i+1行j+1列
        int [][] dir1 = new int[s1.length()+1][s2.length()+1];
        //開始時間
        long stime = System.currentTimeMillis();
        //以向左回溯為先
        LCSLD.LCS(dir,dp,s1,s2);
        System.out.println("dp數(shù)組如下:");
        for(int i = 0;i <= s1.length();i++){
            for(int j = 0;j <= s2.length();j++){
                System.out.printf("%5d",dp[i][j]);
            }
            System.out.println();
        }
        System.out.println("回溯數(shù)組如下:");
        for(int i = 0;i <= s1.length();i++){
            for(int j = 0;j <= s2.length();j++){
                System.out.printf("%5d",dir[i][j]);
            }
            System.out.println();
        }
        System.out.print("最長公共子序列為:");
        LCSLD.LCSD(dir,s1.length(),s2.length(),s1);
        System.out.println();
        //以向上回溯為先
        LCSFD.LCS(dir1,dp1,s1,s2);
        System.out.println("回溯數(shù)組如下:");
        for(int i = 0;i <= s1.length();i++){
            for(int j = 0;j <= s2.length();j++){
                System.out.printf("%5d",dir1[i][j]);
            }
            System.out.println();
        }
        System.out.print("最長公共子序列為:");
        LCSFD.LCSD(dir1,s1.length(),s2.length(),s1);
        System.out.println();
        //結束時間
        long etime = System.currentTimeMillis();
        System.out.printf("執(zhí)行時長: %d 毫秒",(etime - stime));
    }
}

主程序運行結果如下
(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解

待解決問題

經(jīng)過上述努力,發(fā)現(xiàn)LCS回溯的方向可以說是一根筋兒,這樣就導致結果不全,以上述例子來說,LCS總共有三個,結果只能輸出兩個,暫時只能到這兒了,以后看看有沒有機會實現(xiàn)

參考

主要是看了四篇文章有所啟迪,一篇CSDN上的、一篇博客園上的、一篇公眾號上的、一篇個人博客上的

小結

好的算法講解真的很重要,可以事半功倍,就目前接觸而言,代碼隨想錄的算法講解很不錯(對新手友好且免費),其他成體系成專欄的講解(暫時沒有發(fā)現(xiàn),可能都在自己的一畝三分地下)希望多多涌現(xiàn),這樣后來者學習算法就可以站在前人肩上前行了,也許時代造就了現(xiàn)在的社會氛圍較為著急,很難靜下心來公益的分享知識,所以不能一味歸咎于個人(機構)老是搞錢,等中國的科技素養(yǎng)追趕上了中國的科技水平,那時候也許環(huán)境不會這么苛責,現(xiàn)在如果每個人認真發(fā)一份光,其實也可以燎原,不需要等待那天到來,說通透點就是,我花個一天時間把這個問題弄通透,然后分享出來,你花一天時間把那個問題弄通透分享出來,那么對于第三方來說在這兩個問題就可以少走較小彎路了,當然,這說的也可能扯淡,不好把握全局,不好定性脈絡,認知差信息差總是提醒著我,多走幾步,再回頭觀望那時的想法是否正確文章來源地址http://www.zghlxwxcb.cn/news/detail-400011.html

到了這里,關于(Java) 算法——動態(tài)規(guī)劃 最長公共子序列 圖解的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【算法(四·三):動態(tài)規(guī)劃思想——最長公共子序列問題】

    【算法(四·三):動態(tài)規(guī)劃思想——最長公共子序列問題】

    最長公共子序列(Longest Common Subsequence,簡稱LCS)問題是一種常見的字符串處理問題。它的**目標是找到兩個或多個字符串中的最長公共子序列,這個子序列不需要是連續(xù)的,但字符在原始字符串中的相對順序必須保持一致。**例如,考慮兩個字符串\\\"ABCD\\\"和\\\"ACDF\\\",它們的最長公

    2024年04月13日
    瀏覽(19)
  • 【算法】力扣【動態(tài)規(guī)劃,LCS】1143. 最長公共子序列

    1143. 最長公共子序列 本文是對 LCS 這一 動態(tài)規(guī)劃 模型的整理,以力扣平臺上的算法題1143:最長公共子序列為模板題進行解析。 該題目要求計算兩個字符串的最長公共子序列(Longest Common Subsequence,簡稱LCS)的長度。字符串的子序列是指在不改變字符順序的情況下,通過刪去

    2024年01月17日
    瀏覽(27)
  • python數(shù)據(jù)結構與算法-動態(tài)規(guī)劃(最長公共子序列)

    python數(shù)據(jù)結構與算法-動態(tài)規(guī)劃(最長公共子序列)

    一個序列的子序列是在該序列中刪去若干元素后得 到的序列。 例如:\\\"ABCD”和“BDF”都是“ABCDEFG”的子序列。 最長公共子序列(LCS) 問題: 給定兩個序列X和Y,求X和Y長度最大的公共子字列。 例:X=\\\"ABBCBDE”Y=\\\"DBBCDB”LCS(XY)=\\\"BBCD\\\" 應用場景:字符串相似度比對 (1)問題思考 思考: 暴

    2024年02月08日
    瀏覽(28)
  • 算法分析:C語言實現(xiàn)動態(tài)規(guī)劃之最長公共子序列

    算法分析:C語言實現(xiàn)動態(tài)規(guī)劃之最長公共子序列

    最長公共子序列問題: ??????? ?下面的簡單問題說明了動態(tài)規(guī)劃的基本原理。在字母表一∑上,分別給出兩個長度為n和m的字符串A和B,確定在A和B中最長公共子序列的長度。這里,A = a?a?...an。的子序列是一個形式為a?ka?k...aik的字符串,其中每個i都在1和n之間,并且

    2023年04月21日
    瀏覽(27)
  • 算法套路十五——動態(tài)規(guī)劃求解最長公共子序列LCS

    算法套路十五——動態(tài)規(guī)劃求解最長公共子序列LCS

    給定兩個字符串 text1 和 text2,返回這兩個字符串的最長 公共子序列 的長度。如果不存在 公共子序列 ,返回 0 。 一個字符串的 子序列 是指這樣一個新的字符串:它是由原字符串在不改變字符的相對順序的情況下刪除某些字符(也可以不刪除任何字符)后組成的新字符串。

    2024年02月04日
    瀏覽(23)
  • 算法分析 | 動態(tài)規(guī)劃算法設計之最長公共子序列 C語言版

    算法分析 | 動態(tài)規(guī)劃算法設計之最長公共子序列 C語言版

    聲明:凡代碼問題,歡迎在評論區(qū)溝通。承蒙指正,一起成長! 目錄 一、實驗內容與要求 ?二、概要設計 三、直接上代碼???? ?四、輸入數(shù)據(jù)及運行結果 ? 內容:最長公共子序列 ·若給定序列X={x1,x2,…,xm},則另一序列Z={z1,z2,…,zk},是X的子序列是指存在一個嚴格遞增下標序

    2024年02月02日
    瀏覽(27)
  • leetcode1143. 最長公共子序列-動態(tài)規(guī)劃(java)

    leetcode1143. 最長公共子序列 來源:力扣(LeetCode) 鏈接:https://leetcode.cn/problems/longest-common-subsequence 給定兩個字符串 text1 和 text2,返回這兩個字符串的最長 公共子序列 的長度。如果不存在 公共子序列 ,返回 0 。 一個字符串的 子序列 是指這樣一個新的字符串: 它是由原字

    2024年01月19日
    瀏覽(27)
  • 9.動態(tài)規(guī)劃——4.最長公共子序列(動態(tài)規(guī)劃類的算法題該如何解決?)

    9.動態(tài)規(guī)劃——4.最長公共子序列(動態(tài)規(guī)劃類的算法題該如何解決?)

    設最長公共子序列 d p [ i ] [ j ] dp[i][j] d p [ i ] [ j ] 是 S 1 S_1 S 1 ? 的前 i i i 個元素,是 S 2 S_2 S 2 ? 的前 j j j 個元素,那么有: 若 S 1 [ i ? 1 ] = = S 2 [ i ? 1 ] S_1[i-1]==S_2[i-1] S 1 ? [ i ? 1 ] == S 2 ? [ i ? 1 ] ,那么 d p [ i ] [ j ] = d p [ i ? 1 ] [ j ? 1 ] + 1 dp[i][j]=dp[i-1][j-1]+1 d p [

    2024年04月11日
    瀏覽(23)
  • 算法 DAY52 動態(tài)規(guī)劃10 1143.最長公共子序列 1035.不相交的線 53. 最大子數(shù)組和

    本題和動態(tài)規(guī)劃:718. 最長重復子數(shù)組 (opens new window)區(qū)別在于這里不要求是連續(xù)的了 1、dp數(shù)組 dp[i][j]:長度為[0, i - 1]的字符串text1與長度為[0, j - 1]的字符串text2的最長公共子序列為dp[i][j] 2、遞推公式 因為不強調是連續(xù)的,當前dp[i][j] 就有三種路徑可以選:dp[i-1][j] dp[i][j-1]

    2024年02月03日
    瀏覽(34)
  • 動態(tài)規(guī)劃--最長公共子序列

    動態(tài)規(guī)劃--最長公共子序列

    動態(tài)規(guī)劃算法與分治法類似,其基本思想也是將待求解問題分解成若干個子問題﹐ 即將大規(guī)模變成小規(guī)模 ,先求解子問題,然后從這些子問題的解得到原問題的解。與分治法不同的是﹐適合于用動態(tài)規(guī)劃法求解的問題,經(jīng)分解得到的子問題往往不是互相獨立的。 他們之間有關系

    2024年02月04日
    瀏覽(31)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包