题目描述
如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。
- 例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。
给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。
子数组 是数组中的一个连续序列。
示例一
输入:nums = [1,2,3,4]
输出:3
解释:nums 中有三个子等差数组:[1, 2, 3]、[2, 3, 4] 和 [1,2,3,4] 自身。
示例二
输入:nums = [1]
输出:0
思路
首先,需要找到从0号元素到i号元素的等差数列个数与从0号元素到i-1号元素的等差数列个数的递推关系。如下图所示。
如果觉得上图有点复杂,则在此直接说结论:如果用result[i]表示从0号到i号元素的等差数列数量,则有result[i]=result[i-1]+flag。flag表示的是包含第i号元素的等差数列个数。举例:
当i=2,由于result[i-1]=0,flag=1(即图中蓝线),因此result[i]=0+1=1
当i=3,由于result[i-1]=1,flag=2(即图中红线),因此result[i]=1+2=3
当i=4,由于result[i-1]=3,flag=3(即图中绿线),因此result[i]=3+3=6,计算完毕。
那么问题的关键,就是如何计算flag:
每当我们第一次检测到某个三元素等差数列(如数列1 2 3),则flag=1。那么当检测到由该三元素等差数列延伸出的等差数列时,则flag++(如数列1 2 3 4,则flag加一变为2)。循环往复。
直到碰到某个第i号元素,不再属于该等差数列,则置flag=0。如下图:
解释:由前文可知,从0到第4号元素已经有6个等差数列(即result[4]=6)。第5号元素(7)不与前面构成等差数列,则flag置为0,没有新增的等差数列。第6号元素与前面构成5 7 9的等差数列,因此置flag=1,新增一个等差数列。因此result[6]=7
C++代码
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
//若数列中元素个数小于3,则必不存在等差数列
if(nums.size()<3)
return 0;
int n=nums.size();
int result[n]; //result[i]的含义是从第0号到第i号元素这一段当中,等差数列的数量
memset(result,0,sizeof(result));
bool isArithmetic=false;
int flag=0;
for(int i=0;i<n;i++){
if(i>=2&&nums[i]-nums[i-1]==nums[i-1]-nums[i-2]){
if(!isArithmetic){ //如果是第一次检测到这个三元素的等差数列
flag=1;
isArithmetic=true;
}else if(isArithmetic){ //如果检测到由该三元素等差数列延伸出的等差数列(即该等差数列元素大于3个)
flag++;
}
}else{ //如果等差数列断了
flag=0;
isArithmetic=false;
}
if(i>=1)
result[i]=result[i-1]+flag;
}
return result[n-1];
}
};