一道有趣的最长子序列问题

article/2025/9/28 10:08:15

一道有趣的最长子序列问题 – 潘登同学的金融经济学笔记

文章目录

    • 一道有趣的最长子序列问题 -- 潘登同学的金融经济学笔记
  • 来源
  • 求解
    • 递推公式
    • 算法实现

来源

前几天在刷视频的时候,发现了这样一道题

在这里插入图片描述

所谓子序列就是一个序列 a i 1 , a i 2 , ⋯ , a i n a_{i1},a_{i2},\cdots,a_{in} ai1,ai2,,ain满足 i 1 < i 2 < ⋯ < i n i1< i2 < \cdots < in i1<i2<<in,并不要求 i 1 , i 2 , ⋯ , i n i1,i2,\cdots,in i1,i2,,in是紧邻的,只要求下标单调递增即可;

一个具体例子:

  • 一个序列 1 , 5 , 2 , 4 , 3 1,5,2,4,3 1,5,2,4,3
  • 其中存在单调递增子序列 { 1 , 5 } , { 1 , 2 , 4 } , { 1 , 2 , 3 } , { 2 , 3 } \{1,5\},\{1,2,4\},\{1,2,3\},\{2,3\} {1,5},{1,2,4},{1,2,3},{2,3}
  • 其中存在单调递减子序列 { 5 , 2 } , { 5 , 4 } { 5 , 4 , 3 } \{5,2\},\{5,4\}\{5,4,3\} {5,2},{5,4}{5,4,3}

求解

数学证明的方法,显然我是不太会,还请各位大神赐教; 但是基于置信度的解法,我还是会一点滴;

递推公式

用一个记号 ( x , y ) (x,y) (x,y)表示,从某个数开始,x表示从该数开头的最长递增序列,y表示从该数开始最长的递减序列;

从长度为2的序列说起

  • 显然,要么是递增,要么是递减序列

到长度为3的序列

  • 最后一个数的记号 ( 1 , 1 ) (1,1) (1,1)
  • 倒数第二个数的记号
    • 若:倒数第二个数比最后一个数小, 记为 ( 2 , 1 ) (2,1) (2,1)
    • 若:倒数第二个数比最后一个数大, 记为 ( 1 , 2 ) (1,2) (1,2)
  • 倒数第三个数(第一个数)的记号
    • 在倒数第二个数的记号为 ( 2 , 1 ) (2,1) (2,1)的前提下:
      • 若:倒数第三个数比倒数第二个数小, 记为 ( 3 , 1 ) (3,1) (3,1)
      • 若:倒数第三个数比倒数第二个数大, 记为 ( 2 , 2 ) (2,2) (2,2)
    • 在倒数第二个数的记号为 ( 1 , 2 ) (1,2) (1,2)的前提下:
      • 若:倒数第三个数比倒数第二个数小, 记为 ( 2 , 2 ) (2,2) (2,2)
      • 若:倒数第三个数比倒数第二个数大, 记为 ( 1 , 3 ) (1,3) (1,3)

到长度为4的序列(相当于在长度为3的序列前加一个数)

  • 倒数第三个数记号为 ( 3 , 1 ) (3,1) (3,1)

    • 若倒数第四个数比倒数第三个数小,记为 ( 4 , 1 ) (4,1) (4,1)
    • 若倒数第四个数比倒数第三个数大,记为 ( 3 , 2 ) (3,2) (3,2)
  • 倒数第三个数记号为 ( 2 , 2 ) (2,2) (2,2),因为 ( 2 , 2 ) (2,2) (2,2)有两种情况

    • 第一种情况,在倒数第二个数的记号为 ( 2 , 1 ) (2,1) (2,1)且倒数第三个数比倒数第二个数大
      • 若倒数第四个数比倒数第三个数小且比倒数第二个数小,记为 ( 3 , 2 ) (3,2) (3,2)

      • 若倒数第四个数比倒数第三个数小且比倒数第二个数大,记为 ( 2 , 2 ) (2,2) (2,2)
        在这里插入图片描述

      • 若倒数第四个数比倒数第三个数大,记为 ( 2 , 3 ) (2,3) (2,3)

    • 第二种情况,在倒数第二个数的记号为 ( 1 , 2 ) (1,2) (1,2)且倒数第三个数比倒数第二个数小
      • 若倒数第四个数比倒数第三个数小,记为 ( 3 , 2 ) (3,2) (3,2)
      • 若倒数第四个数比倒数第三个数大且比倒数第二个数小,记为 ( 2 , 2 ) (2,2) (2,2)
      • 若倒数第四个数比倒数第三个数大且比倒数第二个数大,记为 ( 2 , 3 ) (2,3) (2,3)
        在这里插入图片描述
  • 倒数第三个数记号为 ( 1 , 3 ) (1,3) (1,3)

    • 若倒数第四个数比倒数第三个数小,记为 ( 2 , 3 ) (2,3) (2,3)
    • 若倒数第四个数比倒数第三个数大,记为 ( 1 , 4 ) (1,4) (1,4)

当然了,这样的递推能无限进行下去,但是我们还是想从中找到规律,当序列比较短(2,3左右)的时候,我们似乎只需要比较这个数与后一个数的大小关系,一旦序列变长了之后,我们不仅需要比较这个数与下一个数的大小关系,还需要比较这个数与后两个数的大小关系,而且还是有时候需要比较而有时又无需比较,我们需要总结一个递推式;我们将目光放到我们的记号 ( x , y ) (x,y) (x,y)上;

  • 对一个数来说,x表示从该数开头的最长递增序列,y表示从该数开始最长的递减序列;
    • 从这个数往后找,如果这个数小于找到的下一个数,那么自然能将记号x加一,表述为数学语言
      ∀ a i , ∃ a i + k , 若 a i < a i + k x i ≥ x i + k + 1 \forall a_i, \exist a_{i+k},若 a_i < a_{i+k} \\ x_i \geq x_{i+k} + 1 ai,ai+k,ai<ai+kxixi+k+1
    • 所以关键是要找到这个数往后大于该数的数的最大的记号x和这个数往后小于该数的数的最大记号y

那么很自然地,我们就去对这个数与其后的数进行比大小,就能确定该数的记号;那么对每个数都与后面的数比一次,粗略来看算法复杂度就是 O ( n 2 ) O(n^2) O(n2)

算法实现

import random
num = 4
a = [random.randint(0,400) for _ in range(num)]
print('数据len:',len(a))
print(a)dp_x = [1 for _ in range(num)] # 记号(x,y)
dp_y = [1 for _ in range(num)] # 记号(x,y)
for i in range(num):index = num-1 - i # 表示现在这个数的索引for j in range(index+1,num):# 表示找到了目前为止最大的xif a[index] <= a[j] and dp_x[index] <= dp_x[j]:dp_x[index] = dp_x[j] + 1# 表示找到了目前为止最大的yif a[index] >= a[j] and dp_y[index] <= dp_y[j]:dp_y[index] = dp_y[j] + 1print('最长递增子序列的长度为:',max(dp_x))
print('最长递减子序列的长度为:',max(dp_y))

算法非常简单啊, 非常长的序列我们很难验证,但是验证长度为4的序列就足够了,下面是几次运行的结果,能看出与我们的分析是一致的

在这里插入图片描述

接着我们来计算序列为300长度的最长子序列

import random
for _ in range(1000):result = []num = 300a = [random.randint(0,1000) for _ in range(num)]# print('数据len:',len(a))# print(a)dp_x = [1 for _ in range(num)] # 记号(x,y)dp_y = [1 for _ in range(num)] # 记号(x,y)for i in range(num):index = num-1 - i # 表示现在这个数的索引for j in range(index+1,num):# 表示找到了目前为止最大的xif a[index] <= a[j] and dp_x[index] <= dp_x[j]:dp_x[index] = dp_x[j] + 1# 表示找到了目前为止最大的yif a[index] >= a[j] and dp_y[index] <= dp_y[j]:dp_y[index] = dp_y[j] + 1# print('最长递增子序列的长度为:',max(dp_x))# print('最长递减子序列的长度为:',max(dp_y))result.append(max(dp_x))result.append(max(dp_y))
print('1000次循环中,300长度的序列中最短的最长子序列的长度为:',min(result))

在这里插入图片描述

显然经过1000次的模拟,得到的最短的最长子序列也是27,所以有99.99%的把握认为能找到一个长度为17的单调子序列;


http://chatgpt.dhexx.cn/article/14vuYumv.shtml

相关文章

最长子序列最长子串的题型汇总

1.最长公共子序列的长度 题目&#xff1a;对于两个字符串&#xff0c;请设计一个高效算法&#xff0c;求他们的最长公共子序列的长度&#xff0c;这里的最长公共子序列定义为有两个序列U1,U2,U3...Un和V1,V2,V3...Vn,其中Ui&ltUi1&#xff0c;Vi&ltVi1。且A[Ui] B[Vi…

动态规划解最长子序列问题

动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题&#xff0c;而会分解出一系列的子问题。简单地采用把大问题分解成子问题&#xff0c;并综合子问题的解导出大问题的解的方法&#xff0c;问题求解耗时会按问题规模呈幂级数增加。 为了节约重复求相同子问题的时间&…

最长****子序列

&#xff08;在研读大佬写的博客后&#xff0c;打算记录下自己学习过程&#xff09; 通过最长上升子序列的拓展了解到&#xff0c;其实这是一个系列的问题主要代表有&#xff1a; 1 最长上升子序列 2 最长不上升子序列 3 最长下降子序列 4 最长不下降子序列 就以最长上升子…

最长公共子序列

最长公共子序列&#xff08;Longest Common Subsequence&#xff0c;简称 LCS&#xff09;是一道非常经典的面试题目&#xff0c;因为它的解法是典型的二维动态规划&#xff0c;大部分比较困难的字符串问题都和这个问题一个套路&#xff0c;比如说编辑距离。而且&#xff0c;这…

最长公共子序列(LCS) 过程图解

1.基本概念 首先需要科普一下&#xff0c;最长公共子序列&#xff08;longest common sequence&#xff09;和最长公共子串&#xff08;longest common substring&#xff09;不是一回事儿。什么是子序列呢&#xff1f;即一个给定的序列的子序列&#xff0c;就是将给定序列中零…

最长子序列问题详解

提到最长子序列问题&#xff0c;想必大家都不陌生&#xff0c;今天我主要想分享一下我对子序列问题的一些理解&#xff1a; 先拿最长上升子序列问题来说吧&#xff1a; 很明显这是一个动态规化问题&#xff0c;仔细想想也不难得出其状态转移方程 首先介绍一下dp[]数组的含义…

如何查看pip版本

Windows系统如何查看pip版本 直接运行pip show pip

python之pip版本问题

我们在默认安装python软件之后&#xff0c;其自行安装的pip的版本可能比较落后。我们使用pip安装模块的时候经常提示安装失败&#xff0c;查看安装失败原因&#xff0c;部分是因为pip不是最新版本需要升级版本才能继续安装&#xff0c;因此写下一点小心得&#xff0c;让我们都能…

pip 查看可安装版本

pip 查看可安装版本 pip版本&#xff1a; pip -V pip 20.1.1 from /usr/lib/python2.7/site-packages/pip (python 2.7) 查看pip可安装版本 import pip._internal.utils.compatibility_tags print(pip._internal.utils.compatibility_tags.get_supported())

python如何查看pip版本并且升级pip

第一次写Python的学习经历 我之前也安装过Python,今天&#xff0c;终于重新安装了64位的windows的Python,于是在命令行输入&#xff1a;“pip list”出现以下的提示&#xff1a; 这个提示以前也出现过&#xff0c;但是看不懂&#xff0c;也不知道怎么处理&#xff0c;然后又胡…

python pip 查找指定安装包版本信息

一、windows操作系统 pip list | findstr 查找的包&#xff08;支持模糊查询&#xff09;例&#xff1a; pip list | findstr huawei结果&#xff1a; 二、linux操作系统 pip list | grep 查找的包&#xff08;支持模糊查询&#xff09;

更新pip版本

更新pip版本 从报错来看是因为pip版本为20.2.3&#xff0c;但当前可用版本是21.0.1 python -m ensurepippython -m pip install --upgrade pippip list设置镜像默认源 #临时使用 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package #设置默认源 pip inst…

拉取的docker镜像中更换python以及pip版本

场景&#xff1a; 需要tensorflow1.10 python3.6 的环境&#xff0c;但是拉取的tf1.10镜像中&#xff0c;默认python版本是3.5 &#xff0c;此时我们需要安装python3.6版本&#xff0c;将python命令的软连接删除&#xff0c;并且指向新安装的3.6&#xff0c;且pip的连接也应该…

Python查看所有版本及pip

1、查看python默认版本&#xff1a; python --version &#xff08;默认的版本我改为了python3&#xff0c;所以结果是3.7的&#xff09; 2、查看另外安装的2.7的版本&#xff1a; python2.7 --version 3、查看python安装路径&#xff1a; 1&#xff09;终端输入python2.7回…

python降低pip版本

场景&#xff1a; 使用Pycharm开发时&#xff0c;经常会遇到因为pip版本过高而导致下载第三方库失败的情况 解决方案&#xff1a; 经查资料&#xff0c;发现可以通过降低pip的版本来解决问题 如下&#xff1a; 第一种方法&#xff1a;使用Terminal命令行进行降级 python -m pip…

Linux查看pip版本号的命令,pip 经常使用命令及控制台怎么查看python 及pip 和已安装包版本号...

在使用python的时候&#xff0c;常常使用到pip这个工具&#xff0c;能够很方便的线上安装依赖库&#xff0c;固然pip还有不少参数均可以帮咱们去查询一些库信息&#xff0c;在安装python的时候&#xff0c;下载带有pip的安装包就能够直接安装pip啦&#xff0c;固然没有带pip的&…

查看pip版本 及升级pip命令报错解决办法

pip install pytest_ordering时警告&#xff0c;pip版本过低 WARNING: You are using pip version 21.1.3; however, version 21.2.4 is available. You should consider upgrading 1、查看pip&#xff1a; pip show pip 2、升级pip&#xff1a;python -m pip install --upg…

最新升级pip命令,查看pip版本命令,pycharm升级pip命令,推荐收藏关注不迷路

1. 查看pip版本命令&#xff1a;pip -V &#xff0c;可以看看以下代码运行完过后&#xff0c;自己的pip版本有没有升级成功 python升级pip命令&#xff1a;打开命令行输入 python -m pip install -U pip 回车 pycharm升级pip命令 &#xff1a;打开命令行输入&#xff1a; py…

[Python]pip查找包的历史版本

pip查找包的历史版本 场景&#xff1a;在一些时候通过pip install xxx 安装第三方库的时候默认情况下安装最新版本&#xff0c;由于是最新版本有个稳定性就不得不考虑其中&#xff0c;所以部分场景会存在一些bug这就要求我们安装历史版本&#xff0c;对一些更新频率比较高的三…