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

最長公共子序列(詳細代碼 注釋 分析 以及求出最長公共子序列內(nèi)容方法)

這篇具有很好參考價值的文章主要介紹了最長公共子序列(詳細代碼 注釋 分析 以及求出最長公共子序列內(nèi)容方法)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

最長公共子序列

文章有些長,希望能夠耐心看完,并且對你有幫助,文章是自己看了書之后,總結(jié)的,如果有什么錯誤的地方,歡迎指出。

一些基本的概念:

子序列: 原序列中刪除若干個元素得到的序列,即原序列中可以不連續(xù)的一段

子串: 原序列中任意個連續(xù)的序列元素組成的序列,即原序列中必須連續(xù)的一段。

(兩者的元素順序必須和原序列中的順序一樣)

最長公共子序列: 一個序列即是X序列的子序列,也是Y序列的子序列,則該序列稱為為X和Y的公共子序列。對于兩個序列的公共子序列是不唯一的,因此,最長公共子序列顧名思義就是長度最長的公共子序列。

思路分析:

方一、從最優(yōu)子結(jié)構(gòu)去考慮

求最長公共子序列長度:
分析:

? 因為動態(tài)規(guī)劃的題目是滿足最優(yōu)子結(jié)構(gòu)(最優(yōu)解包含其子問題的最優(yōu)解)這一基本條件的,因此我們通過分析最優(yōu)子結(jié)構(gòu)的特征,從而推出最優(yōu)值的遞推式,然后從子問題最優(yōu)解出發(fā),求解出整個問題的最優(yōu)解即可。

? 假設(shè)一個最優(yōu)子結(jié)構(gòu)情況,對于一個序列Z = {z1, z2, …… , zk}是 X = {x1, x2, ……, xm} 和 Y ={y1, y2 , ……, yn}的最長公共子序列,根據(jù)對最后一個元素考慮,我們可以分成三種情況來具體討論:

1)xm = yn = zk

? 將xm和yn的值作為序列Z的最長公共子序列的最后一個元素,如果去掉xm和yn,那么對于序列Z的最長公共子序列的長度肯定會減小1,即c[i - 1] [j - 1] = c[i] [j] - 1; 因此,當xm = yn時的遞推公式是: c[i] [j] = c[i - 1] [j - 1] + 1;

(為什么要將xm和yn值做為最長公共子序列最后一個元素?你想,兩個序列相等的元素且都在最后一個,并且和已知最長公共子序列的最后一個元素相等,無論X和Y前面怎么取公共部分,是不是最后這兩個元素都可以作為一個公共部分加入到公共子序列的末尾)

2)xm ≠ yn, xm ≠ zk

? 表明xm肯定不會作為最長公共子序列的最后一個元素,那么我們把xm去掉,對于{x1, x2,……, xm-1} 和 {y1, y2,……, yn -1}的最長公共子序列也還是{z1, z2,……, zk-1}

3)xm ≠ yn, yn ≠ zk

? 同理2)情況

由1)2)3)得最優(yōu)值的遞推式:

對于c[i] [j]數(shù)組:指只取X前i個元素和只取Y前j個元素能夠得到的最長公共子序列的值(即存放最優(yōu)子結(jié)構(gòu)的值)。

由1)可知,如果xi = yj,那么可以從沒有xi和yj的最優(yōu)子結(jié)構(gòu)即c[i - 1] [j - 1]轉(zhuǎn)移過來

即 c[i] [j] = c[i - 1] [j - 1] + 1;

由2)3)可知,如果xi ≠ yj, 那么我們只需要取xi和yj-1最優(yōu)子結(jié)構(gòu)和xi-1和yj最優(yōu)子結(jié)構(gòu)的最大長度即可。

即c[i] [j] = max(c[i] [j - 1] , c[i - 1] [j] );

綜上可以得出遞推式:

最長公共子序列(詳細代碼 注釋 分析 以及求出最長公共子序列內(nèi)容方法)

自底向上求出問題的最優(yōu)解:

? 對子結(jié)構(gòu)考慮的最優(yōu)情況,得出的遞推式是對所有求子問題的最優(yōu)解適用的,通過該遞推公式,自底向上計算子問題的最優(yōu)值,那么最后的答案也肯定是最優(yōu)的(這也就是動態(tài)規(guī)劃的最優(yōu)子結(jié)構(gòu)的特征)

代碼:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1010;
char s1[N], s2[N];
int len1, len2;
int c[N][N];
int main()
{
    //最優(yōu)子結(jié)構(gòu)狀態(tài)值初始化(當然也可以不寫,因為全局變量默認為0)
    memset(c, 0, sizeof(c));
    //輸入序列s1和s2的長度
    cin>>len1>>len2;
    //輸入需要求最長公共子序列的序列s1和s2
    cin>>s1+1>>s2+1;  
    for(int i = 1; i <= len1; i ++){
        for(int j = 1; j <= len2; j ++){
            if(s1[i] == s2[j])c[i][j] = c[i - 1][j - 1] + 1;
            else c[i][j] = max(c[i - 1][j], c[i][j - 1]);
        }
    }
    cout<<c[len1][len2]<<'\n';
    return 0;
}

求最長公共子序列內(nèi)容:

分析:

對于一個最優(yōu)子結(jié)構(gòu)c[i] [j]的來源一共有三個,分別是

1)c[i] [j] = c[i - 1] [j - 1] + 1;

2)c[i] [j] = c[i - 1] [j] ;

3)c[i] [j] = c[i] [j - 1];

在自底向上計算最優(yōu)值的時候,我們可以開一個臨時的數(shù)組b[i] [j]去記錄這3個來源,然后根據(jù)最值反向追蹤最長公共子序列:

1)b[i] [j] = 1, 即表示取了x[i]或y[j]作為最長公共子序列的一部分,我們輸出即可。

2)b[i] [j] = 2,即表示當前c[i] [j]的狀態(tài)來自c[i - 1] [j],我們追蹤c[i - 1] [j]

3)b[i] [j] = 3, 即表示當前c[i] [j]的狀態(tài)來自c[i] [j - 1],我們追蹤c[i] [j - 1]

代碼:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1010;
char s1[N], s2[N];
int len1, len2;
int c[N][N];
int b[N][N];
void print(int i, int j){
    if(i == 0 || j == 0)return;
    if(b[i][j] == 1){
        print(i - 1, j - 1);
        cout<<s1[i];
    }
    else if(b[i][j] == 2)print(i - 1, j);
    else print(i, j - 1);
}
int main()
{
    //最優(yōu)子結(jié)構(gòu)狀態(tài)值初始化
    memset(c, 0, sizeof(c));
    //輸入序列s1和s2的長度
    cin>>len1>>len2;
    //輸入需要求最長公共子序列的序列s1和s2
    cin>>s1+1>>s2+1;  
    for(int i = 1; i <= len1; i ++){
        for(int j = 1; j <= len2; j ++){
            if(s1[i] == s2[j]){
                c[i][j] = c[i - 1][j - 1] + 1;
                b[i][j] = 1;
            }
            else if(c[i - 1][j] >= c[i][j - 1]){
                c[i][j] = c[i - 1][j];
                b[i][j] = 2;
            }
            else {
                c[i][j] = c[i][j - 1];
                b[i][j] = 3;
            }
        }
    }
    print(len1, len2);
    // cout<<c[len1][len2]<<'\n';
    return 0;
}

當然如果你不想浪費空間,你也可以不用這個臨時數(shù)組b,直接通過c數(shù)組判斷即可:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1010;
char s1[N], s2[N];
int len1, len2;
int c[N][N];
void print(int i, int j){
    if(i == 0 || j == 0)return;
    if(c[i][j] == c[i - 1][j - 1] + 1){
        print(i - 1, j - 1);
        cout<<s1[i];
    }
    else if(c[i][j] == c[i - 1][j])print(i - 1, j);
    else print(i, j - 1);
}
int main()
{
    //最優(yōu)子結(jié)構(gòu)狀態(tài)值初始化
    memset(c, 0, sizeof(c));
    //輸入序列s1和s2的長度
    cin>>len1>>len2;
    //輸入需要求最長公共子序列的序列s1和s2
    cin>>s1+1>>s2+1;  
    for(int i = 1; i <= len1; i ++){
        for(int j = 1; j <= len2; j ++){
            if(s1[i] == s2[j])c[i][j] = c[i - 1][j - 1] + 1;
            else c[i][j] = max(c[i - 1][j], c[i][j - 1]);
        }
    }
    print(len1, len2);
    //cout<<c[len1][len2]<<'\n';
    return 0;
}

方二、閆氏DP分析法(從集合的角度考慮):

分析:

很久之前在Acwing上學(xué)習(xí)后,寫的題解(字丑):

我們通過f[i] [j]去表示所有A[1 ~ i]和B[1 ~ j]的公共子序列的集合,其表示的屬性是最大值(即最長長度)。

我們通過最長公共子序列是否包含最后兩個元素即a[i]和b[j]對這個集合來進行劃分,可以分為4種情況:

  1. a[i]和b[j]相等
  2. a[i]和b[j]不相等,a[i]和bx匹配x在j之前
  3. a[i]和b[j]不相等,b[j]和ax匹配x在i之前
  4. a[i]和b[j]不相等,兩數(shù)都沒有匹配

對于f[i] [j] = f[i - 1] [j - 1] + 1覆蓋情況1

對于f[i] [j] = max{f[i - 1] [j], f[i] [j - 1]}覆蓋情況2 3 4

最長公共子序列(詳細代碼 注釋 分析 以及求出最長公共子序列內(nèi)容方法)
最長公共子序列(詳細代碼 注釋 分析 以及求出最長公共子序列內(nèi)容方法)文章來源地址http://www.zghlxwxcb.cn/news/detail-413587.html

代碼:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e3 + 5;
int n, m;
int f[N][N];
char a[N], b[N];
int main()
{
    cin >> n;
    cin >> a + 1;
    cin >> m;
    cin >> b + 1;
    
    for(int i = 1; i <= n; i ++)f[i][0] = i;
    for(int j = 1; j <= m; j ++)f[0][j] = j;
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            int diff;
            if(a[i] == b[j])diff = 0;
            else diff = 1;
            f[i][j] = min({f[i - 1][j] + 1, f[i][j - 1] + 1, f[i - 1][j - 1] + diff});
        }
    }
    // for(int i = 0; i <= n; i ++){
    //     for(int j = 0; j <= m; j ++){
    //         cout << f[i][j] << ' ';
    //     }
    //     cout << '\n';
    // }
    cout << f[n][m] << '\n';
    return 0;
}
/*
狀態(tài)表示:
集合:a前i 變成b前j需要的操作
屬性:min

狀態(tài)計算:
劃分:根據(jù)最后一個元素從增、刪、改進行劃分
//替
1)A[i] == B[j] 不用進行操作
f[i][j] = f[i - 1][j - 1];

2)A[i] != B[j] 
f[i][j] = f[i - 1][j - 1] + 1;

3)A[i] 增B[j](ai 和 bj - 1 對齊)
f[i][j] = f[i][j - 1] + 1;

4)A[i] 刪 A[i](ai - 1 和 bj 對齊)
f[i][j] = f[i - 1][j] + 1;

狀態(tài)轉(zhuǎn)移:


*/

//狀態(tài)表示:f[i][j]是以1~ai的序列和以1~bj的序列的最長的公共子序列長度

//當枚舉到的兩個元素相同時:
//說明可以將該元素加入到兩個子序列的最長公共子序列上,因此就直接對于f[i][j]=f[i-1][j-1]+1,表示在1~a[i-1]和
//1~b[j-1]的公共最長子序列的基礎(chǔ)上加1,將f[i-1][j-1]狀態(tài)加一轉(zhuǎn)移給f[i][j]
//因此我們轉(zhuǎn)移公式就是:f[i][j]=f[i-1][j-1]+1

//當枚舉到的兩個元素不同:
//那我們肯定是不能夠?qū)⑺麄兗尤氲絻蓚€子序列的最長公共子序列上,因此我們要去尋找之前最長的公共子序列長度轉(zhuǎn)移過來
//對于a[i]和b[j]不相等存在3中情況:
//1、a[i]屬于a和b的最長公共子序列,a[i]和bx匹配x在j之前,那么我們就要從f[i][j-1]將狀態(tài)轉(zhuǎn)移過來,此時的狀態(tài)就
//是到i,j為止最長的公共子序列長度
//2、b[j]屬于a和b的最長公共子序列,b[j]和ax匹配x在i之前,那么我們就要從f[i-1][j]將狀態(tài)轉(zhuǎn)移過來此時的狀態(tài)就是
//到i,j為止最長的公共子序列長度
//3、a[i]和b[j]都不屬于a和b的最長公共子序列,我們應(yīng)當是從f[i-1][j-1]去將狀態(tài)轉(zhuǎn)移過來,但對于f[i-1][j]和f[i][j-1]
//是已經(jīng)將f[i-1][j-1]的狀態(tài)包括在里面(因為這三者是相等的)
//因此我們轉(zhuǎn)移公式就是:f[i][j]=max(f[i][j-1],f[i-1][j])

到了這里,關(guān)于最長公共子序列(詳細代碼 注釋 分析 以及求出最長公共子序列內(nèi)容方法)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 代碼隨想Day53 | 1143.最長公共子序列、1035.不相交的線、53. 最大子序和

    本題和?718.?最長重復(fù)子數(shù)組?的區(qū)別就是本題不要求連續(xù),所以在兩個字符不相等的時候,邏輯不相同,當不相同的時候,需要找到dp[i-1][j]和dp[i][j-1]之間的最大值,因為不相等的時候需要找出退而求上一個狀態(tài)的兩個值的最大,這樣才能得到最長公共子序列數(shù),其他的思路

    2024年02月03日
    瀏覽(23)
  • 代碼隨想錄第53天|● 1143.最長公共子序列 ● 1035.不相交的線 ● 53. 最大子序和 動態(tài)規(guī)劃

    代碼隨想錄第53天|● 1143.最長公共子序列 ● 1035.不相交的線 ● 53. 最大子序和 動態(tài)規(guī)劃

    dp[i][j]:長度為[0, i - 1]的字符串text1與長度為[0, j - 1]的字符串text2的最長公共子序列為dp[i][j] 通過pre記錄前一個dp[j-1] 循環(huán)中記錄cur為dp[i],循環(huán)結(jié)束后再更新pre=cur。 和最長公共子序列相同 注意pre和cur放置的位置 dp[i]:包括下標i(以nums[i]為結(jié)尾)的最大連續(xù)子序列和為dp[i

    2024年03月08日
    瀏覽(25)
  • 最長公共子序列和最長公共子串

    最長公共子序列 題目描述 給出1,2,…, n 的兩個排列P 1 和 P 2 ,求它們的最長公共子序列。 輸入格式 第一行是一個數(shù) n 。 接下來兩行,每行為 n 個數(shù),為自然數(shù)1,2,…, n 的一個排列。 輸出格式 一個數(shù),即最長公共子序列的長度。 題目分析 第一階段定義dp數(shù)組 (1)考慮規(guī)模

    2024年02月19日
    瀏覽(20)
  • 【算法訓(xùn)練-字符串 三】最長公共子串、最長公共子序列

    【算法訓(xùn)練-字符串 三】最長公共子串、最長公共子序列

    廢話不多說,喊一句號子鼓勵自己:程序員永不失業(yè),程序員走向架構(gòu)!本篇Blog的主題是【】,使用【】這個基本的數(shù)據(jù)結(jié)構(gòu)來實現(xiàn),這個高頻題的站點是: CodeTop ,篩選條件為: 目標公司+最近一年+出現(xiàn)頻率排序 ,由高到低的去 ??蚑OP101 去找,只有兩個地方都出現(xiàn)過才做

    2024年02月09日
    瀏覽(21)
  • 【LeetCode動態(tài)規(guī)劃#14】子序列系列題(最長遞增子序列、最長連續(xù)遞增序列、最長重復(fù)子數(shù)組、最長公共子序列)

    【LeetCode動態(tài)規(guī)劃#14】子序列系列題(最長遞增子序列、最長連續(xù)遞增序列、最長重復(fù)子數(shù)組、最長公共子序列)

    力扣題目鏈接(opens new window) 給你一個整數(shù)數(shù)組 nums ,找到其中最長嚴格遞增子序列的長度。 子序列是由數(shù)組派生而來的序列,刪除(或不刪除)數(shù)組中的元素而不改變其余元素的順序。例如,[3,6,2,7] 是數(shù)組 [0,3,1,6,2,2,7] 的子序列。 示例 1: 輸入:nums = [10,9,2,5,3,7,101,18] 輸出

    2024年02月01日
    瀏覽(28)
  • 最長公共子序列

    最長公共子序列

    最長公共子序列,英文縮寫為LCS (Longest Common Subsequence)。其定義是,一個序列 S ,如果分別是兩個或多個已知序列的子序列,且是所有符合此條件序列中最長的,則 S 稱為已知序列的最長公共子序列。 子串、子序列還有公共子序列的概念(在上篇LIS中也曾涉及過) ,我們以字

    2024年02月16日
    瀏覽(20)
  • 最長公共子序列LCA

    最長公共子序列LCA

    題目鏈接:3692. 最長連續(xù)公共子序列 - AcWing題庫

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

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

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

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

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

    先來講解以下什么是最長公共子序列。最長公共子序列不是最長相同字符串,有點相似但不一樣,來舉個簡單的例子,有字符串s1=bcdea,s2=abce,最長相同字符串是bc,最大公共部分是2;而最長公共子序列則是bce,最大公共部分是3??梢钥闯觯沧有蛄胁恍枰B續(xù)相等,有相

    2023年04月19日
    瀏覽(25)
  • 動態(tài)規(guī)劃9:最長遞增子序列、最長連續(xù)遞增序列、最長重復(fù)子數(shù)組、最長公共子序列、不相交的線、最長子序和

    動態(tài)規(guī)劃9:最長遞增子序列、最長連續(xù)遞增序列、最長重復(fù)子數(shù)組、最長公共子序列、不相交的線、最長子序和

    例題300: 給你一個整數(shù)數(shù)組 nums ,找到其中最長嚴格遞增子序列的長度。 子序列 是由數(shù)組派生而來的序列,刪除(或不刪除)數(shù)組中的元素而不改變其余元素的順序。例如,[3,6,2,7] 是數(shù)組 [0,3,1,6,2,2,7] 的子序列。 確定dp數(shù)組和下標含義 dp[i]表示在第i個元素的最長子序列數(shù)

    2024年04月08日
    瀏覽(29)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包