学习笔记:求数组的最长递增子序列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)

猜你喜欢

转载自blog.csdn.net/LOVETEDA/article/details/83377075