1. 程式人生 > >學習筆記:求陣列的最長遞增子序列LIS

學習筆記:求陣列的最長遞增子序列LIS

陣列的最長遞增子序列LIS是一類經典問題。例如陣列2,1,5,3,6,4,8,9,7。此陣列的LIS為1,3,4,8,9長度為5。

如果用經典的動態規劃演算法求解的話,設f[i]為以i結尾的LIS的長度。例如求f[8],即以8結尾的LIS的長度,那麼f[ 8]=max{ f[2]+1 ,f[1]+1, f[5]+1, f[3]+1, f[6]+1, f[4]+1}。此時需要遍歷8以前的所有元素。求最長的LIS為max{ f[2] ,f[1] ,f[5] ,f[3], f[6] ,f[4] ,f[8] ,f[9] ,f[7] }。此時演算法的時間複雜度為o(n.^2)。

這裡有一個通過二分查詢能夠將演算法的時間複雜度降低為o(nlogn)的方法:

定義陣列f2,f2的元素從小到大有序排列。f2[i]=j的語義是,長度為i的LIS中,最小的結尾數字。例如,上述陣列中,所有長度為2的LIS中,1,3這個長度為2的LIS以3結尾,是所有長度為2的LIS最小的結尾數字,其他任何一個長度為2的LIS結尾數字都大於3。所以f2[2]=3。

初始化f2[1]=2即等於陣列的第一個元素,語義為:目前已遍歷的陣列元素中(只遍歷了陣列的第一個元素),長度為1的LIS最小結尾數字為2。

從陣列的第二個元素開始遍歷:

i=1,此時i比f2中最小的元素還要小,則f2[1]=1

i=5,此時i比f2中最大的元素還要大,f2的長度+1,f2[2]=5

i=3,用i替換f2中比i大的最小元素,f2[2]=3。此時陣列f2[j]的語義依然為:在目前已遍歷的元素中,長度為j的LIS最小結尾數字為f2[j]。

i=6,此時i比f2中最大的元素還要大,f2的長度+1,f2[3]=6

i=4,用i替換f2中比i大的最小元素,f2[3]=4。

i=8,比f2最大的數字還要大,f2的長度+1,f2[4]=8

i=9,同理,f2的長度+1,f2[5]=9

i=7,替換f2[8]=7。

此時f2的長度為5,即在陣列中LIS最長的長度為5,答案即可得到。

由於f2是有序排列的,在遍歷陣列插入新資料的時候可以通過二分查詢找到插入點,即logn的時間複雜度,加上遍歷陣列的時間複雜度,總時間複雜度降低為o(nlogn)