94.微软笔试题
求随机数构成的数组中找到长度大于=3 的最长的等差数列, 输出等差数列由小到大:
如果没有符合条件的就输出
格式:
输入[1,3,0,5,-1,6]
输出[-1,1,3,5]
要求时间复杂度,空间复杂度尽量小
/*
94.微软笔试题
求随机数构成的数组中找到长度大于=3的最长的等差数列, 输出等差数列由小到大:
如果没有符合条件的就输出
格式:
输入[1,3,0,5,-1,6]
输出[-1,1,3,5]
要求时间复杂度,空间复杂度尽量小
解法如下:
1.排序
2.设极值分别为min, max,那么公差范围为(1..max-min);
3.公差d从(1..max-min)循环,求出每次的最长的数列长度f(d)
所以该题目基础是求出一个有序数组中公差为d的最长等差数列。
较简单动态规划:
设等差数列的起始下标为s,当前下标为i,从s到i,构成的最长的等差数列长度为f(s,i),
有f(s,i+1) = f(s,i) +1 ( input[i+1] == input[s] + f(s,i)*d)
f(s,i) ( input[i+1] != input[s] + f(s,i)*d)
最长的数列长度为:
maxLen = max{f(s,i) s∈[1 .. max-min] i∈[0,sizeof(input)) }
*/
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#define MAX 1000
using namespace std;
void GetSeq(int *input,int size)
{
int maxLen,maxS,maxd,start,d,j,i;
int dp[MAX]={0};
maxLen=0;
maxS=-1;
maxd=1;
d=input[size-1]-input[0];//公差
for(j=1;j<=d;j++)
{
for(start=0;start<size;start++)//公差起始地址start
{
i=start;
dp[i++]=1;//公差的最大长度
for(;i<size;i++)
{
dp[i]=dp[i-1];
if(input[i]==input[start]+dp[i-1]*j)
{
dp[i]++;
if(dp[i]>maxLen)
{
maxLen=dp[i];
maxS=start;
maxd=j;
}
}
else if(input[i]>input[start]+dp[i-1]*j)
break;
}
}
}
printf("%d ",input[maxS]);
for(i=maxS+1,j=1;j<maxLen;i++)
if(input[i]==input[maxS]+j*maxd)
{
printf("%d ",input[i]);
j++;
}
printf("\n");
}
int main()
{
int input[]={1,3,0,5,-1,6};
int n;
n=sizeof(input)/sizeof(int);
sort(input,input+n);
for(int i=0;i<n;i++)
printf("%d ",input[i]);
printf("\n最长的等差数列:");
GetSeq(input,sizeof(input)/sizeof(int));
int input1[]={1,6,4,8,9,5,9,1,7,7};
n=sizeof(input1)/sizeof(int);
sort(input1,input1+n);
for(int i=0;i<n;i++)
printf("%d ",input1[i]);
printf("\n最长的等差数列:");
GetSeq(input1,sizeof(input1)/sizeof(int));
int input2[]={1,3,4,6,7,9,10,12,13,15,16,18,21,24};
n=sizeof(input2)/sizeof(int);
sort(input2,input2+n);
for(int i=0;i<n;i++)
printf("%d ",input2[i]);
printf("\n最长的等差数列:");
GetSeq(input2,sizeof(input2)/sizeof(int));
return 0;
}