就离谱,昨天还奶了一口这题要是从子数组改成子序列难度就大了,没想到今天就出来了orz
先看到数组长度1000,没跑了,动态规划 n2 做法。
核心在于,如果确定了两个数,那必然能确定以这两个数为尾部的一条等差数列。我们使用动态规划的思想,从长度为2开始逐步延长,每增加一个新的元素,数列条数要增加的量,即为以这个新元素为末尾元素,之前的所有元素中的一个为倒数第二个元素,所构成的等差数列的数量(这个值我们之前必然已经得到了)。想到这里,我们基本已经可以列出状态转移方程。需要注意的是,等差数列长度至少为3,也就是我们累加答案的数量应该是 dp[j].getOrDefault(diff,0) 。
class Solution {
public int numberOfArithmeticSlices(int[] nums) {
int ans = 0;
int len = nums.length;
// dp[i].get(j) 代表最后一位为i的等差数组,当公差为j的时候,长度>=3的等差数列个数
Map<Long, Integer>[] dp = new Map[len];
for (int i = 0; i < len; i++) {
dp[i] = new HashMap<Long, Integer>();
}
// i是最后一个数的序号
for (int i = 1; i < len; i++) {
// j是倒数第二个数的序号
for (int j = 0; j < i ; j++) {
long diff = 1L * nums[i] - nums [j];
int bef = dp[j].getOrDefault(diff,0);
ans += bef;
dp[i].put(diff,dp[i].getOrDefault(diff,0) + bef + 1);
}
}
return ans;
}
}
看了下面这位大佬的题解后,有了新的思路,他使用了list和map进行预处理,map.get[i]为数组中值为nums[i]的下标连成的链表。然后,通过确定末尾两个数,锁定倒数第三个数的值,然后去map里拿链表,如果链表中有多个数,则累加。
dp[i][j]的i和j就单纯代表最后两个数下标为nums中i和j时的总个数。
链接:https://leetcode-cn.com/problems/arithmetic-slices-ii-subsequence/solution/tong-ge-lai-shua-ti-la-yi-ti-liang-jie-d-404p/