浙大PAT 1045. 快速排序(25)
著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的N个互不相同的正整数的排列,请问有多少个元素可能是划分前选取的主元?
例如给定N = 5, 排列是1、3、2、4、5。则:
因此,有3个元素可能是主元。
输入格式:
输入在第1行中给出一个正整数N(<= 105); 第2行是空格分隔的N个不同的正整数,每个数不超过109。
输出格式:
在第1行中输出有可能是主元的元素个数;在第2行中按递增顺序输出这些元素,其间以1个空格分隔,行末不得有多余空格。
输入样例:5 1 3 2 4 5输出样例:
3 1 4 5关于这道题目 网上已经有的两种解法 ,具体的不做细讲,大家进去看即可
正反遍历法:http://www.kkun.cc/articles/67
基于主元位置不变法:http://blog.csdn.net/gq_bob/article/details/49520161
今天我想讲的方法是 单次遍历排除法(总之时间复杂度不是O(N)的肯定是不行啦~~~)
1. 输入元素
2. 进行判断,如果大于max , 则更新max,并将其置入Nums数组
3. 如果该数小于max,则说明前面有数可能违反规则,此时从Nums数组最后一个开始遍历,依次去除被当前点淘汰的点,直到剩下的点符合要求,或者数组为空
主要思想: 从左到右遍历,之后进入Nums的点,必然满足大于左边所有数的要求,此时更新点只需排除那些不满足小于右边点即可,代码如下:
#include <iostream> using namespace std; int main() { int N; cin>>N; int i = 0 , max = 0 , maxi = 0; int Nums[100000] = {0}; int n; for (i ; i < N; i++) { scanf("%d",&n); if (n > max) // 如果比现在最大值大 一定可以进来 { Nums[maxi] = n; maxi++; max = n; } else // 不能成为主元 但却可以淘汰其他主元 { int j = 0; for ( j = maxi-1; j >=0 ; j--) { if (Nums[j] > n) { Nums[j] = 0; maxi--; } else { maxi = j+1; break; } } } } cout<<maxi<<endl; if (maxi != 0) { for (i = 0 ; i < maxi-1 ; i++) cout<<Nums[i]<<' '; cout<<Nums[i]<<endl; } else cout<<endl; system("pause"); }
有兴趣的同学可以测试下,这比前两种都要快~~~