荒廢演算法的學習已經快一年了,最近越來越認識到演算法的重要性,雖然可能不去參加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.工作中經常遇到乙個問題以後,很容易鑽牛角尖,而不是向同事...
近一年回顧
這個假期過後,標誌著自己學習已經滿滿的兩年了。不知為何這第二年過的感覺要比第一年快好多。這一年的經歷,重點向說下思想的重要性。先的批判自己,然後在表揚,給以自己學習的動力和方向。首先說下自己的這一年學習 總體說有兩大塊的內容 這部分是所有軟體開發的基礎。無論是客戶端還是瀏覽器版,都要準守的規則。同時...