问题描述
一个算术数组是指至少包含两个整数,且相邻整数之间的差值都相等的整数数组。
例如,[9、10],[3、3、3] 和 [9、7、5、3] 是算术数组,而 [1、3、3、7],[2、1、2],和 [1、2、4] 不是算术数组。
Sarasvati 有一个包含 N 个非负整数的数组,其中的第 i 个整数为 Ai。
她想从数组中选择一个最大长度的连续算术子数组。
请帮助她确定最长的连续算术子数组的长度。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含整数 N。
第二行包含 N 个整数,其中第 i 个整数表示 Ai。
输出格式
每组数据输出一个结果,每个结果占一行。
结果表示为 Case #x: y,其中 x 为组别编号(从 1 开始),y 表示最长的连续算术子数组的长度。
数据范围
1≤T≤100,
1≤Ai≤109,
对于每个测试点,满足 2≤N≤2×105 的数据一定不超过 10 组,其余数据则满足 2≤N≤2000。
输入样例:
4
7
10 7 4 6 8 10 11
4
9 7 5 3
9
5 5 4 5 5 5 4 5 6
10
5 4 3 2 1 2 3 4 5 6
输出样例:
Case #1: 4
Case #2: 4
Case #3: 3
Case #4: 6
样例解释
对于测试数据 1,最长的连续算术子数组为 [4,6,8,10]。
对于测试数据 2,最长的连续算术子数组就是数组本身。
对于测试数据 3,最长的连续算术子数组为 [4,5,6] 和 [5,5,5]。
对于测试数据 4,最长的连续算术子数组为 [1,2,3,4,5,6]。
解题思路
1. 双指针做法
思路
- 首先,任意两个数都能形成等差数列,所以终点从2开始找。i是起点,j是终点。while循环找到等差数列后的第一个数的下标。比如样例给的一组数据:10 7 4 6 8 10 11。一开始i为0,j为2。while只能循环一层,此时j为3(这是让等差数列不连续的第一个数),所以下标为0~2的3个数是等差数列的长度。然后与结果取大的那一个。
- 还有一个注意的点,下标i~j-1的数是等差数列,所以当起点在它们之间时,等差数列的长度一定比刚刚判定的最大的长度短。比如样例给的一组数据:10 7 4 6 8 10 11。第一轮i=0,j=2,等差数列长度最大值为3(10,7,4),如果下一次循环i++之后,i=1,那么等差数列长度为2(7,4),所以这里可以做优化,即双指针将起点设置为j-1的位置。所以令i=j-2(为什么不是i=j-1呢??因为for循环会执行i++,i=j-2经过for循环之后就是j-1了)
AC代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N=200010;
int a[N];
int main()
{
int t;
scanf("%d",&t);
for(int cases=1;cases<=t;cases++)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int res=0;
for(int i=0;i<n;i++)
{
int j=i+2;
while(j<n&&a[j]-a[j-1]==a[j-1]-a[j-2]) j++;
res=max(res,j-i);
i=j-2;
}
printf("Case #%d: %d\n",cases,res);
}
return 0;
}
2. 双指针+差分做法
思路
本题需要计算最长的连续等差数列的长度 我们可以转化为差分数组 最长连续相等的长度 最后再加1即可 例如
原数组 10 7 4 6 8 10 11
差分数组 -3 -3 2 2 2 1
我们可以看出差分数组最长有三个2相连 表示有相邻的三个数与前一个数的差都是2,所以等差数列有4个数:4 6 8 10
注意:等差数列的长度为差分数组相同数+1
AC代码
#include <iostream>
using namespace std;
const int N=200010;
int a[N],b[N];
int main()
{
int t;
scanf("%d",&t);
for(int cases=1;cases<=t;cases++)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
if(i>0) b[i]=a[i]-a[i-1];//b[]下标从1开始
}
int res=0,l=1,r=1;
while(r<n)
{
if(b[l]!=b[r])
{
res=max(res,r-l+1);
l=r;
}
r++;
}
res=max(res,r-l+1);
printf("Case #%d: %d\n",cases,res);
}
return 0;
}