文章目录

  • 题目介绍
  • 题解1:往回遍历
  • 题解2:二分查找


题目介绍

  • 原题链接:NC163 最长上升子序列(一)
  • 描述
    给定一个长度为 n 的数组 arr,求它的最长严格上升子序列的长度
    所谓子序列,指一个数组删掉一些数(也可以不删)之后,形成的新数组。例如 [1,5,3,7,3] 数组,其子序列有:[1,3,3]、[7] 等。但 [1,6]、[1,3,5] 则不是它的子序列
    我们定义一个序列是 严格上升 的,当且仅当该序列不存在两个下标i和j满足 i<ji<j 且python如何实现一个递增的列表 python求最长递增子序列_python如何实现一个递增的列表
  • 数据范围: python如何实现一个递增的列表 python求最长递增子序列_python如何实现一个递增的列表_02
  • 要求:时间复杂度python如何实现一个递增的列表 python求最长递增子序列_Python3_03, 空间复杂度python如何实现一个递增的列表 python求最长递增子序列_动态规划_04
  • 示例1
    输入:
[6,3,1,5,2,3,7]
  • 返回值:
4
  • 说明:该数组最长上升子序列为 [1,2,3,7] ,长度为4

题解1:往回遍历

建议新手白脖子先看视频教程:【小鱼老师算法题】python讲解动态规划思想的最长递增子序列问题 另外我的题解是为了方便在本地IDE进行调试,所以没有新建类,而是使用exec函数

li = []
exec('li=' + input())
dp = [1] * len(li)
for i in range(1, len(li)):
    for j in range(i):
        if li[i] > li[j]:
            dp[i] = max(dp[i], dp[j]+1)
print(max(dp) if li else 0)

python如何实现一个递增的列表 python求最长递增子序列_Python3_05

  • 知识点:动态规划
    动态规划算法的基本思想是:将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果
  • 思路:
    要找到最长的递增子序列长度,每当我们找到一个位置,它是继续递增的子序列还是不是,它选择前面哪一处接着才能达到最长的递增子序列,这类有状态转移的问题常用方法是动态规划
  • 具体做法:
    step 1:用dp[i]表示到元素i结尾时,最长的子序列的长度,初始化为1,因为只有数组有元素,至少有一个算是递增
    step 2:第一层遍历数组每个位置,得到n个长度的子数组
    step 3:第二层遍历相应子数组求对应到元素i结尾时的最长递增序列长度,期间维护最大值
    step 4:对于每一个到iii结尾的子数组,如果遍历过程中遇到元素j小于结尾元素,说明以该元素结尾的子序列加上子数组末尾元素也是严格递增的,因此转移方程为python如何实现一个递增的列表 python求最长递增子序列_Python3_06
  • 图示:

题解2:二分查找

dp[i]表示从左至右到原序列第i个元素的最长递增子序列的长度,从第i个元素往回遍历更新dp[i]的值。由于每个元素都需要往回遍历一次,时间复杂度是python如何实现一个递增的列表 python求最长递增子序列_Python3_07。往回遍历如何更新dp[i]的值在题解1中已有很好的介绍,这里主要写用二分法代替往回遍历的过程,时间复杂度是python如何实现一个递增的列表 python求最长递增子序列_动态规划_08

二分法的过程为:首先创建数组arr=[ele_1],ele_1是原序列第一个元素,然后从第二个元素开始从左至右遍历原序列

  1. 如果ele_i > max(arr),将ele_i加到arr最后
  2. 如果ele_i <= max(arr),用二分法找到arr中第一个比ele_i大(或相等)的元素并用ele_i替换

遍历完成后arr的长度即为最长递增子序列的长度(但arr不是最长递增子序列)。第二步替换是因为遍历到的元素可能会有比ele_i大但比替换元素小的元素,比如原序列为[2,5,8,3,4,6]。

import bisect

li = []
exec('li=' + input())
if not li:
    print(0)
    exit()
dp = [1] * len(li)
sorted_list = [li[0]]
for i in range(1, len(li)):
    if li[i] > sorted_list[-1]:
        sorted_list.append(li[i])
        dp[i] = len(sorted_list)
    else:
        position = bisect.bisect_left(sorted_list, li[i])
        sorted_list[position] = li[i]
        dp[i] = position+1
print(max(dp))