AcWing 3311. 最长算术

问题描述

一个算术数组是指至少包含两个整数,且相邻整数之间的差值都相等的整数数组。
例如,[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. 双指针做法

思路

  1. 首先,任意两个数都能形成等差数列,所以终点从2开始找。i是起点,j是终点。while循环找到等差数列后的第一个数的下标。比如样例给的一组数据:10 7 4 6 8 10 11。一开始i为0,j为2。while只能循环一层,此时j为3(这是让等差数列不连续的第一个数),所以下标为0~2的3个数是等差数列的长度。然后与结果取大的那一个。
  2. 还有一个注意的点,下标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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值