题目
给定一个大小为n的数组,要求写出一个算法,求其最长的等差数列的子序列
分析
该题需要分几种情况考虑。
1. 原数组是有序的,所要求的的子序列可以不连续。
对于数组arr[],不同的等差值d=1,2,3,4,5```(arr[max]-arr[min])可以求出不同的最长等差数列,然后在这些等差数列中求出最长的那个即可我们首先转化为求一个数组的固定等差值的最长等差子序列。如数组1,2,4,6,8,9,求等差值2的最长等差子序列为2,4,6,8
1.1 固定等差值的最长子序列
求符合条件的最长子序列可以用动态规划来做,设dis[i]记录数组arr[]的第1-i个元素子数组的最长等差子序列长度,状态转移方程式:
dis[i]=1;
dis[i]=dis[k]+1, k是数组第1-i个元素中,与元素i等差为d并且距离i最近的元素(k<i);
代码
1 int RegularArithmeticSeq(int arr[],int len,int d) 2 { 3 if (arr==NULL||len<1) 4 throw std::exception("Invalid input."); 5 6 int* dis=new int[len+1](); 7 8 int re_len=0,re_index=0; 9 for (int i=1;i<=len;i++) 10 { 11 dis[i]=1; 12 for (int k=i;k>0;k--) 13 { 14 int cur_d=arr[i-1]-arr[k-1]; 15 16 if (cur_d==d&&dis[i]<=dis[k]) 17 { 18 dis[i]=dis[k]+1; 19 } 20 21 if (re_len<=dis[i]) 22 { 23 re_len=dis[i]; 24 re_index=i; 25 } 26 27 if (cur_d>d) 28 break; 29 } 30 } 31 32 int out=arr[re_index-1]; 33 for (int n=0;n<re_len;n++) 34 { 35 cout<<out<<' '; 36 out=out-d; 37 } 38 cout<<endl; 39 40 delete[] dis; 41 42 return re_len; 43 }
上述代码的时间复杂度为O(n*n),时间复杂度为O(n);
对于寻找1-i中最后一个和i等差的元素k,除了顺序遍历,还可以用二分查找法进行一点优化,查找的时间复杂度为O(logn)
1</