找出陣列中長度最長的等差數列
#include <stdio.h> #include <stdlib.h> #define MAX 1000 void GetSeq(int *input, int size, int d){ if(input == NULL) return; int result[MAX] = {0}; int startIndex = 0; int maxLen = 0; int maxLenStartIndex = -1; for(;startIndex < size-maxLen; startIndex++){ int i = startIndex; result[i] = 1; i++; for(;i<size;i++){ result[i] = result[i-1]; if(input[i] == input[startIndex] +result[i-1]*d){ result[i]++; if(result[i]> maxLen){ maxLen = result[i]; maxLenStartIndex = startIndex; } } else if(input[i] > input[startIndex] + result[i-1]*d) break; } } printf("Max sequence start index: %d, length: %d \n", maxLenStartIndex, maxLen); } int main(){ int input[] = {1,3,4,6,7,9,10,12,13,15,16,18,21,24}; GetSeq(input, sizeof(input)/sizeof(int), 3); }
T2:
求微軟面試題:求整數隨機數構成的陣列中找到長度大於=3的最長的等差數列
輸出等差數列由小到大:
如果沒有符合條件的就輸出[0,0]
格式:
輸入[1,3,0,5,-1,6]
輸出[-1,1,3,5]
要求時間複雜度,空間複雜度儘量小
網上有動態規劃的解法,時間複雜度O(N^3):http://openuc.sinaapp.com/?p=286
而本文要提另一種動態規劃解法,時間複雜度O(N^2),空間複雜度比較大,一會說。
方法:
第一步都一樣,先排序。
第二步,動態規劃。在一個已排好序的數列中,等差數列的差d滿足 0 <= d <= a[N-1] - a[0]。於是,設一個二維表dp,有a[N-1] - a[0] + 1 行,N列,dp[i][j]記錄數列a[j],公差為i下的最長數列長度。那麼很明顯有:dp[i][j] = dp[i][ index_of( a[j] + i ) ] + 1。其中index_of(num)表示數num在陣列a中的索引。上述dp的意思是:如果a[j]能構成等差數列的一份子,公差為i,那麼它的下一項就是a[j] + i,這當然要求a[j] + i存在於陣列a中啦~而且,a[j]構成的數列的長度就是由 a[j] + i 構成數列長度加1. 依據上述分析,只要對陣列a由尾到頭遍歷,對每個a[j],求出所有公差從0到a[N-1]-a[0]下的最長數列長度,則問題就得解了。
注意幾個問題:
1. 上述分析過程中要求求出所有公差從0到a[N-1]-a[0],但實際上並不需要這麼一個一個的求,因為以任何a[j],它能構成等差數列,則公差一定是 a[ k ] - a[ j ],這裡 j < k < N,因此,求解的範圍得到縮小,因此整體的時間複雜度為0(N^2)。
2. 另一個實現問題是,dp只記錄了最長數列的長度,而我們為了能回朔並輸出等差數列,我們還需要知道構成最長等差數列a[j]的下一個數是什麼,因此,需要同時記錄下一跳的索引。在程式碼中,我用pair<int,int>來記錄,first記錄長度,second記錄下一跳索引。
3. 注意處理a[j]與多個數差值相同的情況,比如 1,3,3,對a[0]=1,它和a[1],a[2]的差值相同,所以對於a[0],公差為2而言,即dp[2][0],它只需要更新一次即可。 #include "stdafx.h"
#include <stdio.h>
#include <iostream>
using namespace std;
const int N = 10;
const int INVALID_IDX = -1;
void show(int* a,int n)
{
for (int i=0;i<n;++i)
{
cout<<a[i]<<",";
}
cout<<endl;
}
inline int compare(const void* p1,const void* p2)
{
return *(int*)p1 - *(int*)p2;
}
void longest_seq(int* a)
{
qsort(a,N,sizeof(int),&compare);
int R = a[N-1]-a[0]+1;
pair<int,int>** dp = new pair<int,int>*[R];
for (int i=0;i<R;++i)
{
pair<int,int>* row = new pair<int,int>[N];
for (int j=0;j<N;++j)
{
row[j].first = 0; //記錄當前最長數列的長度
row[j].second = INVALID_IDX;//記錄與first相對應的等差數列的下一值在陣列a中的索引
}
dp[i] = row;
}
int maxlen = 0;
int rowidx = INVALID_IDX;
int colidx = INVALID_IDX;
for (int i=N-2;i>=0;--i)
{
for (int j=i+1;j<N;++j)
{
if (dp[ a[j]-a[i] ][i].first != 0) continue; //以該“差”為行號的值如果已經存在,就不需要再為相同的差值更新
dp[ a[j]-a[i] ][i].first = dp[ a[j]-a[i] ][j].first + 1;
dp[ a[j]-a[i] ][i].second = j;
if (dp[ a[j]-a[i] ][i].first > maxlen)
{
maxlen = dp[ a[j]-a[i] ][i].first;
rowidx = a[j]-a[i];
colidx = i;
}
}
}
if( maxlen > 1 )
{
cout<<"The longest seq is:"<<endl;
while( colidx != INVALID_IDX )
{
cout<<a[colidx]<<",";
colidx = dp[rowidx][colidx].second;
}
cout<<endl;
}
else
{
cout<<"0,0"<<endl;
}
for (int i=0;i<R;++i)
delete []dp[i];
delete []dp;
}
int main(void)
{
int a[N] = {8, 8, 7, 4, 1, 3, 3, 1, 8, 4};
longest_seq(a);
return 0;
}