首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >算法学习之寻找最长等差数列

算法学习之寻找最长等差数列

作者头像
用户4415180
发布2022-06-23 14:07:25
发布2022-06-23 14:07:25
4490
举报
文章被收录于专栏:高并发高并发

  最长等差数列就是在一个数组中,组成等差数列的最长的那一个,首先我们对数组排序,然后我们一般会先想到暴力法从第一个开始循环遍历整个数组,时间复杂度O(N^3),下面给出伪代码

代码语言:javascript
复制
               int i,j,k,len = 0
               for(i = 0; i < n; i++)
                     for(j = i+1; j < n; j++)
                    {
                        int delta = a[j] - a[i];
                        len = 2;
                        int tmp = a[j];
                        for(k = j+1; k < n; k++)
                       {
                            if(a[k] - tmp== delta)
                          {
                               len++;
                               tmp = a[k];
                          }
                       }
                      求出最大的len
                    }

第二种方法用动态规划,我们可以利用等差数列的性质来做,当等差数列长度为奇数的时候,比如相邻3个数,aiajak

则2*aj = ai+ak;只要任何一个关于它对称的两个数相加都等于它的2倍,有了这个性质我们就可以利用动态规划来做

dp[i][j] = d,表示以a[i]a[j]为前两个元素的等差数列长度为d,我们再来推状态转移方程,

 如果ai+ak<2*aj,说明ak - aj < aj - ai dp[i][j]的值不能确定,k接着往后走

如果ai+ak>2*aj,说明ak-aj > aj -ai,此时dp[i][j]的值为2,因为k不能往后走了,再往后走二者差距更大,所以a[i]a[j]开头的等差数列为2,然后再i--,开始寻找下个ai aj开头的等差数列

如果ai+ak==2*aj,则说明这三个数构成等差数列,此时dp[i][j]=dp[j][k]+1;也就是说以ajak开头的等差数列前加上了一个ai,状态转移确定好后,下面开始写代码

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct result
{
    int max_len;
    int i;
    int j;
};
int max(int a,int b)
{
    return a > b ? a : b;
}
void find_llap(int *arry,int n)
{
    int dp[50][50]; //dp[i][j]代表以arry[i]和arry[j]为头两个元素的等差数列,此题规模小,规模大的时候i,j可以做hash,就可以节省空间
    int i,j,k;
    struct result result;
    memset(dp,0,sizeof(dp));
    for(i = 0; i < n; i++)
    {
       dp[i][n] = 2; //因为以arry[n]为第二个元素的等差数列长度一定为2
    }
    if(n < 2)
    {
        for(i = 0; i < 2; i++)
            printf("%d ",arry[i]);
        return;
    }
    result.max_len = 0;
    for(j = n-1; j >= 1; j--)
    {
        i = j-1;k = j+1;
        while(i >= 0 && k <= n)
        {
            if(arry[i]+arry[k] > arry[j]<<1) //如果和ai+ak>2aj,说明ak-aj>aj-ai,这个构造不成等差数列,则k以后的更不行,因为数组是升序
             {
                 dp[i][j] = 2;                //所以此步骤直接赋值为2,及只有ai aj构造成等差数列
                 i--;
             }
            else if(arry[i]+arry[k] < arry[j]<<1)
            {
                k++;       //如果ai+ak<2aj,说明ak-aj<aj-ai,所以以ai aj开头的等差数列,往后遍历,可能还有新的元素符合公差,所以k++
            }
            else
            {
                /*如果ai+ak=2aj,则正好构成等差数列,直接将前一个子问题的解+1即可*/
                dp[i][j] = dp[j][k]+1;
                result.max_len = max(result.max_len,dp[i][j]);
                if(result.max_len == dp[i][j])
                {
                    result.i = i;
                    result.j = j;
                }
                i--;k++;
            }
         }
         if(result.max_len == 0)
         {
             result.max_len = 2;
             result.i = 0;
             result.j = 1;
         }
         while(i >= 0) /*这个循环是因为k已经到最后了,所以以这个j为第二个元素的所有数列都是2*/
         {
             dp[i][j] = 2;
             i--;
         }
     }
     int delta = arry[result.j] - arry[result.i];
     int last  = arry[result.i]+(result.max_len-1)*delta;
     for(i = arry[result.i]; i <= last; i+=delta)
        printf("%d ",i);

}

int main()
{
    int n;
    int arry[100];
    scanf("%d",&n);
    int i;
    for(i = 0; i < n; i++)
      scanf("%d",&arry[i]);
    find_llap(arry,n-1);
    return 0;
}

  依据这个性质,还有一种动态规划,dp[i][j]代表等差数列最后两个元素,然后从前往后遍历,得到的结果一样

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-02-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档