1. 程式人生 > >資料結構經典面試題:在字串中找到出現頻率大於50%的那個字元

資料結構經典面試題:在字串中找到出現頻率大於50%的那個字元

來源:我是碼農,轉載請保留出處和連結!

本文連結:http://www.54manong.com/?id=13

image.png

問題描述:

在某個字串中(字串可能很長,比如有幾千萬個字元),請找出某個出現頻率大於50%的那個字元。例如:在字串"aabcdaa"中,字串長為7,字元'a'出現了4次,其出現頻率大於50%,因此'a'就是最終要輸出的字元。

問題分析:

思路1:

解決這個問題最簡單的方法就是遍歷一遍字串,針對每個字元都統計出其出現的次數,最後再遍歷一遍這些次數,看哪個字元的次數超過了總次數的50%。該方法的優點是思路簡單明瞭,缺點是額外的儲存空間耗費大,演算法時間複雜度高。

思路2:

首先對這個字串中的字元按照某種次序排序(比如字元的字典序),得到一個有序的字串,顯而易見,該字串中間的那個字元一定就是我們要找的那個出現頻率超過50%的字元。該方法的優點是可以在O(Nlog2N+1)時間內解決,但仍然不夠快。

思路3:能否不排序呢?當然可以!我們對整個字串遍歷一遍,遍歷的過程中,每當遇到兩個不同的字元時,就把它們兩個都刪除掉,這樣,最終當字串中沒有不同字元(即只有種字元)時,剩下的這種字元一定就是我們所要求的出現頻率超過50%的那個字元了。比如在字串"aabcdaa"中,我們將"ab","cd"分別刪除,最終字串中剩下的都是字元"a"了,"a"即為所求。

程式碼如下:

//在字串中找到出現頻率大於50%的那個字元
char get_char(char *ch)
{
   char str;
   int times = 0;
   while(*ch) 
   {
      if(times == 0)
         str= *ch, times = 1;
      else 
      {
        if(str== *ch)
            times++;
        else
            times--;
      }
      ch++;
   }
   return str;
}

    某個字元str如果出現頻率大於一半,比如出現頻率為55%,那麼其他字元出現頻率的總和為(1-55%)=45%,字元str出現頻率比其他字元出現頻率的總和大(55%-45%)=10%,按照上述我們的程式思路,在最壞的情況下,每次抵消的兩個字元中都有一個str,那麼最終還能剩10%的字元str。該演算法的時間複雜度為O(n)。

問題擴充套件:

    在一個int型陣列中,某三個數字出現頻率分別大於25%,請找出這三個數字。

思路:

    和原問題大同小異,只要降低規模即可,每次抵消四個不相同的數字,不斷重複,最後剩下的三個數字就是答案。

程式碼如下:

int candiA = 0, candiB = 0, candiC = 0;
void get_three_num(int num[])
{
    int countA = 0, countB = 0, countC = 0;
    for (int i = 0; i < num.Length; i++)
    {          
		if (countA == 0 || countB == 0 || countC == 0 )
		{                   
			if (countA == 0)
			{
				if (countB != 0 && num[i] == candiB)
					countB++;
				else if (countC != 0 && num[i] == candiC)
					countC++;
				else
				{
					candiA = num[i];
					countA++;
				}
			}
			else if (countB == 0)
			{
				if (countA != 0 && num[i] == candiA)
					countA++;
				else if (countC != 0 && num[i] == candiC)
					countC++;
				else
				{
					candiB = num[i];
					countB++;
				}
			}
			else if (countC == 0)
			{
				if (countA != 0 && num[i] == candiA)
					countA++;
				else if (countB != 0 && num[i] == candiB)
					countB++;
				else
				{
					candiC = num[i];
					countC++;
				}
			}
		}
		else
		{
			if (num[i] == candiA)
				countA++;
			else if (num[i] == candiB)
				countB++;
			else if (num[i] == candiC)
				countC++;
			else
			{
				countA--;
				countB--;
				countC--;
			}
		}
    }
}