数据结构经典面试题:在字符串中找到出现频率大于50%的那个字符

版权声明:本文出自www.54manong.com,转载请注明原地址,谢谢! https://blog.csdn.net/xiaohuanglv/article/details/85420485

来源:我是码农,转载请保留出处和链接!

本文链接: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)。

扫描二维码关注公众号,回复: 4725202 查看本文章

问题扩展:

    在一个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--;
			}
		}
    }
}

猜你喜欢

转载自blog.csdn.net/xiaohuanglv/article/details/85420485