446. Arithmetic Slices II - Subsequence
difference between any two consecutive elements is the same.
For example, these are arithmetic sequences:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
The following sequence is not arithmetic.
1, 1, 2, 5, 7
A zero-indexed array A consisting of N numbers is given. A subsequence slice of that array is any sequence of integers (P0, P1, …, Pk) such that 0 ≤ P0 < P1 < … < Pk < N.
A subsequence slice (P0, P1, …, Pk) of array A is called arithmetic if the sequence A[P0], A[P1], …, A[Pk-1], A[Pk] is arithmetic. In particular, this means that k ≥ 2.
The function should return the number of arithmetic subsequence slices in the array A.
The input contains N integers. Every integer is in the range of -231 and 231-1 and 0 ≤ N ≤ 1000. The output is guaranteed to be less than 231-1.
Example:
Input: [2, 4, 6, 8, 10]
Output: 7
Explanation:
All arithmetic subsequence slices are:
[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]
方法1: dynamic programming
grandynag: https://www.cnblogs.com/grandyang/p/6057934.html
思路:
这道题有一点像之前的frog jump,因为dp的转移式需要根据和上一个数的差值来遍历一个hashmap查找。这道题还需要遍历当前dp位置之前的所有数字,计算两数差值,并且在j中查找有没有这个diff。如果有的话,说明之前至少有两个数字形成了相同diff的sequence,那么现在的第三个数使得新的等差数列成立,dp[j][diff]应该被计入res。同时,这个数字应该被叠加至diff[i][diff]。注意是叠加不是diff[j][diff]:举个栗子,j = 2, dp[j][2] = 2, 分别为[2, 4, 6], [4, 6],dp[j][4] = 1, [2, 6],那么新的8会在此基础上产生什么样的改变?首先[2, 4, 6], [4, 6]被变成[2, 4, 6, 8]和[4, 6, 8],dp[i][2] += dp[j][2],同时,A[j]和A[i]本身形成了新的一对弱等差数列,因此再dp[i][diff] ++。当dp[j][diff]不存在时,这两个操作都加0,对结果没什么影响,所以overall, 转移式可以非常简单的表示为++dp[i][diff] = dp[j][diff]。这里的test case会有差值非常大的数字,比如接近int max和int min的两个数字连在一起,那么差值就会溢出整型范围。这里把difff暂时保存为long,先和整型范围比较一下,如果大于int max或小于int min, 由于题目规定了数字都是整型范围内的,因此不可能出现三个数字等差直接continue。否则需要再把difff换回整型,继续上面的做法。
易错点:
- (long) (A[i] - A[j]) 是没用的:(long) A[i] - A[j]才可以因为两个数字都是int的话,默认用int类中间值过度,还是会溢出,必须把其中一个变成long,才会默认用long过度。
Complexity
Time complexity: O(n^2)
Space complexity: O(n ^ 2)
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
int res = 0;
vector<unordered_map<int, int>> hash(A.size());
for (int i = 0; i < A.size(); i++) {
for (int j = 0; j < i; j++) {
long difff = (long) A[i] - A[j];
if (difff > INT_MAX || difff < INT_MIN) continue;
int diff = (int) difff;
// hash[i][diff] = hash[j][diff] + 1;
// if (hash[i][diff] >= 2) {
// res += hash[j][diff];
// }
if (hash[j].count(diff)) {
res += hash[j][diff];
}
++hash[i][diff] += hash[j][diff];
}
}
return res;
}
};