著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的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
新学期练手,单纯从题目提出的问题来说,解决难度一点都不大,两重循环轻松搞定,可是如果你提交一定会被大量的运行超时所打倒,毕竟200ms。这时候就需要优化了,目标也一定是减少循环次数,可是如何减少呢?当初我的思路就是:如果待判断的这个数的左边有一个数比它小,并且还是主元的话,那这个数一定的左边一定没有一个数比他大,这个数的右边也是同理。因此想到了分别遍历两次,一次从左边,一次从右边,每个数都有有两个标识,一个是左边没一个比它大的,叫lflag,一个是右边没一个数比它小的,叫rflag,第一个数的lflag必定是1,最后一个数的rflag也一定是1,判断方法就是先从左边遍历各个数,从各个数的左边一个一个找,如果有比它小且lflag为1的,也将这个数的lfalg置为1,右遍历同理,写完觉得应该没什么问题了,可这样写完拿去提交的时候还是有一个超时,一下没想到辙又去看别人是怎么做的了。てへぺろ(•ω<)
终于找到一个,就是这个,看完时候立刻化身祥林嫂,“我真傻,真的”,完全不用我这么麻烦,同样的一次左遍历,一次右遍历,但是每个数的表示只有一个标识,是不是主元,叫flag吧,初始假设每个数都是主元,即flag都为1。左遍历先确定一个最大值,初始值就是第一个数,然后不断往后找,如果一个数比最大值大,最大值就更新,而且可以确定这个数比它的左边的任意一个数都大,毕竟已经大于之前的最大值了;如果小,洗洗睡吧,你肯定不是主元,你的左边已经有比你大的了。左遍历结束就排除掉很多数了,再从最右边开始遍历,这回是找最小值,一个道理,就不细说了,这样一来,剩下的flag仍然为1的就是主元了。完成
总结一下,我主要输在初始的思路上,我的思路就是正面刚,先假设全都不是,然后一个一个找是的,这个做法呢,是逆向思维,先假设都是,再去一个个排除,在这个问题上一定是后者好,毕竟判断主元这个东西是一票否决制的,判断它是主元很麻烦,必须一个一个去比较,但如果判断它不是很简单,找一个左边比它大的数或者右边比它小的数,找到这个数就能否定它。逆向思维,在概率论就吃过亏的...我真傻,真的。
#include <stdio.h> #include <stdlib.h> int cmp (const void *a, const void *b) { return *(int *)a - *(int *)b; } int main() { int i, N; scanf("%d", &N); int *numl = (int *) malloc (sizeof(int) * N); int *zhuyuan = (int *) malloc (sizeof(int) * N); int *res = (int *) malloc (sizeof(int) * N); for(i = 0; i < N; i++) { scanf("%d", &numl[i]); zhuyuan[i] = 1; } int leftMax = numl[0]; int rightMin = numl[N-1]; for(i = 1; i < N; i++) { if(numl[i] > leftMax) { leftMax = numl[i]; } else { zhuyuan[i] = 0; } } for(i = N-2; i >= 0; i--) { if(numl[i] < rightMin) { rightMin = numl[i]; } else { zhuyuan[i] = 0; } } int count = 0; for (i = 0; i < N; i++) { if(zhuyuan[i] == 1) { res[count++] = numl[i]; } } qsort(res, count, sizeof(int), cmp); printf("%d\n", count); for(i = 0; i < count; i++) { if(i > 0) { printf(" "); } printf("%d", res[i]); } printf("\n"); return 0; }