浙大PAT 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
    關於這道題目 網上已經有的兩種解法 ,具體的不做細講,大家進去看即可


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

    有興趣的同學可以測試下,這比前兩種都要快~~~


  • 免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM