http://haixiaoyang.wordpress.com/category/dynamic-programming/
http://www.51nod.com/question/index.html#!questionId=79
在一个升序排列好的数列里面找到最长的等差数列
例子:1 3 5 6 8 9 10 12 13 14
子数列有(两项的不在列举)
1 3 5
1 5 9 13
3 6 9 12
3 8 13
5 9 13
.....
得出的最长的等差数列应该是:6 8 10 12 14
方案1:
用hash
遍历所有可能的差值d
hash表中记录的是到当前为止,以之前的数字为结尾的等差数列的最长长度
对一个新的元素,将其减去d之后,查找是否有相同的值,如果存在,则替换为这个新元素,并将值加1
public static void Solve1(int[] items) { Dictionary hash = new Dictionary(); int max = items.Max() - items.Min(); int maxLength = 2, maxInc = -1, last = -1; for (int inc = 1; inc < max; inc++) { if (inc * maxLength > max) break; hash.Clear(); hash.Add(items[0], 1); for (int i = 1; i < items.Length; i++) { if (hash.ContainsKey(items[i] - inc)) { int value = hash[items[i] - inc]; hash.Remove(items[i] - inc); hash.Add(items[i], value + 1); if (value + 1 > maxLength) { maxLength = value + 1; maxInc = inc; last = items[i]; } } else if (!hash.ContainsKey(items[i])) hash.Add(items[i], 1); } } Console.WriteLine("{0} {1} {2}", maxLength, maxInc, last); }
方法2:
//Find the length of the longest arithmetic progression sequence of a sorted array //solution: //suppose there is the array a[n] with arithmetic progression: // ... a[i], a[j], a[k], use A[i][j] to symbol the number of arithmetic progression //starting from a[i], a[j], then A[i][j] = 1 + A[j][k], in which case //a[j] - a[i] == a[k] - a[j]; since the array is sorted, from each possible //middle point j, we can extend on left and right to seek out all pairs that make //a[i] - a[left] == a[right] - a[i] const int M = 15; int GetLPS(int a[M]) { assert(a); if (1 == M) return 1; int rec[M][M]; for (int i =0; i < M; i++) for (int j = 0; j < M; j++) rec[i][j] = 2; int nMax = 2; for (int i = M - 2; i >= 1; i--) { int nLft = i - 1; int nRgt = i + 1; while (nLft >= 0 && nRgt < M) { if (a[i] - a[nLft] == a[nRgt] - a[i]) { //one thing is if you iterate from left to right, //you should assign to rec[i][nRgt] rather than rec[nLft][i] rec[nLft][i] = rec[i][nRgt] + 1; if (rec[nLft][i] > nMax) nMax = rec[nLft][i]; //well, the continuous same elements don't affect the result //why??? nLft--, nRgt++; } else if (a[i] - a[nLft] < a[nRgt] - a[i]) nLft--; else nRgt++; } } return nMax; }
设下标 j < i < k
f[i,k]表示以a[i], a[k]为等差数列的最后两项的最长长度
如果 a[i]-a[j] = a[k] - a[i]则 f[i,k] = f[j,i] +1
int maxDiffLen(int *a, int n) { vector<vector<int> > vt(n); for (int i = 0; i < n; ++i) vt[i].resize(n , 2 ); int maxLen = 0; for (int i = 1; i < n - 1 ; ++i ) { int j = i - 1; int k = i + 1; while (j >= 0 && k < n) { if (a[k] - a[i] > a[i] - a[j]) --j; else if ( a[k] - a[i] < a[i] - a[j] ) ++k; else { vt[i][k] = vt[j][i] + 1; if (vt[i][k] > maxLen) maxLen = vt[i][k]; ++k; --j; } } } return maxLen; }
又想到一种方法,但是很占内存。f[i][k]表示以a[i]结尾的,差为k的数列的最大长度。
int getLArray(int *a, int n) { int maxDiff = a[n-1] - a[0]; int ** f = new int *[n]; for (int i = 0; i < n ; ++i) f[i] = new int [maxDiff+1]; for (int i = 0; i < n ; ++i) for (int j = 0; j <= maxDiff; ++j) f[i][j] = 1; int maxLen = 2; for (int i = 1; i < n; ++i) { for (int j = i - 1; j >=0; --j) { int k = a[i] - a[j]; if (f[i][k] < f[j][k] + 1) f[i][k] = f[j][k] + 1; if (maxLen < f[i][k]) maxLen = f[i][k]; } } for (int i = 0; i < n; ++i) delete [] f[i]; delete []f; return maxLen; }