摩尔投票算法-leetcode数组出现次数超过一半和1/3的元素。

1、剑指 Offer 39. 数组中出现次数超过一半的数字[1]

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

摩尔投票算法是基于这个事实:每次从序列里选择两个不相同的数字删除掉(抵消),最后剩下一个数字或几个相同的数字,就是出现次数大于总数一半的那个

目标:不断删除2个不同数字,直到无法删除。

对实现过程的理解:假设我们有2个隐形数组, array, result分别表示当前无法删除的元素和删除之后剩下的元素。

例:输入:{1,2,1,3,1,1,2,1,5}

遍历数组

1)从第一个元素1开始,由于目前array为空,无其它元素可以和1一起删除,所以暂时无法删除,加入array,array:{1}, result由于未删除任何元素,仍是{1,2,1,3,1,1,2,1,5}。

2)对第二个元素2,可以和之前扫描到的1一起删除,array:{ }, result: {1,3,1,1,2,1,5}。

3)4)对与后面2个元素{1, 3}的处理过程同 1)2),此时array:{ }, result: {1,1,2,1,5}。

5)处理同1),此时array:{ 1 }, result: {1,1,2,1,5}。

6)对第六个元素1,虽然此时array非空,但值和1相等,无法抵消,此时array:{ 1,1}, result: {1,1,2,1,5}。

7)对第七个元素2,可以和之前扫描到的1一起删除,此时array:{ 1}, result: {1,1,5}。

8)对第八个元素1,虽然此时array非空,但值和1相等,无法抵消,此时array:{ 1,1}, result: {1,1,5}。

9)对第九个元素5,可以和之前扫描到的1一起删除,此时array:{1}, result: {1}。

这个过程就是删除(抵消)了(1,2),(1,3),(1,5)剩下了一个1。

对array数组观察可以发现,array只能同时存储一种数值,因此可以采用 两个遍历majority, count分别代表array数组元素的数值,和数组长度。过程如下:

设当前扫描的元素为x,若count=0,即array为空,不存在可抵消数字,则将当前数字加入array,即majority=x;

若majority=x, 当前数字与前一个相同,无法抵消,加入array, count++;

若majority!=x, 当前数字与前一个不同,抵消, count--;

代码(c++)

int majorityElement(vector& nums) {
        //摩尔投票法
        int majority = 0, count = 0; //majority记录array里的元素,count记录array长度
        for (auto x: nums)
        {
            if (count == 0)
                majority = x;

            if (majority == x)
                count++;
            else
                count--;
        }
        return majority;
    }

Leetcode229.求众数

给定一个大小为 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。

前面一题的升级版,且不保证一定存在众数。

和前面思路一致,但是array数组最多存在2个不同元素,因为出现超过 ⌊ n/3 ⌋ 次的元素最多2个。

用cand1, cand2表示2个候选元素值,cnt1, cnt2表示元素数量。

    vector majorityElement(vector& nums) {
        int cand1 = 0, cand2 = 0, cnt1 = 0, cnt2 = 0;
        for (auto x: nums)
        {
            if (cnt1 == 0  && cand2 != x)
                cand1 = x;
            if (cand1 == x)
                cnt1++; 
            else if (cand2 == x)
                cnt2++; 
            else if (cnt1 == 0){
                cand1 = x;
                cnt1++; 
            }
            else if (cnt2 == 0){
                cand2 = x;
                cnt2++; 
            }    
            else { // x!=cand1 && x!=cand2
                cnt1--;
                cnt2--;
            }
        }

        // 统计cand1, cand2出现次数,若> ⌊ n/3 ⌋,则加入结果
        cnt1 = cnt2 = 0;
        for (auto x: nums)
        {
            if (x == cand1) 
                cnt1++;
            else if (x == cand2)    
                cnt2++;
        }

        vector res;
        if (cnt1>nums.size()/3)
            res.push_back(cand1);
        if (cnt2>nums.size()/3)
            res.push_back(cand2);   

        return res;
    }

题目

[1] https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/

[2] https://leetcode-cn.com/problems/majority-element-ii/

参考

[3]https://www.zhihu.com/question/49973163

 

 

 

你可能感兴趣的:(c++)