時隔近一年,重學演算法 最長公共子串行問題

2021-10-04 09:16:05 字數 3985 閱讀 3033

荒廢演算法的學習已經快一年了,最近越來越認識到演算法的重要性,雖然可能不去參加acm比賽,但是演算法也是乙個程式設計師必備的一門課。讓我有點難受是過去所學得演算法似乎都沒有真正地去搞懂過,有很多細節的地方都是以自己的想法掩蓋過去,試圖說服自己已經懂了,所以在演算法的學習路上才會那麼的坎坷(當然我現在仍然在演算法學習路上)。其實很多時候都怕自己學演算法不會變通,生搬硬套,也許是自己不夠熟悉,練習不夠。但不管如何,繼續摸索。

昨天學習了動態規劃的最長公共子串行問題。評判乙個問題是否可以用

動態規劃去解決時,需要判斷該問題是否具有以下的兩個特點。

最優子結構。最優子結構是指乙個問題可以分解為若干的子問題,二這些子問題在結構上是與原問題一致的,只是問題的規模會越來越小。

重疊子問題。在乙個問題被分解為若干的子問題後,可能會出現重疊的子問題,即乙個問題會被求解多次,浪費資源。重疊子問題的解決可以使用陣列去儲存子問題的結果,當問題再次被分解為子問題時先判斷該子問題是否已經被計算過了,如果被計算過就無須再次計算,直接使用子問題的結果。

最長公共子串行問題的分析

1.首先子串行可以是不連續的,比如字串 abcde是乙個序列,而 ace是該字串的子串行,ace並沒有相鄰。

2. 以c[i] [j] 作為長度為i的字串a和長度為j的字串b的最長公共子序的長度。假設a[i]為字串a的第i個元素,b[j]為字串b的第j個元素.

3. 當a[i]==b[j]時, 此時他們的公共子串行的長度為a[i-1]和b[i-1]時候的最長公共子串行的長度加1,即c[i][j]=c[i-1][j-1].

4. 當a[i]!=b[j]時,需要判斷以下三種情況:

(1)a[i]等於b[0]~b[j-1]中的乙個,即a[i]對於最長公共子串行有貢獻,此時的最長公共子串行的長度為 c[i][j-1]

(2)b[j]等於a[0]~a[i-1]中的乙個,即b[i]對於最長公共子串行有貢獻.此時的最長公共子串行的長度為 c[i-1][j]

(3)a[i]不等於b[0]~b[j-1]中的乙個, b[j]不等於a[0]~a[i-1]中的乙個 ,即a[i]和b[j]對於最長公共子串行的長度都沒有貢獻.此時的最長公共子串行的長度為 c[i]-1[j-1].

顯然第一種情況的最長公共子串行長度都比第三種的大,所以我們只要考慮前兩者,且要取兩者中較大的乙個。因此我們得到了該最長公共子串行的遞推方程組。

我們可以通過遞迴不斷地去分解問題。

也可以從子問題出發,把子問題計算出來,再去解決父問題,將子問題的求解結果儲存到陣列,下次便可以直接使用,同時無需去判斷子問題是否已經解決過,因為是從子問題出發的。

這裡我們使用了第二種方法

先考慮從c[0][j]和c[i][0]的問題,a串或b串長為0時,其最長公共子串行的長度為0,因此需要初始化為0;

這裡c[i][j]的行和列都加了一,因為需要儲存ab串長度為0時候其最長公共子串行的長度。

最長公共子串行**

//fun為二維陣列實現

//fun1為滾動陣列實現

#include

#define m 100

#define n 100

int c[m+1]

[n+1]=

;//c[m][n]為長度為m的a的子串行與長度為n的b的子串行的最長公共子串行

//思路:

//如果xi=xj,則最長公共子串行為c[i-1][j-1]+1

//圖個xi!=xj,xi最長公共子串行為

void

init()

char a[m]

="abcdefgcc"

;char b[n]

="crefysdjnhgccs"

;/*動態規劃,非遞迴,因為是自下而上的,先計算了子問題,在往上計算大的問題

*因為一開始就對最小子問題有了初始化(init函式),每次的計算都需要用到上次計算的結果,

*故用陣列儲存上次的結果,下次便可以直接使用

*///程式的編寫需要注意的是陣列長度問題,

intmax

(int a,

int b)

intfun

(int i,

int j)

else

return c[i+1]

[j+1];

}//滾動陣列

int c1[2]

[n]=

;//c1選擇為較小的子串行長度

intfun1

(int i,

int j)

else

}void

common

(int lm,

int ln)

}printf

("%d\n lm:%d ln:%d"

,c[lm]

[ln]

,lm,ln)

;//輸出ab陣列的長度以及c[m][n]的值

}//由於在使用二維陣列進行動態規劃時,

//每次使用到的資料只有前乙個和上一行的資料

//因此可以使用一行陣列進行滾動,從而縮小空間

void

roll

(int lm,

int ln)

// printf("\n");

// for (int j=0;j

// printf("%d ",c1[i%2][j] );

// }

// printf("\n");

// for (int j=0;j

// printf("%d ",c1[(i+1)%2][j] );

// }

// printf("\n");

}printf

("\n");

for(

int i=

0;i<=ln;i++)}

intmain()

while

(b[ln]

!='\0'

)common

(lm,ln)

;//二維陣列實現

roll

(lm,ln)

;//滾動陣列實現

return0;

}

另外的最長公共子串的問題跟最長公共子串行其實是差不多的,最長公共子串是相鄰的,需要在判斷a[i] 和b[i]不等的時候

附上最長公共子串的**,可能實現有點出入

#include

#define m 100

#define n 100

int c[m+1]

[n+1]=

;void

init()

char a[m]

="abcdefg"

;char b[n]

="bcacdefgca"

;int

max(

int a,

int b)

intfun

(int i,

int j)

else

return c[i]

[j];

}int

main()

while

(b[ln++]!=

'\0'

)for

(int i=

0;i1;i++

)for

(int j=

0;j1;j++

)int maxn=0;

for(

int i=

0;i}printf

("%d\n lm:%d ln:%d \n%s"

,maxn,lm,ln,b)

;return0;

}

演算法學習路途遙遠,一點一點積累。。。。。

時隔一年,再聊Open RAN

上週參加mwc,小棗君最大的感受,就是撲面而來的網路開放化 虛擬化 智慧型化浪潮。從接入網到核心網,幾乎所有的傳統通訊裝置都有了雲化解決方案。白盒 雲化 輕量化 類似的字眼在展會上幾乎隨處可見。彷彿一夜之間,所有的企業都成為了基站裝置商 核心網裝置商,整個行業進入了 人人皆vendor 裝置廠家 的...

工作近一年的總結

1.在工作步調 觀念上沒有和老闆保持高度的一致,一直以為老闆是 錯誤的,而沒有向他多問幾個為什麼,而是找其他部門的同事請教,而且結果未果,這樣做其實是很低效的 2.沒有把平時累計的困惑幾天的問題彙總成為具體的文字 郵件儲存,向同事隨時請教 3.工作中經常遇到乙個問題以後,很容易鑽牛角尖,而不是向同事...

近一年回顧

這個假期過後,標誌著自己學習已經滿滿的兩年了。不知為何這第二年過的感覺要比第一年快好多。這一年的經歷,重點向說下思想的重要性。先的批判自己,然後在表揚,給以自己學習的動力和方向。首先說下自己的這一年學習 總體說有兩大塊的內容 這部分是所有軟體開發的基礎。無論是客戶端還是瀏覽器版,都要準守的規則。同時...