Moore's majority vote algorithm

求n个数中出现次数超过《Moore's majority vote algorithm》的元素。

Moore’s majority vote algorithm可以在O(n)时间内求解问题。算法流程如下:

维护一个计数器和当前候选元素,对数组进行扫描。若计数器为0,将当前元素作为候选元素。若当前元素等于候选元素,则计数器加一,否则减一。扫描完毕时候选元素即为所求,再扫描一次数组统计候选元素个数,若超过《Moore's majority vote algorithm》则为所求。代码如下:

int majorityElement(vector<int>& nums) {
        int candidate, counter = 0, len = nums.size();
        for(int i = 0; i < len; ++i){
            if(counter == 0)
                candidate = nums[i];
            if(nums[i] == candidate)
                ++ counter;
            else
                --counter;
        }
        return candidate;
    }

简单证明如下:循环内candidate代表当前票数最高的元素,遇到与candidate值相同的元素,counter加一,否则减一,当且仅当candidate元素超过《Moore's majority vote algorithm》时,counter才不会被抵消为0。

方法二:位操作

对每一个bit统计该bit在数组元素中出现的次数,若大于《Moore's majority vote algorithm》,则在majority element中该bit定为1。

反证:若存在某一位《Moore's majority vote algorithm》,在数组中出现超过《Moore's majority vote algorithm》次,而在majority element该bit为0。由于majority element中该bit为0,所以该bit中0的个数大于《Moore's majority vote algorithm》,则1的个数不超过《Moore's majority vote algorithm》,与假设矛盾。代码如下:

    int majorityElement(vector<int>& nums) {
        int cnt[32], len = nums.size(), limit = len / 2;
        memset(cnt, 0, sizeof(cnt));
        for(int i = 0; i < 32; ++i){
            int val = 1 << i;
            for(int j = 0; j < len; ++j)
                if(nums[j] & val)
                    ++cnt[i];
        }
        int ans = 0;
        for(int i = 0; i < 32; ++i){
            if(cnt[i] > limit)
                ans += 1 << i;
        }
        return ans;
    }


变形:求n个数中出现次数超过《Moore's majority vote algorithm》的元素。

由于次数超过《Moore's majority vote algorithm》的元素个数不超过两个,所以可以保存当前top2的候选者,counter为0时将该元素作为候选,碰到其他元素,则二者的counter均减一,由于剩下的元素个数小于《Moore's majority vote algorithm》,所以无法将解的counter抵消成0。要注意的细节是:要先将当前元素与两个候选者进行比较,对counter作相应增加,都不匹配时才能对counter为0的候选者进行重置,这是为了保证两个候选者为不同的元素。代码如下:

vector<int> majorityElement(vector<int>& nums) {
        int c1 = INT_MIN, c2 = INT_MIN, counter1 = 0, counter2 = 0;
        int n = nums.size();
        for(int i = 0; i < n; ++i){
            if(nums[i] == c1)
                ++counter1;
            else if(nums[i] == c2)
                ++counter2;
            else if(counter1 == 0)
                c1 = nums[i], counter1 = 1;
            else if(counter2 == 0)
                c2 = nums[i], counter2 = 1;
            else
                --counter1, --counter2;
        }
        counter1 = 0, counter2 = 0;
        for(int i = 0; i < n; ++i){
            if(nums[i] == c1)
                ++counter1;
            else if(nums[i] == c2)
                ++counter2;
        }
        vector<int> ans;
        if(counter1 > n / 3)
            ans.push_back(c1);
        if(counter2 > n / 3)
            ans.push_back(c2);
        return ans;
    }

点赞