深度学习
问题描述:
在某个字符串中(字符串可能很长,比如有几千万个字符),请找出某个出现频率大于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--; } } } }
来源:我是码农,转载请保留出处和链接!
本文链接:http://www.54manong.com/?id=13