1. 题目描述
A sequence of number is called arithmetic if it consists of at least three elements and if the difference between any two consecutive elements is the same.
A zero-indexed array A consisting of N numbers is given. A slice of that array is any pair of integers (P, Q) such that 0 <= P < Q < N.
A slice (P, Q) of array A is called arithmetic if the sequence:
A[P], A[p + 1], …, A[Q - 1], A[Q] is arithmetic. In particular, this means that P + 1 < Q. The function should return the number of arithmetic slices in the array A.
【翻译过来】:题目首先定义了arithmetic的概念:相邻的两个元素的差值相同,这样的数组就是arithmetic的。一定要注意是相邻的这个条件,如果不注意这个条件,会对后面的分析带来很大的困惑。
接着题目给出了一个数组,需要我们求出这个数组包含的arithmetic片段的数目。所谓包含的arithmetic片段,其实就是原数组的若干子集的数目,这些子集需要满足arithmetic的性质即可。
2. 样例
arithmetic的数组:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
非arithmetic的数组:
1, 1, 2, 5, 7
输入输出样例:
A = [1, 2, 3, 4]
return: 3, for 3 arithmetic slices in A: [1, 2, 3], [2, 3, 4] and [1, 2, 3, 4] itself.
3. 分析
判断arithmetic的特性以及子集的数目,很明显的动态规划的题型。经过分析我们知道,所谓arithmetic的片段不过是原数组的相邻的子集而已,我们只要求出原数组下arithmetic的子数组个数既是答案。
因此,我们可以从前两个元素开始判断,计算它们的差值difference,然后循环开始遍历。
这里我们的思路是:每当出现一个新的元素满足差值与difference相同,该部分的子集长度就增长一个,例如:
【上一次arithmetic片段】:
1,3,5
片段是【1,3,5】,counter = 1
【增加一个满足的元素】:
1,3,5,7
片段是【1,3,5】,【1,3,5,7】,【3,5,7】,counter = 1 + 2 = 3
即:当新增的元素满足difference的值,currentCounter一直满足等差数列的增长:1,2,3……。这是因为counterCurrent代表的是以当前新增元素结尾的arithmetic子片段个数。每个新增元素都会产生新的arithmetic子片段,所以总和counter每一次都会加上counterCurrent。
4. 源码
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
if (A.size() <= 2) {
return 0;
}
int counter = 0;
int currentCounter = 0;
int difference = A[0] - A[1];
for (int i = 1; i < (int)A.size() - 1; i++) {
if ((A[i] - A[i+1]) == difference) {
currentCounter++;
}
else {
currentCounter= 0;
difference = A[i] - A[i+1];
}
counter += currentCounter;
}
return counter;
}
};
5. 心得
动态规划的算法比较难想而且理解起来比较吃力,本题主要是currentCounter代表的是当前以新增元素结尾的arithmetic子片段个数。因为每一次新增元素产生的子片段都是新的,总数里面都要加上。