【算法】【动规】 最长等差数列
2023-12-24 17:57:11
跳转汇总链接
2.7 最长等差数列
给你一个整数数组 nums,返回 nums 中最长等差子序列的长度。
回想一下,nums 的子序列是一个列表 nums[i1], nums[i2], …, nums[ik] ,且 0 <= i1 < i2 < … < ik <= nums.length - 1。
并且如果 seq[i+1] - seq[i]( 0 <= i < seq.length - 1) 的值都相同,那么序列 seq 是等差的。
和 2.6 一样,这道题明显出现了倒数两个数倒推之前所有数的方法,所以状态表示中不免出现 dp[i][j] 样的表达。
进一步解释一下,
设满足要求的子序列中,倒数三个数为 a、b、c,已知 b c,推导 a 是否存在且 a 的下标是否在 b 之前,是本题的解题关键。
分析到这里都和 2.6 差不多,唯一不同的是,本题给出的数据并不是去重的,在找 a 的过程中,可能有多个 a,而我们需要的只是离 i 位置前面最近的一个 a 的下标(这里设 k)。
如果仍然使用 hash 的办法去映射 <元素,元素下标的数组>,如果出现这个元素出现的次数接近 n,k i j 统统遍历后,复杂度就是 n3 了。所以肯定不能这样写。
- 状态表示
- 考虑到两个连续数字才能推导出这一组等差数,又需要我们以 “一个位置为子序列的结尾” 这样的方法去定义状态表示,于是考虑用如下定义:
- dp[i][j] 表示,以 i 位置(倒数第二个数)和 j 位置(最后一个数)为结尾的所有满足等差数列的子序列中,最长的长度是多少
- 状态转移方程
-
首先我们需要填写的是 dp[i][j]
-
其次已知的值是 arr[i] 和 arr[j] 作为等差子序列的结尾
-
设倒数第三个数位置为 k 元素为 a,arr[i] 为 b,arr[j] 为 c,可以分为 a = c - b 是否存在,这两种大情况
a 存在,且 a < b,dp[i][j] = dp[k][i] + 1; a 存在,但 b < a < c,dp[i][j] = 2; a 不存在,dp[i][j] = 2;
-
- 优化
- ?方法一,hash 映射 <元素,元素下标的数组>,已经在一开始分析过了,有一定优化效果但在特殊情况下十分不理想。
- ?方法二,一边填写 dp 表,一边保存离他最近的元素的下标,使用的结构只需要 <元素,下标>
- 初始化
- dp 表所有值都初始化成 2
- 填表顺序
- 为了保证填后面的表时前面的依赖数据是已知的,所以我们需要,保证倒数第二个数字,也就是 i 位置不变的情况下遍历最后一个数字 j。
- 这样才能保证寻找 k 位置的时候是稳定的,才能找到距离 i 位置最近的 a 的位置 k。
- 返回值
- dp 表中的最大值
class Solution {
public:
int longestArithSeqLength(vector<int>& nums) {
int n = nums.size();
int ret = 2;
unordered_map<int, int> hash; // 优化
hash[nums[0]] = 0; // 第一个的数的下标是0
vector<vector<int>>dp(n, vector(n, 2));// 初始化
for(int i = 1; i < n - 1; i++) // 固定倒数第二个数,可以固定 k 位置并填写进 hash 表
{
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;
}
};
🥰如果本文对你有些帮助,欢迎👉 点赞 收藏 关注,你的支持是对作者大大莫大的鼓励!!(????) 若有差错恳请留言指正~~
文章来源:https://blog.csdn.net/m0_67470729/article/details/135134749
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!