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;
}