(Leetcode) 最长上升子序列 - Python实现

题目:最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18],输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

-------------------------------------------------------------------------------

思路:典型的动态规划问题,设立1个dp list,用于保存当前元素nums[i]跟前面比它小的元素构成的最长序列。

解法1#:动态规划

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        if len(nums) == 1:
            return 1

        max_len = 0
        dp = [1 for _ in range(len(nums))]
        for i in range(1, len(nums)):
            for j in range(0,i):
                if nums[j] < nums[i]:
                    # 如果nums[j]小于nums[i], 就在dp[j]的基础上+1
                    dp[i] = max(dp[j]+1, dp[i])
            max_len = max(dp[i], max_len)

        return max_len

解法2#:动态规划+二分查找,通过二分法不断插入新元素来寻找最长序列。速度极快

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        if len(nums) == 1:
            return 1
        # 用于临时存放数组序列
        tmp_array = [nums[0]]
        control_num = True
        # 将nums[i]按顺序放到tmp_array的合适位置
        for i in range(1, len(nums)):
            # 如果遇到更小的元素,且tmp_array只有一个元素,直接替换掉
            if nums[i] < tmp_array[0] and control_num:
                tmp_array[0] = nums[i]
            elif nums[i] >= tmp_array[-1]:
                tmp_array.append(nums[i])
                control_num = False
            # 介于最小和最大之间,就用二分法插入
            elif tmp_array[0] < nums[i] < tmp_array[-1]:
                index = self.semiInsert(nums[i], tmp_array, 0, len(tmp_array)-1)

    def semiInsert(self, num, tmp_array, first, last):
        if first > last:
            return -1
        mid = (first+last) // 2
        # 我们需要找到的是介于两个相邻值之间的位置mid
        if tmp_array[mid] > num:
            if num >= tmp_array[mid-1]:
                return mid
            else:
                last = mid-1
        else:
            first  = mid + 1
        return self.semiInsert(num, tmp_array, first, last)

参考:

https://blog.csdn.net/qq_32424059/article/details/88076376

https://blog.csdn.net/wenqiwenqi123/article/details/81327682

https://blog.csdn.net/yingzoe/article/details/88987893

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值