求数组中出现次数超过一半的元素(《编程之美》寻找水贴王问题)C代码

   给定一个数组,其中有一个元素的出现次数超过1/2,如何快速的找出这个元素。这个问题在《编程之美》中是这样描述的:

“研究院的员工和实习生们都很喜欢在Tango上面交流灌水。传说,Tango有一大“水王”,他不但喜欢发贴,还会回复其他ID发的每个帖子。坊间风闻该“水王”发帖数目超过了帖子总数的一半。如果你有一个当前论坛上所有帖子(包括回帖)的列表,其中帖子作者的ID也在表中,你能快速找出这个传说中的Tango水王吗?”

  两个问题殊途同归,都是快速查找数组中出现次数超过一半的元素。

  最直接的解法:对数组进行排序,取n/2 + 1个元素即为所求,这种算法的复杂度最坏的情况下是O(n^2),平均情况下是O(n*log2n)。

  另一种方式:可以根据不同就抵消,相同就增一的计算器完成。设置一个当前值和当前值的计数器,初始化当前值为数组首元素,计数器值为1,然后从第二个元素开始遍历整个数组,对于每个被遍历到的值a[i]

1 如果a[i]==currentValue,则计数器值加1

2 如果a[i] != currentValue, 则计数器值减1,如果计数器值小于0,则更新当前值为a[i],并将计数器值重置为1

#include <stdio.h>
#include <stdlib.h>

int FindMoreValue(int arr[], int n){
        int i;
        int curr_count = 1;
        int curr_value = arr[0];
        for(i = 1; i < n; i++){
                if(arr[i] == curr_value){
                        curr_count++;
                }else{
                        curr_count--;
                        if(curr_count < 0){
                                curr_value = arr[i];
                                curr_count = 1;
                        }
                }
        }
        if(curr_count > 0){
                return curr_value;
        }else{
                //不存在出现次数超过一半的元素
                return -1;
        }
}

int main(int argc, char * argv[]){
        int arr[10] = {1,1,1,1,1,1,2,3,4,5};
        int value = FindMoreValue(arr, 10);
        printf("Find Value:%d\n", value);
}

如果要查找数组中出现次数超过1/3的两个元素呢?

#define NAN (0.0 / 0.0)

int FindMore(int arr[], int n, int cans[2]){
        int i;
        if(n < 2){
                return -1;
        }
        int times[2];
        times[0] = times[1] = 0;
        cans[0] = cans[1] = NAN;
        for(i = 0; i < n; i++){
                if(arr[i] == cans[0]){
                        times[0]++;
                }else if(arr[i] == cans[1]){
                        times[1]++;
                }else{
                        times[0]--;
                        times[1]--;
                        if(times[0] < 0){
                                cans[0] = arr[i];
                                times[0] = 1;
                        }else if(times[1] < 0){
                                cans[1] = arr[i];
                                times[1] = 1;
                        }
                }
        }
        return 0;
}

以此类推,求出现次数超过1/4的三个元素等等。



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值