寻找数组中最大递增子序列

参考博客:寻找数组中最大递增子序列

#coding=utf-8
# 寻找list中的最长递增子序列.. 不要求元素必须彼此相邻.. 如:[1,-1,2,-3,4,-5,6,-7] >> [1,2,4,6]
# https://wax8280.github.io/2016/10/18/859/
# 这段代码我真是看了很久都还没完全吃透理解...
def getdp(arr):
    n = len(arr)
    # dp存储到当前位置i为止的,最长递增子序列长度..
    # end存储当前最大递增子序列最大元素,的最小值  MaxV
    dp, ends = [0] * n, [0] * n
    ends[0], dp[0] = arr[0], 1
    right = 0
    for i in range(1, n):
        l = 0
        r = right  # end[0,...right]
        # 二分查找,找到当前的s[i]是否是可以比前i-1个中的某个值大.
        # 若找不到,则更新ends[l或r]
        # 若arr[i]比ends有效区的值都大,则l=right+1
        # s = [2, 1, 5, 3, 6, 4, 8, 9, 7]
        while l <= r:
            m = (l + r) / 2       # 二分查找使更快..
            if arr[i] > ends[m]:  # 这是没找到end大于a[i]的情况,则继续二分查找..
                l = m + 1
            else:
                r = m - 1
        # while循环是直到l>r才退出的..
        right = max(right, l)
        ends[l] = arr[i]  #
        dp[i] = l + 1
    return dp

def generateLIS(arr, dp):
    n = max(dp)
    index = dp.index(n)
    lis = [0] * n
    n -= 1
    lis[n] = arr[index]
    # 从右向左
    for i in range(index, 0 - 1, -1):
        # 关键
        if arr[i] < arr[index] and dp[i] == dp[index] - 1:
            n -= 1
            lis[n] = arr[i]
            index = i
    return lis
s = [2, 1, 5, 3, -1, 4, 3, -3, -2]
dp = getdp(s)
print '方法一##############', max(dp)
res = generateLIS(s, dp)
print res






######################### my code1 #############################
# 时间复杂度O(N^2)..
# 效率最低的...
def fun(s):
    n = len(s)
    LIS = [1] * n
    for i in range(n):
        for j in range(i):  # j,遍历当前的最大递增子序列
            if s[i] > s[j] and LIS[j] + 1 > LIS[i]:
                LIS[i] = LIS[j] + 1
    return max(LIS)
s = [2, 1, 5, 3, -1, 4, 3, -3, -2]
res1 = fun(s)
print '方法二#############', res1



######################### my code2 #############################
def fun2(s):
    n = len(s)
    LIS = [1] * n  # 存放每个i位置的最长子序列值
    Maxv = [1] * (n + 1)  # 存放最长子序列内的最大值
    Maxv[1] = 1
    Maxv[0] = min(s) - 1  # 取边界?
    maxlen = 1  # 最大的递增子序列长度
    for i in range(1, n):
        # j是遍历当前最大的递增子序列长度
        for j in range(maxlen, -1, -1):  # 这里需要逆序注意!!!
            if s[i] > Maxv[j]:  # 找到了现在进来的这个s[i]比哪一个长度的j对应的Maxv值大,那么LIS[i]就是j+1
                LIS[i] = j + 1
                break  # 找打了就可以马上break了,不需要再遍历更前面的Maxv值..
        if LIS[i] > maxlen:
            maxlen = LIS[i]
            Maxv[LIS[i]] = s[i]
        # 这个else是因为s[i]进来没能LIS[I]大于maxlen,即可能s[i]找到的大于的Maxv[j]j是比较靠中间的j,所以它是存在Maxv[j + 1]的
        # 所以如果Maxv[j + 1]更大s[i]更小,那么s[i]可以替换掉Maxv[j + 1]
        elif Maxv[j] < s[i] and s[i] < Maxv[j + 1]:
            Maxv[j + 1] = s[i]
    return maxlen


s = [2, 1, 5, 3, -1, 4, 3, -3, -2]
res2 = fun2(s)
print '方法三###############'

方法以一直还是没吃透。。。

放上来希望有大神能愿意指点一二。。。~~

点赞