線性dp:最長公共子串

Tomorrowland_D發表於2024-08-24

最長公共子串

  • 閱讀本文前可以先了解“動態規劃方法論”,在我之前講過的文章有講過。

動態規劃方法論

  • 本文講解的題與leetcode718.最長重複子陣列,題意一模一樣,閱讀完本文以後可以去挑戰這題。

力扣連結

題目敘述:

給定兩個字串,輸出其最長公共子串的長度。

輸入

ABACCB
AACCAB

輸出

3

解釋

最長公共子串是ACC,其長度為3。

與最長公共子序列的區別

  • 公共子串:字元必須是連續相等的
  • 公共子序列:字元必須是相等的,可以不連續。

動態規劃思路

  • 只有當兩個字串中的字元連續相等的時候,公共子串的長度才不斷增加,否則清零
  • 因此,我們不難發現,公共子串問題其實是公共子序列問題的一個特殊情況

狀態變數以及其含義

  • 我們延續最長公共子序列的思路,可以使用兩個指標變數,ij來遍歷a,b字串。
  • 那麼我們的f[i][j]代表著什麼呢?因為本題是要連續的子串,因此我們的 f[i][j]表示以a[i]b[j]為結尾的公共子串的長度

遞推公式

  • 那麼,我們很容易的就可以得出遞推公式:
    • f[i][j]=f[i-1][j-1]+1a[i]==b[j]
    • f[i][j]=0)(a[i]!=b[j]
  • 邊界條件為:
    • f[0][j]=0
    • f[i][0]=0

遍歷順序:

  • 顯然是從上到下,從左到右。

如何初始化?

  • 處理好上面所說的邊界條件,並且根據遞推公式來進行初始化f陣列即可。

舉例列印dp陣列

  • 舉例如如圖所示:

img

  • f[i][j] 的值如圖所示。

最終程式碼實現

#include<iostream>
#include<cstring>
using namespace std;

char a[200]="BCCABCCB";
char b[200]="AACCAB";
int f[201][201];

int main(){
  int ans=0;
  for(int i=1; i<=strlen(a); i++){
    for(int j=1; j<=strlen(b); j++){
      if(a[i-1]==b[j-1]) f[i][j]=f[i-1][j-1]+1;
      ans=max(ans,f[i][j]);
    }
  }
  printf("ans=%d\n",ans);
  return 0;
}

相關文章