先写出几个来看看,找找规律:
A = {1,2,3,4,5,6,7}
新建一个数组res,res[i]保存0~i这些数里的等差数列个数,那么:
res[0] = 0;
res[1] = 0;
res[2] = {1,2,3}
res[3] = {1,2,3} + {2,3,4} + {1,2,3,4}
res[4] = {1,2,3} + {2,3,4} + {1,2,3,4} + {3,4,5} + {2,3,4,5} + {1,2,3,4,5}
...
可以发现,res[i]是res[i - 1]的结果加上包含了A[i]的等差数列个数。那就很好求了:
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
if(A.size() < 3)
return 0;
vector<int> res(A.size(), 0);
for(int i = 2; i < A.size(); ++i)
{
res[i] = res[i - 1] + countArithmic(A, 0, i);
}
return res[A.size() - 1];
}
int countArithmic(vector<int>& A, int start, int end) //包含A[end]的等差数列个数,就是由A[end]一位一位往前找,遇到不能构成等差数列的就break
{
if(end - start + 1 < 3)
return 0;
int cha = A[end] - A[end - 1];
int res = 0;
for(int i = end - 1; i > start; --i)
{
if(A[i] - A[i - 1] == cha)
res++;
else
break;
}
return res;
}
};
但是!这样还是太麻烦,还可以简化的。countArithmic这个函数,往前一个一个的找,这样会有很多重复计算,但是显然,如果A[i]能和前面的两个数构成等差数列,那么也能和他们前面的数构成等差数列。如
1,2,3,4,5
4能和1,2,3构成等差数列,5能和3,4构成等差数列,那么5也能和3,4前面的构成等差数列。所以以5结尾的等差数列是以4结尾的等差数列加上{3,4,5}。
所以代码可以改进成这样:设置一个dp数组,dp[i]存的是以[i]结尾的等差数列个数,那么dp[i] = dp[i - 1] + 1;
class Solution {
// 2nd round date: 2016-10-15 location: Vista Del Lago III Apartement
public:
int numberOfArithmeticSlices(vector<int>& A) {
if (A.size() < 3) return 0;
vector<int> dp(A.size(), 0);
int res = 0;
for (int i = 2; i < A.size(); i ++) {
if (A[i] - A[i - 1] == A[i - 1] - A[i - 2])
dp[i] = dp[i - 1] + 1;
res += dp[i];
}
return res;
}
};