1.题目解析
题目来源:1027.最长递增子序列——力扣
测试用例
2.算法原理
1.状态表示
等差数列至少是三个数,所以一维数组显然无法满足状态表示,所以需要开辟一个二维数组来表示,二维数组的两个下标分别是倒数第一与倒数第二个数
dp[i][j]:倒数第一个位置下标为j,倒数第二个位置下标为i的最长等差子序列的长度
2.状态转移方程
a. 这里需要固定倒数第二个位置来移动倒数第一个位置找到倒数离倒数第二个位置最近的倒数第三个数的位置
b. 为什么需要最近的倒数第三个数字的位置呢,因为如果出现许多重复的数字,当该数字满足等差数列,显然取最后一个位置插入等差数列会使等差数列长度最长
c. a中的遍历方法就是方便取出最近的倒数第三个数字的下标,这里取下标需要逐个遍历,效率很低,不妨将数组中元素与下标绑定插入哈希表,但是直接全部插入哈希表也会效率很低,所以不妨在找到倒数第三个数时动态插入,这样既保证了倒数第三个数一定位于倒数第二个数之前且效率更高
d. 当固定第i个位置遍历完整个数组后将i下标后移,然后将后移前的nums[i]插入哈希表,这样保证哈希表中只有构成等差子序列的元素及其下标
3.初始化
由于我们一开始就确定了等差子序列的最后两个数,所以哪怕没有构成等差子序列那么长度也为2,所以不妨开始就将dp表全部初始化为2
4.填表顺序
固定倒数第二个位置移动倒数第一个数字找到倒数第三个数字,存入哈希表,再将倒数第二个数存入哈希表
5.返回值
返回dp表的最大值
3.实战代码
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;}
};