1. 程式人生 > >計算機的本質(TSOJ 1541)————孤獨的餃子

計算機的本質(TSOJ 1541)————孤獨的餃子

我就先不多囉嗦了,題目內容如下。

題目描述

苦逼運維修好學校的土豆伺服器,復讀終止;

但一位惡人及時地將伺服器下鍋,開始復讀。

現在伺服器輸出了n (1<=n<=200000) 個數,需要求出其中出現次數最多的那個數 x。

其中x出現的次數 c > n / 2, 非常符合復讀機本質。

由於伺服器已經下鍋,執行混亂,對於任意輸出的數u, 0<=u<=10^100。

輸入描述

第1行一個整數n。

第2行n個整數,代表輸出的整數。

本題只有一組測試資料。

輸出描述

一個整數x。

樣例輸入

10

6 6 6 7 7 7 7 7 7 7

樣例輸出

7

 

不難看出,這是典型的主元素問題,其中主元素的個數嚴格大於 n / 2 。

這個題目的特殊之處就是資料的範圍是0<=u<=10^100,對於這種大數問題,用int型別或者long long int型別是遠遠不夠的,int型別的範圍也就是21億這樣子,long long int型別也多不到哪去,遠遠小於給定範圍。所以這個範圍對使用C/C++的使用者來說,就幾乎等於告訴你這題的資料要用字串來處理。

首先,我們來說一下資料在int範圍內的解法。容易想到,先將給定資料排序,由於主元素個數嚴格大於 n / 2 ,就不難看出不論元素總的個數是奇數還是偶數,處於 n / 2 這個位置的元素必定是主元素。這樣來看,最終的時間複雜度就由排序的時間複雜度來決定,快速排序複雜度是O(nlogn),用這種排序法便可以較快得出結果。

然後,我們只要對快速排序的過程稍作修改,將資料的比較改成字串的比較,藉助strcmp()這個函式,再者就是在字串交換時藉助strcpy()函式,當然使用這兩個函式之前要包含字串標頭檔案。這樣做完之後,我興奮地提交了一次,然而結果是超時了QAQ。

我想,既然快速排序法超時了,這個題目必定就有更巧妙地演算法。我考慮了一會,便想到了一個非常節省時間的方法,將時間複雜度降到了O(n), 提交的結果也很是讓人激動,Accepted。

話不多說,先貼上程式碼為敬。

#include <stdio.h>  
#include <string.h>

char a[210000][110];
	
int main()  
{  
	char temp[110];
	int n,i,head;
        scanf("%d",&n);
        head=1;
	for (int i=1; i<=n;i++)
	{ 
    	scanf("%s",temp);  
    	if(head==1)
    		strcpy(a[head++],temp);
    	else if(strcmp(temp,a[head-1])==0)
    		strcpy(a[head++],temp); 
    	else
    		head--;
	}
        printf("%s\n",a[1]);  
		
	return 0;
}

這個方法就是採用刪除法(或者說是抵消法),只要輸入的下一個數和前一個數不同,就把這兩個數都刪除掉(或者說這兩個數互相抵消),然後由於主元素的個數嚴格大於 n / 2 ,不難想到最終剩下的元素都是主元素,所以只要輸出第一個元素就是最終結果。

好了,餃子對這個題目的理解目前就這麼多,希望大佬們給出更妙的解法。