 /**//********************************************************************

purpose: 微软笔试题

求随机数构成的数组中找到长度大于=3的最长的等差数列
输出等差数列由小到大:
如果没有符合条件的就输出
格式:
输入[1,3,0,5,-1,6]
输出[-1,1,3,5]
要求时间复杂度,空间复杂度尽量小

*********************************************************************/
#include <iostream>
#include <set>
#include <vector>

using namespace std;

// 归并排序
void Merge(int rOrg[], int rBuf[], int from, int mid, int to)
  {
int i = from;
int j = mid + 1;
int k = from;
while (i <= mid && j <= to)
 {
if (rOrg[i] <= rOrg[j])
rBuf[k++] = rOrg[i++];
else
rBuf[k++] = rOrg[j++];
}
if (i <= mid)
while (i <= mid)
rBuf[k++] = rOrg[i++];
else
while (j <= to)
rBuf[k++] = rOrg[j++];
while(k>from)
rOrg[--k] = rBuf[k];
}
// 归并排序
void MergeSort(int r[], int rBuf[], int from, int to)
  {
if (from == to)
rBuf[from] = r[from];
else
 {
int mid = (from + to) / 2;
MergeSort(r, rBuf, from, mid);
MergeSort(r, rBuf, mid + 1, to);
Merge(rBuf, r, from, mid, to);
}
}
// 二分查找
int BinarySearch(int *r, const int &item, int left, int right)
  {
int middle;
while(left <= right)
 {
middle = (left + right)/2;
if(r[middle] == item)
return middle;
else if(r[middle] < item)
left = middle + 1;
else
right = middle - 1;
}
return -1;
}

// 求随机数构成的数组中找到长度大于=3的最长的等差数列
 void MaxLenEQDistSubArray(int rOrg[], int len) {
 if (rOrg == NULL || len < 3) {
return;
}
int *rBuf = new int[len]; // 用于归并排序
MergeSort(rOrg, rBuf, 0, len-1);

int** steps = new int*[len];
int* stepP;
int i, j, k, jEnd, left, right=len-1,
curDist, curLastItem, curLen=0,
maxDist, maxLastItem, maxLen=2;

// 初始化 步数数组
 for (i = 0; i < len; i++) {
steps[i] = new int[len-i];
stepP = steps[i];
 for (int j = len-i-1; j >= 0; j-- ) {
stepP[j] = 0;
}
}

// 开始查找最大等差子数组
// i为等差第一项的位置 j为等差第二项位置
 for (i = 0; i < len; i++) {
jEnd = len - 1; // 要求的等差数列最小长度为3,等差第二项最大为原数组倒数第二项
stepP = steps[i];
 for (j = i + 1; j < jEnd; j++) {
 if (stepP[j-i-1]) { // ① 此index步长j-i己被前面②计算过
continue;
}
//stepP[j-i-1]=1; // 可省略,因为不会再访问这个标志
curLastItem = rOrg[j];
curDist = rOrg[j]-rOrg[i]; // 本次等差
left = j;
curLen = 2;
 while ((k=BinarySearch(rOrg, curLastItem+curDist, left+1, right)) != -1) { //是否存在下一等差数
curLen++;
curLastItem += curDist;
steps[left][k-left-1] = 1; // ② 记录 index为left位置 index步长k-left 的数组己被前面计算过
left = k;
}
 if (curLen > maxLen) { // 记录最大等差数列信息
maxLen = curLen;
maxLastItem = curLastItem;
maxDist = curDist;
}
}
}

// 输出结果
 if (maxLen >= 3) {
int start = maxLastItem - maxDist*(maxLen-1);
cout<<"max length:"<<maxLen<<endl;
cout<<"max sub array: ";
while(maxLen--)
 {
cout<<start<<" ";
start += maxDist;
}
cout<<endl;
 } else {
cout<<"no GT 3 length sub array"<<endl;
}

delete[] rBuf;
delete[] steps;
}

void Test_MaxLenEQDistSubArray()
  {
 /**///// test MergeSort
//const int LEN = 8;
//int rOrg[LEN]={10,3,5,1,9,34,54,565},rBuf[LEN];
//MergeSort(rOrg, rBuf, 0, LEN-1);
//for (int i = 0; i < LEN; i++)
// cout << " " << rOrg[i];

 int rOrg[] = {1,3,0,5,-1,6}; //{1,3,0,5,-1,6}; {1,3,7,8,9,10,11,0,5,-1,6}; {1,3,7,8,9,10,11,12,0,5,-1,6}; {1,3,7,8,9,10,11,12,13,0,5,-1,6};
MaxLenEQDistSubArray(rOrg, sizeof(rOrg)/sizeof(rOrg[0]));

 {
 int rOrg[] = {1,3,7,8,9,10,11,0,5,-1,6};
MaxLenEQDistSubArray(rOrg, sizeof(rOrg)/sizeof(rOrg[0]));
}
 {
 int rOrg[] = {1,3,7,8,9,10,11,12,0,5,-1,6};
MaxLenEQDistSubArray(rOrg, sizeof(rOrg)/sizeof(rOrg[0]));
}
 {
 int rOrg[] = {1,3,7,8,9,10,11,12,13,0,5,-1,6};
MaxLenEQDistSubArray(rOrg, sizeof(rOrg)/sizeof(rOrg[0]));
}

}
|