LeetCode300. 最长上升子序列

本文为打卡刷Leetcode题系列文章, 这个系列文章的目录都是按照如下四个部分构成

  • 题目链接
  • 题目描述
  • 代码初步
    这部分写的是我在刷题过程中的思路,相信在拿到题目就立马参考大神们的思路写代码是不会有进步的,我思故我在,思考让我进步!!
  • 代码欣赏
    这一部分po出优秀的解题答案,这里我们可以学习大神们的解题思路,进而内化成自己的。

题目链接

https://leetcode-cn.com/problems/longest-increasing-subsequence/

题目描述

在这里插入图片描述

代码初步

在拿到这个题目时,想到了要用到动态规划。动态规划最重要的是怎么划分状态,一开始我只是想保存并不断更新最长上升子序列的值,但没想出来要如何更新。

后面参考了leetcode讨论区大神的解题思路,才发现其实可以通过记录前面每位数上的最长上升子序列,来求得当前位上的最长上升子序列。

pol一下代码:

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums:
            return 0
        n = len(nums)
        dp = [1] * n

        for i in range(n):
            for j in range(i):
                if nums[j] < nums[i]:
                	# 这里取max的原因是因为可能存在前面的几位最长上升子序列的长度相等,并且当前位都大于它们
                    dp[i] = max(dp[i], dp[j]+1)
                else:
                    continue
        return max(dp)

在这里插入图片描述

用到的数据结构与算法:

动态规划是数据结构与算法中必须要掌握的一门算法。但是也不要把它想得很高深。

动态规划的过程:把问题的求解过程分成N个阶段,每个阶段会生成一个状态,用数组保存这些个状态值,最后通过这个保存状态值的数组来求解的过程。

比如这一题的每个状态就是假设数组中总共有N个数,那么遍历数组,求得到第i个数字的时候包含的最长升子序列的个数,保存在另一个新数组里。

代码欣赏

  • 时间复杂度改进:你能把代码的时间复杂度提升到O(NlogN),这里看到对数立马想到了二分查找。
  • 代码思路: 贪心算法 + 二分查找
    贪心法: 向着事情发展最有利的方向前进
  • 算法流程:
  1. 维护一个数组dp, 使整个列表维护着一个排序列表。最长子序列就为数组dp的长度
  2. 从给定的原数组中依次取出值nums[i],与dp[-1]作比较,
  • 此时会出现两种情况,当nums[i]比dp[-1]大时, 将nums[i]直接添加在dp末尾
  • 当nums[i] 比dp[-1]小时,需要找到dp中第一个比nums[i]大的数,然后将其替换为nums[i],始终保持dp中元素最小,求得最长子序列就越长。

为什么始终保持dp中元素最小,求得最长子序列就越长?

设常量数字 N,和随机数字 x,我们可以容易推出:当 N 越小时,N<x 的几率越大。例如: N=0 肯定比 N=1000更可能满足 N<x.

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        dp = []
        for n in nums:
            if not dp or n>dp[-1]:
                dp.append(n)
            else:
                l, r = 0, len(dp) - 1
                # 二分法查找dp数组中第一个比nums[i]大的数,替换
                while l <= r:
                    mid = l + (r-l)//2
                    if n > dp[mid]:
                        l = mid + 1
                    else:
                        r = mid - 1
                dp[l] = n
        return len(dp)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值