最長遞增子串行問題的求解
最長遞增子串行問題是乙個很基本、較常見的小問題,但這個問題的求解方法卻並不那麼顯而易見,需要較深入的思考和較好的演算法素養才能得出良好的演算法。
一, 最長遞增子串行問題的描述
設l=是n個不同的實數的序列,l的遞增子串行是這樣乙個子串行lin=,其中k1是對序列l=按遞增排好序的序列。那麼顯然x與l的最長公共子串行即為l的最長遞增子串行。這樣就把求最長遞增子串行的問題轉化為求最長公共子串行問題lcs了。
最長公共子串行問題用動態規劃的演算法可解。設li=< a1,a2,…,ai>,xj=< b1,b2,…,bj>,它們分別為l和x的子串行。令c[i,j]為li與xj的最長公共子串行的長度。則有如下的遞推方程:
這可以用時間複雜度為o(n2)的演算法求解。求最長遞增子串行的演算法時間複雜度由排序所用的o(nlogn)的時間加上求lcs的o(n2)的時間,演算法的最壞時間複雜度為o(nlogn)+o(n2)=o(n2)。
三, 第二種演算法:動態規劃法
設f(i)表示l中以ai為末元素的最長遞增子串行的長度。則有如下的遞推方程:
這個遞推方程的意思是,在求以ai為末元素的最長遞增子串行時,找到所有序號在l前面且小於ai的元素aj,即jf[i]-1)
f[i]=f[j]+1;//更新f[i]的值。}}
system.out.println(f[n-1]);
}這個演算法有兩層迴圈,外層迴圈次數為n-1次,內層迴圈次數為i次,演算法的時間複雜度
所以t(n)=o(n2)。這個演算法的最壞時間複雜度與第一種演算法的階是相同的。但這個演算法沒有排序的時間,所以時間複雜度要優於第一種演算法。
四, 對第二種演算法的改進
在第二種演算法中,在計算每乙個f(i)時,都要找出最大的f(j)(jlen) len++;//更新當前最大遞增子串行長度;
}system.out.println(len);
}現在來證明這個演算法為什麼是正確的。要使演算法正確只須證如下命題:
命題1:每一次迴圈結束陣列b中元素總是按遞增順序排列的。
證明:用數學歸納法,對迴圈次數i進行歸納。
當i=0時,即程式還沒進入迴圈時,命題顯然成立。
設ib[j2],因為第i次迴圈之前陣列b是遞增的,因此第i次迴圈時b[j1]或b[j2]必有乙個更新,假設b[j1]被更新為元素ai+1,由於ai+1=b[j1]> b[j2],按演算法ai+1應更新b[j2]才對,因此產生矛盾;假設b[j2]被更新,設更新前的元素為s,更新後的元素為ai+1,則由演算法可知第i次迴圈前有b[j2]=s< ai+1< b[j1],這與歸納假設矛盾。命題得證。
命題2:b[c]中儲存的元素是當前所有最長遞增子串行長度為c的序列中,最小的最末元素,即設當前迴圈次數為i,有b[c]=(f(i)為與第二種演算法中的f(i)含義相同)。
證明:程式中每次用元素ai更新b[c]時(c=f(i)),設b[c]原來的值為s,則必有aip(i))的最長遞增子串行後面,就應該能接在b[l]後面,那麼就應該有p(i)=l,與l> p(i)矛盾。因此一定有p(i)=f(i),命題得證。
演算法的迴圈次數為n,每次迴圈二分查詢用時logn,所以演算法的時間複雜度為o(nlogn)。這個演算法在第二種演算法的基礎上得到了較好的改進。
原文出處:http://www.wangchao.net.cn/bbsdetail_59352.html
最長遞增子串行求解
演算法難,難於上青天 搞懂乙個演算法不容易,還是寫篇部落格為以後複習做好準備 include define n 1000 using namespace std int getlongcommonsub int a 6 int dp 6 int n return dp i 1 int main in...
zz 最長遞增子串行的求解
什麼是最長遞增子串行呢?問題描述如下 設l 是n 個不同的實數的序列,l的遞增子串行是這樣乙個子串行 lin 其中k1且 ak1。求最大的m值。對於這個問題有以下幾種解決思路 1 把a1,a2,an 排序,假設得到 a 1,a 2,a n 然後求a的 a 的最長公共子串,這樣總的時間複雜度為 o n...
最長遞增子串行問題
給定乙個長度為n的陣列,找出乙個最長的單調自增子序列 不一定連續,但是順序不能亂 例如 給定乙個長度為6的陣列a,則其最長的單調遞增子串行為,長度為4.include define maxn 100 假設最多有100個元素 using namespace std int l maxn l i 表示元...