查找在数组出现次数超过一半的数字
Posted gaofs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了查找在数组出现次数超过一半的数字相关的知识,希望对你有一定的参考价值。
一、题目:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
二、分析:
1). 暴力统计(遍历统计):统计超过数组长度一半的数,最简单也是最常用的思路就是暴力统计,遍历数组中所有元素,记录每一个元素出现的次数,最后找出出现次数最大的那个数。
优点:准确、思路简单,符合人的常规思维模式。
缺点:有很多额外的辅助信息,比如需要一个二维数组来记录,并且二维数组的长度至少为原数组长度的一般(这儿是针对C语言,数组申请需要提前知道数组长度,非高等语言中的可变数组),需要进行额外的多次查找位置,最后还需要进行查找出现次数最大的那个数。
2). 暴力统计确实简单,但是问题也很明显,那么能不能找个更加简单的算法?答案是可以的。
排序算法:因为这个数出现的次数超过列表的一半,那么排序后的结果,最中间的那个数一定是需求的数。算法复杂度取决于排序算法的选取。
优点:复杂度全部依赖于你选的排序算法。
缺点:先决条件是已知一定有一个数字出现的次数超过了数组长度的一半,而且复杂度完全依赖于排序算法。
3). 排序算法时间复杂度比暴力统计时间复杂度肯定都高的,再介绍一个比较好的算法。
抵消策略:因为这个数出现的次数超过了列表的一半,那么我拿这个数和其余所有的数进行抵消,结果一定还会剩下至少一个。
算法:①. 申请两个变量 tempValue,tempIndex,初始化tempValue为array[0],tempIndex为1 .
②. 从数组的第二个数开始,依次和tempValue进行比较,如果不一样,tempIndex -= 1,如果一样,tempIndex += 1;运算后如果tempIndex为0,把array[i] 赋值给tempValue,tempIndex修改为1.直到数组完结。
③. 最后tempValue一定是需要的数。
优点:这个算法优点很明显了,无论是从时间上还是从空间上,都兼顾到了。
缺点:缺点依然是先决条件:一定有一个数字出现的次数超过了数组的一半。
4). 你来补充。
三、代码:
代码不是重点,全看个人编程能力,我这儿只是一个样例,证明我自己做过。
遍历算法:
int traverseEach(int *array,int number) { int *tempArray = (int *)malloc(sizeof(int)*(number / 2 + 1) * 2); //全部初始化为0 for (int i = 0; i < number * 2; i ++) { tempArray[i] = 0; } int maxNumber = 0; int returnValue = 0; int maxCount = 0; int tempIndex = 0; for (int i = 0; i < number; i ++) { tempIndex = 0; if (maxCount == 0) { //初始化一下 tempArray[maxCount] = array[i]; tempArray[number + i] = 1; maxCount = 1; } else { // for (; tempIndex < maxCount; tempIndex ++) { if (tempArray[tempIndex] == array[i]) { tempArray[number + tempIndex] += 1; break; } } if (tempIndex == maxCount) { //新的 tempArray[tempIndex] = array[i]; tempArray[number + tempIndex] += 1; maxCount += 1; } } if (maxNumber < tempArray[number + tempIndex]) { maxNumber = tempArray[number + tempIndex]; returnValue = tempArray[tempIndex]; } } free(tempArray); //检验是否大于一半 if (maxNumber <= number/2) { returnValue = 0; } return returnValue; }
排序算法:(这儿就是用冒泡排序做个例子)
void maopSort(int *array,int number) { int changed = 1; for (int i = number - 1; i > 0 ; i --) { if (changed == 0) { break; } changed = 0; for (int j = 0; j < i; j++) { if (array[j] > array[j+1]) { //exchange array[j] += array[j+1]; array[j+1] = array[j] - array[j+1]; array[j] = array[j] - array[j+1]; changed = 1; } } } } int sortRelu(int *array, int number){ maopSort(array, number); return array[number/2]; }
抵消策略:
int neutralize(int *array,int number) { int returnValue = array[0]; int count = 1; for (int i = 1; i < number; i ++) { if (returnValue == array[i]) { count += 1; } else { count -= 1; } if (count <= 0) { count = 1; returnValue = array[i]; } } return returnValue; }
*!
明显的能看见代码量越来越少,希望自己以后碰到问题,如果时间多了,可以多想想。一个好的算法,不仅仅能有效的解决问题,而且还可以减少很多代码量。
以上是关于查找在数组出现次数超过一半的数字的主要内容,如果未能解决你的问题,请参考以下文章