1045 快速排序(25 分)
著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的 N 个互不相同的正整数的排列,请问有多少个元素可能是划分前选取的主元?
例如给定 $N = 5$, 排列是1、3、2、4、5。则:
- 1 的左边没有元素,右边的元素都比它大,所以它可能是主元;
- 尽管 3 的左边元素都比它小,但其右边的 2 比它小,所以它不能是主元;
- 尽管 2 的右边元素都比它大,但其左边的 3 比它大,所以它不能是主元;
- 类似原因,4 和 5 都可能是主元。
因此,有 3 个元素可能是主元。
输入格式:
输入在第 1 行中给出一个正整数 N(≤105); 第 2 行是空格分隔的 N 个不同的正整数,每个数不超过 109。
输出格式:
在第 1 行中输出有可能是主元的元素个数;在第 2 行中按递增顺序输出这些元素,其间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
5
1 3 2 4 5
输出样例:
3
1 4 5
思路:
做出答案不难,难在如何不超时完成,第一次提交两个测试点超时了。想更快,一般都是嵌套循环太多了,改进的话要么递归要么迭代,如果能迭代就不用用递归。看问题时,要分析一下多层循环里面是否有很多的重复计算?看看前后计算是不是有关联的?如果能找到这种关系,就能用迭代写出来了。
一开始写的时间复杂度为O(2N^2+NlogN),空间复杂度O(3N),果然超时了,修改后如下,时间复杂度为O(2N+NlogN)。
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define MIN -1 5 #define MAX 1000000001 6 7 int compare(const void *a, const void *b){ 8 return *(int *)a - *(int *)b; 9 } 10 11 int main(void){ 12 int i, N, index=0, min=MAX, max=MIN; 13 14 scanf("%d", &N); 15 int A[N], pivot[N], judge[N]; 16 for( i=0; i<N; i++) 17 scanf("%d", &A[i]); 18 19 judge[0] = 1; 20 for( i=1; i<N; i++){ 21 if( A[i] > max ){ 22 judge[i] = 1;/*前面符合*/ 23 max = A[i]; 24 } 25 else 26 judge[i] = 0; 27 } 28 for( i=N-1; i>=0; i--){ 29 if( A[i] < min ){ 30 judge[i] &= 1;/*后面符合,与上前面结果*/ 31 32 if( judge[i] ) 33 pivot[index++] = A[i]; 34 35 min = A[i]; 36 } 37 else 38 judge[i] = 0; 39 } 40 41 qsort( pivot, index, sizeof(int), compare); 42 43 printf("%d ", index); 44 if( index != 0 ){ 45 for( i=0; i<index-1; i++) 46 printf("%d ", pivot[i]); 47 printf("%d", pivot[i]); 48 } 49 else 50 printf(" "); 51 52 return 0; 53 }