Question:
给定一个最大为10,000的整型序列(每个值的大小在0到100,000)之间,求最大递减子序列。子序列可以不连续。
Answer1:
递归查找。递归查找从每个位置为开始的最长的递减子序列。
效率低!
Answer2:
当从前向后难找到节约方法时,从后向前的方法此时通常会富有成效。
这里就可以从序列的最后开始向前……
(1)检查从当前位置到最后所有节点的bestsofar值。
This is fairly clearly an O(N 2) algorithm. Check out its code:
1 #include <stdio.h>
2 #define MAXN 10000
3 main () {
4 long num[MAXN], bestsofar[MAXN];
5 FILE *in, *out;
6 long n, i, j, longest = 0;
7 in = fopen ("input.txt", "r");
8 out = fopen ("output.txt", "w");
9 fscanf(in, "%ld", &n);
10 for (i = 0; i < n; i++) fscanf(in, "%ld", &num[i]);
11 bestsofar[n-1] = 1;
12 for (i = n-1-1; i >= 0; i--) {
13 bestsofar[i] = 1;
14 for (j = i+1; j < n; j++) {
15 if (num[j] < num[i] && bestsofar[j] >= bestsofar[i]) {
16 bestsofar[i] = bestsofar[j] + 1;
17 if (bestsofar[i] > longest) longest = bestsofar[i];
18 }
19 }
20 }
21 fprintf(out, "bestsofar is %d\n", longest);
22 exit(0);
23 }
(2)跟上一个算法比,这个为了缩短检查时间,定义了bestrun[MAXN],其长度就是最长子序列长度,其值就是第一次存入的值(随后变为“最好的”值)
(原文:Implement an array `bestrun' whose index is the length of a long subsequence and whose value is the first (and, as it turns out, `best') integer that heads that subsequence.)
Here's a coding of this algorithm:
1 #include <stdio.h>
2 #define MAXN 200000//使用200000会堆栈溢出,而且题目要求也是20000,因此应改为20000。
3 main () {
4 FILE *in, *out;
5 long num[MAXN], bestrun[MAXN];
6 long n, i, j, highestrun = 0;
7 in = fopen ("input.txt", "r");
8 out = fopen ("output.txt", "w");
9 fscanf(in, "%ld", &n);
10 for (i = 0; i < n; i++) fscanf(in, "%ld", &num[i]);
11 bestrun[0] = num[n-1];
12 highestrun = 1;
13 for (i = n-1-1; i >= 0; i--) {
14 if (num[i] < bestrun[0]) {
15 bestrun[0] = num[i];
16 continue;
17 }
18 for (j = highestrun - 1; j >= 0; j--) {
19 if (num[i] > bestrun[j]) {
20 if (j == highestrun - 1 || num[i] < bestrun[j+1]){
21 bestrun[++j] = num[i];
22 if (j == highestrun) highestrun++;
23 break;
24 }
25 }
26 }
27 }
28 printf("best is %d\n", highestrun);
29 exit(0);
30 }
(3)使用二分查找改进速度,使时间复杂度变为O(nlgn)
#include <stdio.h> #define SIZE 200000 #define MAX(x,y) ((x)>(y)?(x):(y)) int best[SIZE]; // best[] holds values of the optimal sub-sequence int main (void) { FILE *in = fopen ("input.txt", "r"); int i, n, k, x, sol; int low, high; fscanf (in, "%d", &n); // N = how many integers to read in // read in the first integer fscanf (in, "%d", &best[0]); sol = 1; for (i = 1; i < n; i++) { best[i] = -1; fscanf (in, "%d", &x); if(x >= best[0]) { k = 0; best[0] = x; } else { // use binary search instead low = 0; high = sol-1; for(;;) { k = (int) (low + high) / 2; // go lower in the array if(x > best[k] && x > best[k-1]) { high = k - 1; continue; } // go higher in the array if(x < best[k] && x < best[k+1]) { low = k + 1; continue; } // check if right spot if(x > best[k] && x < best[k-1]) best[k] = x; if(x < best[k] && x > best[k+1]) best[++k] = x; break; } } sol = MAX (sol, k + 1); } printf ("best is %d\n", sol); fclose(in); return 0; }