给你一个整数数组 nums
,返回 nums
中所有 等差子序列 的数目。
如果一个序列中 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该序列为等差序列。
- 例如,
[1, 3, 5, 7, 9]
、[7, 7, 7, 7]
和[3, -1, -5, -9]
都是等差序列。 - 再例如,
[1, 1, 2, 5, 7]
不是等差序列。
数组中的子序列是从数组中删除一些元素(也可能不删除)得到的一个序列。
- 例如,
[2,5,10]
是[1,2,1,
2,4,1,
5,
10]
的一个子序列。
题目数据保证答案是一个 32-bit 整数。
思路:
首先,本道题要求的是所有可能的子序列的数目,要注意此时子序列可以重复出现,因为是友不同位置的同一元素构成的,比如:{5,5,10,15},可以构成两个子序列{5,10,15},{5,10,15},不同点在于用的5来自不同下标。
再者,对于所求的数量与前面所求数量有所关联的题,往往会出现dp[i]=dp[j]+1,这里的加一是指会额外多出一种可能,dp[j]表示在原本所有j位置构成的字串加上i位置仍是字串,因此数量不变。
对于本题,由于在找前面符合条件的字串时,涉及到了前面字串的具体构成(因为构成字串最少需要三个元素),因此需要用多维数组表示。dp[i][j]表示i位置数据在前,j位置数据在后,在加上i之前的元素构成子序列,符合条件的数值是2*num[i]-num[j](因为是等差数列)。然后,由于可以出现重复的子序列,因此对于i位置之前所有符合数值的下标都需要进行加上。
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
int n=nums.size();
vector<vector<int>>dp(n,vector<int>(n));
unordered_map<long long,vector<int>>hash;
int sum=0;
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
long long a=(long long)2*nums[i]-nums[j];
if(hash.count(a))
{
for(auto k:hash[a])
if(k<i)
{
dp[i][j]+=dp[k][i]+1;
}
}
sum+=dp[i][j];
}
hash[nums[i]].push_back(i);
}
return sum;
}
};