美文网首页基础算法分析实现
算法 - 数组主元素(出现次数超过一半的元素)

算法 - 数组主元素(出现次数超过一半的元素)

作者: erlich | 来源:发表于2022-07-29 19:13 被阅读0次

    题目:

    • 整数数组,包含n个元素
    • 主元素 - 某个元素出现次数 > n/2
    • 是否存在主元素
    • 找出主元素

    举个例子

    数组:[1, 5, 1, 8, 1, 2, 1, 1, 3, 1]

    包含6个1,出现次数超过了半数5

    1就是主元素

    数组:[1, 5, 9, 8, 1, 2, 1, 1, 3, 1]

    包含5个1,出现次数不超过半数5

    没有主元素

    分析

    主要逻辑包含两个要点

    • 无论如何都需要统计元素的出现次数count,或者类似于统计的过程
    • 主元素是哪个元素需要找到

    最直观的思路 - 字典存储统计次数

    用字典把元素当作key,value存储出现的次数

    但是有需要遍历所有的存储key,比较各自出现次数大小

    • 需要开辟额外的字典空间
    • 事件复杂度会额外增加 O(n)

    取巧部分

    key - 主元素,默认取数组第一个当作key

    反正需要统计次数

    则在首次遍历数组的过程中,就统计count

    我们可以不用统计具体每个元素出现的次数,既然主元素的出现次数超过 一半

    • 则让主元素与其他元素竞争,遍历到是key,就count++,否则就 count--,直到为0
    • 如果count == 0,没法--,就替换key,count = 1
    • 如果key存在,那么key一定能竞争过其他所有元素,因为其他所有元素的次数之和不会超过数组元素数量的一半
    • 这样只需要在遍历结束之后,判断count 是否大于0,否则不存在主元素
    • 因为在遍历过程中一直保存着key,是个准key
    • 遍历一次数组,统计key的次数,判断统计的次数 是否 大于 n/2
    • 大于 n/2, 则key就是主元素了

    这种方式比之前的字典方式,省去了空间复杂度

    实现

    void checkKeyElement(int array[], int n) {
        int count = 0;
        int key = array[0];
        
        for (int i = 0; i < n; i++) {
            if (array[i] == key) {
                count++;
            } else {
                if (count > 0) {
                    count--;
                } else {
                    key = array[i];
                    count = 1;
                }
            }
        }
        
        if (count < 1) {
            printf("数组中不存在主元素\n");
            return;
        }
        count = 0;
        for (int i = 0; i < n; i++) {
            if (array[i] == key) {
                count++;
            }
        }
        if (count <= n / 2) {
            printf("数组中不存在主元素\n");
            return;
        }
        printf("数组中存在主元素 %i\n", key);
    }
    

    相关文章

      网友评论

        本文标题:算法 - 数组主元素(出现次数超过一半的元素)

        本文链接:https://www.haomeiwen.com/subject/uvpqwrtx.html