这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
446. 等差数列划分 II - 子序列
给你一个整数数组 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 整数。
- 示例 1:
输入:nums = [2,4,6,8,10] 输出:7 解释:所有的等差子序列为: [2,4,6] [4,6,8] [6,8,10] [2,4,6,8] [4,6,8,10] [2,4,6,8,10] [2,6,10]
- 示例 2:
输入:nums = [7,7,7,7,7] 输出:16 解释:数组中的任意子序列都是等差子序列。
提示:
1 <= nums.length <= 1000
解题思路
数组含义:
dp[i][d]代表以下标i结尾,公差为d的子序列个数,因为这题的公差可能会出现溢出,并且公差过大的问题,所以不直接采用数组来存储,而是使用map。
状态转移
- d=nums[i]-nunms[j]
- dp[i][d]+=dp[j][d]+1
使用二重循环,遍历i,j。将nums[i] 和 nums[j] 分别当作等差数列的尾项和倒数第二项。使用map存储公差d和子序列个数的关系。
由于题目要统计的等差子序列至少有三个元素,上面二重循环,其中「将 nums[i] 加到以nums[j] 为尾项,公差为 d 的弱差子序列的末尾」这一操作,实际上就构成了一个至少有三个元素的等差子序列,因此我们将循环中的 dp[j][d] 累加,即为答案
代码
class Solution {
public int numberOfArithmeticSlices(int[] nums) {
int n=nums.length,res=0;
HashMap<Long,Integer>[] dp=new HashMap[n];
for (int i = 0; i < n; i++) {
dp[i]=new HashMap<>();
}
for (int i=0;i<n;i++)
for (int j=0;j<i;j++)
{
long d=(long)nums[i]-(long)nums[j];
int pre=dp[j].getOrDefault(d,0);
res+=pre;
dp[i].put(d,pre+dp[i].getOrDefault(d,0)+1);
}
return res;
}
}