浙大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");
}有兴趣的同学可以测试下,这比前两种都要快~~~

浙公网安备 33010602011771号