C语言 neutralize函数,查找在数组出现次数超过一半的数字

一、题目:

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为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). 3)的变形版,依据原理完全一样。

算法:①. 从列表中移除两个不相等的数字。

②. 重复①,直到数组只剩下一个数为止。

③. 上面剩下的那个数一定是需要的那个数

5). 你来补充

**** 修改 *****

上面算法2、3、4 中,都没有给出题目的解,这儿就再絮叨一点,其实只需要再次遍历一遍数组,加一下个数,判断个数是否大于数组长度的一半即可,这就一个for循环,一个判断即可。

三、代码:

代码不是重点,全看个人编程能力,我这儿只是一个样例,证明我自己做过。

遍历算法:

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;

}

*!

明显的能看见代码量越来越少,希望自己以后碰到问题,如果时间多了,可以多想想。一个好的算法,不仅仅能有效的解决问题,而且还可以减少很多代码量。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值