最長子序列可以說是剛接觸動態規劃的人經常遇見也不得不解決的問題,最常見的有兩種,一種是最長公共子串行(lcs),還有乙個是最長上公升子串行(lis)。今天我就總結下這兩個的做法。
一:最長公共子串行(lcs)
題目描述:給你兩個陣列,可以是數字的,也可以是字串,我們假設是數字的!舉個例子:
x = 1, 5, 6, 4, 1, 3, 7
y = 1, 1, 6, 8, 3, 4, 7
求乙個新的陣列s,該陣列中的每個數均是x和y陣列中的公共數,並滿足原陣列中數字的前後關係,這樣的陣列有很多個,比如說 (1,1),(1,1,3,7),(1,6,7)等。同時s陣列要是長度最長的那個,像上面的(1,1,3,7),長度是4,那麼即為所求解!
做dp題目最重要的一點是能正確的構造出dp函式,如果能很好的構造出來,就成功一半了。
dp[i][j] 表示x陣列的前i位和y陣列的前j位之前的lcs,那麼它可以由前面三個狀態推出來。
0 if(i=0 || j=0) --初始化,不難理解,不管是x還是y陣列,只要有乙個長度是0,那麼s陣列就是0
dp[i][j] = max(dp[i-1][j],dp[i][j-1] if(i,j>0 && x[i] != y[j]) --s陣列沒有新增數字,那麼只能從前面繼承來,乙個從x,乙個從y,看那個大
dp[i-1][j-1] + 1 if(i,j>0 && x[i] == y[j]) --如果是兩個相同,當然是把s陣列加1,可以看成x和y都繼承了
**很簡單,兩個for迴圈就可以了。
二:最長遞增子串行(lis)
題目描述:給你乙個陣列,如x陣列,x = 1,2,3,6,5,7,4,8,6。
求乙個新的陣列s,該陣列中的每個數均是x陣列中的數,且對s中任意兩個數s[i],s[j]滿足 j>i && s[j]>s[i]。同時s陣列要是長度最長的那個,像(1,2,3,6,7,8)和(1,2,3,5,7,8),長度是6,即為所求解。
dp[i]表示以x陣列中的第i個元素為s陣列的底元素的最長子序列的長度。這樣又可以變成子問題來求解了,
dp[i] = max(dp[j]) + 1 0num[j]。就是在i前面找乙個符合條件的最長子序列。
對這個題目來說,dp方程還是比較容易推出來和理解的,但你可以發現,時間複雜度是o(n^2)的,這對許多題目都是不能接受的,所以你必須進行優化。這就牽扯到乙個問題,最長遞增子串行的o(n*lgn)做法。
做法如下:首先給你乙個陣列stack,用來儲存最長遞增子串行(按照遞增的要求,即陣列的最頂端的數最大,最尾的數最小,如果說用棧的話你也許更好理解),對x陣列進行線掃,如果x[i]大於陣列的頂端元素(最大值),那麼把這個數加入到stack陣列中來,如果比頂端元素小,那麼在stack陣列中找到第乙個大於x[i]的數,並用x[i]替換掉。因為stack陣列是有序的,在你找第乙個大於x[i]的數的時候你就可以用二分查詢來做,這就是優化所在!
這兩個都是很簡單的dp題目,但也包含了動態規劃思想,在後面的很多題目中你會發現都會不經意中用到這種思想,所以很好的理解他們是必須的。但動態規劃博大精深,就因為他沒有固定的程式,許多都是思想,所以僅僅知道這兩個是遠遠不夠的!
最長子序列 動態規劃
一.題目描述 在字母表上分別給出兩個長度為m和n的字串x和y,確定在x和y中的最長公共子串行。例如,x為 abcbdab y為 bdcaba 則兩者的最長公共子串行為bdab。二.思路分析 假設兩個字串為x1,x2 xi和y1,y2 yj,再令l i,j 表示這兩個的最長公共子串行。思路如下 如果x...
單調遞增最長子序列(動態規劃)
求乙個字串的最長遞增子串行的長度 如 dabdbf最長遞增子串行就是abdf,長度為4 第一行乙個整數0輸出字串的最長遞增子串行的長度 3 aaaababc abklmncdefg 137 ac 1 include2 include 3 include4 using namespace std 5c...
求單調遞增最長子序列(動態規劃)
題目描述 求乙個字串的最長遞增子串行的長度 如 dabdbf最長遞增子串行就是abdf,長度為4 輸入 乙個字串,該字串的長度不會超過10000 輸出 輸出字串的最長遞增子串行的長度 樣例輸入 aaa ababc abklmncdefg 樣例輸出 1 3 7 解題思路 從前往後遍歷,計算每乙個字元處...