浙大PAT 1045. 快速排序(25)

流过昼夜 提交于 2020-04-02 07:23:03

著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的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
    关于这道题目 网上已经有的两种解法 ,具体的不做细讲,大家进去看即可


    正反遍历法: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");
    }

    有兴趣的同学可以测试下,这比前两种都要快~~~

  • 标签
    易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
    该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!