当前位置: 首页 > news >正文

子序列问题

文章目录

  • 300. 最长递增子序列
  • 376. 摆动序列
  • 673. 最长递增子序列的个数
  • 646. 最长数对链
  • 1218. 最长定差子序列
  • 873. 最长的斐波那契子序列的长度
  • 1027. 最长等差数列
  • 446. 等差数列划分 II - 子序列

300. 最长递增子序列

题目链接

在这里插入图片描述
子序列的性质:不连续
子数组/子串:连续

状态表示:dp[i]:以i为结尾的数组的所有子序列中,最长递增子序列的长度。

状态转移方程:
核心逻辑是:对于每个 i(当前元素),通过遍历它之前的所有元素 j(j < i),判断能否通过 j 对应的子序列延长出更长的子序列。

转移条件:
当 nums[i] > nums[j] 时(即当前元素大于前序元素,满足 “递增” 条件),说明可以将 nums[i] 接在 “以 nums[j] 结尾的子序列” 后面,形成一个更长的子序列。此时,该新子序列的长度为 dp[j] + 1(dp[j] 是前序子序列的长度,加 1 是因为新增了 nums[i])。

class Solution {
public:int lengthOfLIS(vector<int>& nums) {int n=nums.size();vector<int>dp(n,1);int ret=1;for(int i=1;i<n;i++){
for(int j=0;j<i;j++)
if(nums[i]>nums[j])dp[i]=max(dp[i],1+dp[j]);ret=max(ret,dp[i]);}
return ret;}
};

376. 摆动序列

题目链接

在这里插入图片描述
在这里插入图片描述
根据题意,要找正负交替的子序列的最大长度。
先看看如何才能正负交替,下一个数比上一个数大–》为正。下比上小–》为负。所以我们要找的就是 一组 递增-》递减-》递增-》递减 这样的摆动的数。

和子数组专题里的”湍流数组“一样。

我们可以总结一下,像这种 具有 “二元对立属性” 题,一般都是要两个dp去表示 这两个对立的属性(这里是 数据的方向,向上/向下 (递增/递减)。像子数组专题里还有求 ”乘积最大“ ”乘积为正数“的子数组,二元对立就是 正 和 负)。然后再相互依赖推导转移方程。

核心逻辑是:“当前属性 X 的状态,只能由前序对立属性 Y 的状态转移而来”。

回到这题。我们了解到具体的方法后,直接状态表示就行。

  • f[i]:以 nums[i] 为结尾的最长摆动子序列中,最后一步是 “递增”(即 nums[i] 大于前一个元素)的序列长度。
  • g[i]:以 nums[i] 为结尾的最长摆动子序列中,最后一步是 “递减”(即 nums[i] 小于前一个元素)的序列长度。

然后状态转移方程和子数组有个区别,其实也就是子序列和子数组的区别。
子序列不要求连续,所以对i位置讨论的时候,i的前序子数组 可能是前面的任意位置。只需要再加一层循环去遍历i前的位置,然后判断即可

class Solution {
public:int wiggleMaxLength(vector<int>& nums) {int n=nums.size();vector<int>f(n,1);auto g=f;int ret=1;for(int i=1;i<n;i++){for(int j=0;j<i;j++){if(nums[i]>nums[j])f[i]=max(f[i],g[j]+1);else if(nums[i]<nums[j])g[i]=max(g[i],f[j]+1);}ret=max(ret,max(f[i],g[i]));}return ret;}
};

673. 最长递增子序列的个数

题目链接

在这里插入图片描述
找最长递增子序列我们前面做过了,思路是一样的。
这题只需要再找出个数即可。

分析如何找个数:
count[i]:以i为结尾,递增子序列的个数。

同样根据子序列的特性(不连续),我们知道,前序的递增子序列的结尾是不固定的。但前序递增子序列的长度肯定是 当前所求的长度-1,所以只需要把长度符合的情况累加即可

class Solution {
public:int findNumberOfLIS(vector<int>& nums) {int n=nums.size();vector<int>len(n,1),count(n,1);int maxlen=1,ret=0;for(int i=1;i<n;i++){for(int j=0;j<i;j++){if(nums[i]>nums[j]){if(len[j]+1>len[i]){len[i]=len[j]+1;count[i]=count[j];}else if(len[j]+1==len[i]){count[i]+=count[j];}}}maxlen=max(maxlen,len[i]);}for(int i=0;i<n;i++){if(len[i]==maxlen)ret+=count[i];}return ret;}
};

646. 最长数对链

题目链接

在这里插入图片描述
和前面思路一样,子序列不连续,所以引入j来遍历前i组中符合条件的前序dp。

预处理:提前将对数链按照第一个元素排序,保证所有可能作为当前数对前驱的数对都被包含在遍历范围内(j < i)

class Solution {
public:int findLongestChain(vector<vector<int>>& pairs) {int n=pairs.size();vector<int>dp(n,1);int ret=1;sort(pairs.begin(),pairs.end(),[](const vector<int>&a,const vector<int>&b){return a[0]<b[0];});for(int i=1;i<n;i++){for(int j=0;j<n;j++){if(pairs[i][0]>pairs[j][1])dp[i]=max(dp[i],dp[j]+1);}ret=max(dp[i],ret);}return ret;}
};

1218. 最长定差子序列

题目链接

在这里插入图片描述
需要找到数组中最长的子序列,使得子序列中相邻元素的差等于给定的 difference

用 unordered_map<int, int> hash 存储状态,其中:hash[x] 表示:以值 x 为结尾的、满足 “相邻元素差为 difference” 的最长子序列的长度。

  • 为什么用哈希表?因为子序列的 “前一个元素” 必须是 x - difference(这样 x - (x - difference) = difference,满足等差条件),而哈希表可以快速查询 “x - difference 是否存在” 以及其对应的最长子序列长度,避免了暴力遍历的低效。

  • 初始化逻辑:第一个元素 arr[0] 自身可构成长度为 1 的子序列,因此 hash[arr[0]] = 1。

状态转移方程(hash[arr[i]] 的计算方式)
对于数组中的每个元素 arr[i](记为 x),要计算以 x 为结尾的最长子序列长度,需依赖 “前一个符合条件的元素”:

  • 前一个元素必须是 x - difference(因为 x - (x - difference) = difference,满足等差条件)。
  • 若 x - difference 存在于哈希表中(即之前出现过该值),则以 x 结尾的子序列长度 = 以 x - difference 结尾的子序列长度 + 1(在其基础上新增 x)。
  • 若 x - difference 不存在(即之前没出现过),则 x 自身构成一个子序列,长度为 1(此时 hash[x - difference] 默认为 0,加 1 后为 1)。
class Solution {
public:int longestSubsequence(vector<int>& arr, int difference) {unordered_map<int,int>hash;hash[arr[0]]=1;int ret=1;for(int i=1;i<arr.size();i++){hash[arr[i]]=hash[arr[i]-difference]+1;
ret=max(ret,hash[arr[i]]);}return ret;}
};

873. 最长的斐波那契子序列的长度

题目链接

在这里插入图片描述
一、问题分析

  • 定义:给定严格递增的数组 arr,找出最长的斐波那契子序列的长度。斐波那契子序列需满足:存在下标 i < j < k,使得 arr[i] + arr[j] = arr[k]。
  • 目标:返回最长斐波那契子序列的长度;若不存在(长度不足 3),返回 0。

二、动态规划解法

  1. 状态表示
    dp[i][j]:以 arr[i] 和 arr[j] 为最后两个元素的斐波那契子序列的最长长度(需满足 i < j)。
  2. 状态转移方程
    对于每一对 (i, j)(i < j),假设子序列的前一个元素为 a = arr[j] - arr[i]:
  • 若 a 存在于数组中(通过哈希表快速判断),且 a < arr[i](因数组严格递增,保证 a 的下标 k < i),则:dp[i][j] = dp[k][i] + 1(在以 arr[k] 和 arr[i] 结尾的子序列后,添加 arr[j],长度 + 1)。
  • 若 a 不存在,dp[i][j] 保持初始值 2(仅包含 arr[i] 和 arr[j] 两个元素,不满足 “三个及以上元素” 的斐波那契子序列要求)。
  1. 预处理:哈希表加速查找
    利用数组严格递增的特性,用 unordered_map<int, int> hash 存储「元素值 → 下标」的映射,实现 O(1) 时间判断 “前一个元素 a 是否存在于数组中”。
  2. 初始化
    dp 数组所有元素初始化为 2,因为每一对 (i, j) 至少能构成长度为 2的序列(仅包含 arr[i] 和 arr[j] 两个元素)。
class Solution {
public:int lenLongestFibSubseq(vector<int>& arr) {unordered_map<int,int>hash;int n=arr.size(),res=2;for(int i=0;i<n;i++)hash[arr[i]]=i;vector<vector<int>>dp(n,vector<int>(n,2));
for(int j=2;j<n;j++)
{for(int i=1;i<j;i++){int a=arr[j]-arr[i];if(a<arr[i]&&hash.count(a))dp[i][j]=dp[hash[a]][i]+1;res=max(res,dp[i][j]);}
}
return res<3?0:res;}
};

1027. 最长等差数列

题目链接

在这里插入图片描述
和前面的题一样,不过注意一下等差的表示
nums[j] - nums[i]=nums[i]-nums[k]
故而:nums[k] = 2*nums[i] - nums[j]

class Solution {
public:int longestArithSeqLength(vector<int>& nums) {int n=nums.size();unordered_map<int,int>hash;hash[nums[0]]=0;vector<vector<int>>dp(n,vector<int>(n,2));int ret=2;for(int i=1;i<n;i++){for(int j=i+1;j<n;j++){int a=2*nums[i]-nums[j];if(hash.count(a))dp[i][j]=dp[hash[a]][i]+1;ret=max(ret,dp[i][j]);}hash[nums[i]]=i;}return ret;}
};

446. 等差数列划分 II - 子序列

题目链接

在这里插入图片描述
在这里插入图片描述

dp[i][j] : “以 i, j 为结尾的长度 ≥3 的等差子序列数量”。

统计后累加。

class Solution {
public:
#define ll long longint numberOfArithmeticSlices(vector<int>& nums) {int n=nums.size();int res=0;unordered_map<ll,vector<int>>hash;for(int i=0;i<n;i++)hash[nums[i]].push_back(i);vector<vector<int>>dp(n,vector<int>(n));for(int j=2;j<n;j++){for(int i=1;i<j;i++){auto a=2*(ll)nums[i]-nums[j];if(hash.count(a))for(auto&e:hash[a])if(e<i)dp[i][j]+=dp[e][i]+1;else break;res+=dp[i][j];}}return res;}
};
http://www.dtcms.com/a/495764.html

相关文章:

  • 多模态大模型Ovis2.5核心技术改进点、训练方法
  • 建网站步骤ps临摹图片做网站的图片犯法吗
  • 网站建设服务的具体条件烟台企业网站开发
  • 如何做分公司网站wordpress数据库版本
  • DeviceNet 转 MODBUS TCP:倍福 CX 系列 PLC 与 MES 系统在 SMT 回流焊温度曲线监控的通讯配置案例
  • 湛江企业自助建站全国网站建设公司实力排名
  • Redux和@reduxjs/toolkit同时在Next.js项目中使用
  • 从个人贡献者到团队引领者:测试团队的知识管理与能力建设
  • 机械臂动作捕捉系统选型指南:从需求到方案,NOKOV 度量光学动捕成优选
  • 网站开发标准商务网站的推广方法有哪些
  • 注册网站要百度实名认证安不安全网站建设评审会简报
  • 卷积神经网络中的卷积运算原理
  • Solidity 变量完全指南
  • 流式响应 sse 系统全流程 react + fastapi为例子
  • 好看的创意网站设计渑池县建设局网站
  • 综合电子商务型企业网站网站群管理系统哪个好
  • Windows 11 25H2 重磅更新:锁屏小组件、AI 动作全上线
  • 怎么解决打印机故障问题?使用打印机驱动网就能解决!
  • 计算圆的周长和面积
  • 华艺网站开发唐山seo公司
  • 安徽省水利建设厅官方网站别墅设计
  • PolarDB Supabase 助力 Qoder、Cursor、Bolt.diy 完成 VibeCoding 最后一公里
  • 旅游网站开发指导350模板网
  • Nginx 基本使用和高级用法详解
  • 移位操作符
  • vue3实现两个shp文件同时展示
  • 黄埔企业网站建设东莞住建局电话是多少
  • python+uniapp基于微信小程序的学院设备报修系统
  • 【项目部署】JavaWeb、MavenJavaWeb项目部署至 Tomcat 的实现方式
  • 付费网站搭建如何评价一个网站做的是否好