查找在数组出现次数超过一半的数字

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;
}

*!

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

   

 

以上是关于查找在数组出现次数超过一半的数字的主要内容,如果未能解决你的问题,请参考以下文章

找出数组中出现次数超过一半的数字

编程算法 - 数组中出现次数超过一半的数字 代码(C)

数组中出现次数超过一半的数字

Java 剑指offer(39) 数组中出现次数超过一半的数字

出现次数超过一半的数字

数组中出现次数超过一半的数字(C语言+Java)