题目:

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

思路:

方法1,动态规划

建立一个动态数组,来表示遍历到数组的对应位置时,当前的递增子序列的长度,具体过程是遍历数组,遍历到某个数的时候,再遍历从0开始到当前位置的数,更新最大序列长度,如果索引j对应的数小于索引i的数,就更新最大长度,状态转移公式取更新后的当前位置的最大序列长度j位置上的这个数对应的最大序列长度加1之间的较大值,可举例思考,遍历完全部元素以后,返回动态数组中的最大值。

方法2,贪心和二分查找
维护一个数组,索引i上的数表示长度为i的最长序列的末尾元素的最小值,在让序列变长的过程中,每次都放能放的最小值,才能让序列更长。

具体过程
遍历数组中的元素,当这个值比结果数组中的最后一个大时直接加在后面,当比最后一个元素小时,要找到一个位置,这个位置的数大于遍历的元素,这个位置前面的数小于遍历的元素,用二分法找到这个位置,然后将找到的位置的数换为遍历到的元素,最后返回维护的这一数组的长度。

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # # 动态规划
        # dp = [1] * len(nums) # 表示遍历到数组的对应位置时,当前的递增子序列的长度
        # for i in range(len(nums)):
        #     for j in range(i):
        #         if nums[j] < nums[i]:
        #             dp[i] = max(dp[i],dp[j] + 1)
        # # 更新当前位置的最大长度,比较的是当前位置更新后的长度和当前遍历到的这个数满足条件的话,再加上1的长度哪个更大,更新
        # return max(dp) # 取最大的长度
        # 贪心加二分查找
        # 维护一个数组,索引i上的数表示长度为i的最长上升子序列的末尾元素的最小值,就是这个位置能放置的最小值,这样才能让序列更长
        d = []
        for n in nums:
            if not d or n > d[-1]:
                d.append(n)
            else:
                l,r = 0,len(d)-1 # 初始左右指针
                cur = r
                while l <= r:
                    mid = (l+r) // 2 # 找到中间位置,向下取整
                    if d[mid] >= n: # 中间的数大于遍历的数,要往前找
                        cur = mid
                        r = mid -1
                    else:# 中间的数小于遍历的数,往后找
                        l = mid + 1
                d[cur] = n
        return len(d)