LeetCode:300. 最长上升子序列(python)

LeetCode:300. 最长上升子序列(python)

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:

  • 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
  • 你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

LeetCode 链接

思路1:动态规划
  • 确定状态和选择
    • 状态:序列 0~i,最终状态为序列 0~n-1n 为序列的长度,则用 dp[i] 记录当前位置 i 处的最长上升子序列的长度。
    • 选择:计算 dp[i] ,若 nums[i]>nums[j]0<=j<i,则判断 dp[j]+1 大于 dp[i],若是则更新 dp[i]。因此有 i-1 种选择,需要通过两次遍历求解,时间复杂度为 O ( n 2 ) O(n^2) O(n2)
附代码1(Python3):
class Solution:
    def lengthOfLIS(self, nums):
        if not nums: 
            return 0
        
        n, res = len(nums), 1    # 序列长度和初始化最长上升子序列长度
        dp = [1]*n               # 初始化 dp
        for i in range(1, n):
            for j in range(i):
                if nums[i] > nums[j]:
                    dp[i] = max(dp[i], dp[j]+1)    # 更新 dp
            res = max(res, dp[i])                  # 更新最长上升子序列长度
        return res
test = Solution()
nums = [10,9,2,5,3,7,101,18]
test.lengthOfLIS(nums)
4
思路2:二分法求解
  • 按顺序将序列 0~n-1 的值插入到数组的尾端,数组要求从大到小排序,若无法插入,则添加一个包含该值的新数组;遍历结束后,数组的个数即为最长上升子序列的长度
  • 通过二分法查找合适的插入位置,比较当前值与每个数组的尾端的值大小
  • 整体时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
附代码2(Python3):
class Solution:
    def lengthOfLIS(self, nums):
        if not nums:
            return 0
        
        top = []                           # 整体数组
        for i in range(len(nums)):
            # 二分查找插入数组
            left, right = 0, len(top)-1    # 左右边界索引
            while left <= right:          
                mid = (left+right)//2      # 左中位数
                if top[mid][-1] < nums[i]:
                    left = mid+1
                else:
                    right = mid-1
            # 若 left 等于数组的个数,则需要添加新数组;否则,在 left 数组尾部添加新值
            if left == len(top):
                top.append([nums[i]])
            else:
                top[left].append(nums[i])
        return len(top)
test = Solution()
nums = [10,9,2,5,3,7,101,18]
test.lengthOfLIS(nums)
4
思路4:二分法求解优化
  • 二分法查找数组时只需要查看数组的最后一个值,并不需要记录数组的所有值,只需要将最后一个值记录即可,因此用一维数组代替整体数组(二维数组)。
附代码4(Python):
class Solution:
    def lengthOfLIS(self, nums):
        if not nums:
            return 0
        
        top = []                           
        for i in range(len(nums)):
            # 二分查找
            left, right = 0, len(top)-1    # 左右边界索引
            while left <= right:          
                mid = (left+right)//2      # 左中位数
                if top[mid] < nums[i]:
                    left = mid+1
                else:
                    right = mid-1
            # 若 left 等于数组长度,则需要添加新值;否则,在 left 位置的值覆盖为新值
            if left == len(top):
                top.append(nums[i])
            else:
                top[left] = nums[i]
        return len(top)
test = Solution()
nums = [10,9,2,5,3,7,101,18]
test.lengthOfLIS(nums)
4

参考:

LeetCode 题解

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值