标签:
给定一个整型数组, 求这个数组的最长严格递增子序列的长度。 譬如序列1 2 2 4 3 的最长严格递增子序列为1,2,4或1,2,3.他们的长度为3。
输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为一个整数n(1<=n<=100000):代表将要输入的序列长度
输入的第二行包括n个整数,代表这个数组中的数字。整数均在int范围内。
对于每个测试案例,输出其最长严格递增子序列长度。
4 4 2 1 3 5 1 1 1 1 1
2 1
这个题一开始用最简单的办法来做,果然超时了
代码如下
1 #include <cstdio> 2 int toDo[100002]; 3 int cnt[100002]; 4 5 int n; 6 int main(int argc, char const *argv[]) 7 { 8 while(scanf("%d",&n) != EOF) { 9 for(int i = 0; i < n ; i++) { 10 scanf("%d",&toDo[i]); 11 } 12 int max = 0; 13 for(int i = 0; i < n; i++) { 14 int maxi = 0; 15 for(int j = i-1; j >= 0; j--) { 16 if(toDo[j] < toDo[i] && maxi < cnt[j]) { 17 maxi = cnt[j]; 18 } 19 } 20 cnt[i] = maxi + 1; 21 if(max < cnt[i]) { 22 max = cnt[i]; 23 } 24 } 25 printf("%d\n",max); 26 } 27 return 0; 28 }
后来参考了许多别人的博客,才明白应该这样做
首先,你需要一个数组minNum[i]来记录达到长度i的最小数字是几,这个数组必然是递增的,因为长度更长的它的数字肯定更大。
那么,当一个新数字来的时候,假设现在最长的长度为k
如果它比minNum[k]大,那么minNum[++k] = newNum;
如果不比minNum[k]大,则需要去更新这个数组中的元素。具体需采用二分法来找到这个数字的位置,接着更新之。
但一开始提交错误,原来的代码是这样的
1 #include <cstdio> 2 int toDo[100002]; 3 int minNum[100002]; 4 5 int n; 6 7 int bSearch(int p,int low, int high) { 8 if(low < high) { 9 int mid = (low + high)/2; 10 if(minNum[mid] == p) { 11 return mid; 12 } 13 else if(minNum[mid] < p) { 14 return bSearch(p, mid+1, high); 15 } 16 else { 17 return bSearch(p, low, mid-1); 18 } 19 } 20 return low; 21 } 22 23 int main(int argc, char const *argv[]) 24 { 25 while(scanf("%d",&n) != EOF) { 26 for(int i = 0; i < n ; i++) { 27 scanf("%d",&toDo[i]); 28 } 29 30 minNum[1] = toDo[0]; 31 int k = 1; 32 for(int i = 1; i < n; i++) { 33 if(toDo[i] > minNum[k]) { 34 minNum[++k] = toDo[i]; 35 } 36 else { 37 int p = bSearch(toDo[i], 1, k); 38 minNum[p] = toDo[i]; 39 } 40 } 41 printf("%d\n",k); 42 } 43 return 0; 44 }
经过实验,发现测试数据为 4 5 6 1 2 3 5就会出错,
检查之后发现是二分搜索的错误,当minNum为 1 5 6时, 2 的到来使它变为2 5 6, 而不是1 2 6
修改在17行
代码如下
1 #include <cstdio> 2 int toDo[100002]; 3 int minNum[100002]; 4 5 int n; 6 7 int bSearch(int p,int low, int high) { 8 if(low < high) { 9 int mid = (low + high)/2; 10 if(minNum[mid] == p) { 11 return mid; 12 } 13 else if(minNum[mid] < p) { 14 return bSearch(p, mid+1, high); 15 } 16 else { 17 return bSearch(p, low, mid); 18 } 19 } 20 return low; 21 } 22 23 int main(int argc, char const *argv[]) 24 { 25 while(scanf("%d",&n) != EOF) { 26 for(int i = 0; i < n ; i++) { 27 scanf("%d",&toDo[i]); 28 } 29 30 minNum[1] = toDo[0]; 31 int k = 1; 32 for(int i = 1; i < n; i++) { 33 if(toDo[i] > minNum[k]) { 34 minNum[++k] = toDo[i]; 35 } 36 else { 37 int p = bSearch(toDo[i], 1, k); 38 minNum[p] = toDo[i]; 39 } 40 } 41 printf("%d\n",k); 42 } 43 return 0; 44 }
事实上,不需要toDo这个数组,代码如下
1 #include <cstdio> 2 int toDo; 3 int minNum[100002]; 4 int n; 5 6 int bSearch(int p,int low, int high) { 7 if(low < high) { 8 int mid = (low + high)/2; 9 if(minNum[mid] == p) { 10 return mid; 11 } 12 else if(minNum[mid] < p) { 13 return bSearch(p, mid+1, high); 14 } 15 else { 16 return bSearch(p, low, mid); 17 } 18 } 19 return low; 20 } 21 22 int main(int argc, char const *argv[]) 23 { 24 while(scanf("%d",&n) != EOF) { 25 int k = 0; 26 for(int i = 0; i < n ; i++) { 27 scanf("%d",&toDo); 28 if(k == 0) { 29 minNum[++k] = toDo; 30 continue; 31 } 32 if(toDo > minNum[k]) { 33 minNum[++k] = toDo; 34 } 35 else { 36 int p = bSearch(toDo, 1, k); 37 minNum[p] = toDo; 38 } 39 } 40 printf("%d\n",k); 41 } 42 return 0; 43 }
标签:
原文地址:http://www.cnblogs.com/jasonJie/p/5783373.html