天天看点

Majority Number I II IIIMajority Number I II III

Majority Number I II III

一个寻众数的问题。

多数投票算法 Boyer–Moore majority vote algorithm

  • Majority Number I II III
    • Majority Number
    • Majority Number II
    • Majority Number III

Majority Number

Leetcode:169. Majority Element

Lintcode:46. Majority Number

Given an array of integers, the majority number is the number that occurs more than half of the size of the array. Find it.

Notice

You may assume that the array is non-empty and the majority number always exist in the array.

本题是一个求众数问题,也是一个投票问题。需要找到数组中出现次数超过半数的元素。

本问题可以用贪心方法求解。由于本题中的众数出现次数超过 ⌊n/2⌋ ⌊ n / 2 ⌋ 。

可以将本问题看做超过半数有效的投票问题。任取数组 A A 中一个元素AiAi将其看做目标众数的候选值,其形成候选数组 B B 加入AiAi。

Ai A i 是否为结果的关键是,候选数组 B B 能否构成以AiAi为众数的 A A 的子数组。

这时,考虑Aj,i≠jAj,i≠j与 Ai A i 的值。有两种情况。

  1. Ai=Aj A i = A j

    此时将 Aj A j 加入数组 B B

  2. Ai≠AjAi≠Aj

    这时可以看出在数组 A A 中删去 Ai,AjAi,Aj并不影响数值 Ai,Aj A i , A j 在数组中是众数的可能性。

    因为,众数在数组中一定出现半数以上。

    但删的是两个不相同元素,假设其中一个是正确答案,则它与非众数元素同时减少一个,答案元素仍超过半数。

    如果,两个都不是正确答案,删去这两个元素。则正确答案占比仍超过半数。

    综上所述,这时抛弃 Aj A j 并删除 B B 中的一个 AiAi。

    如果, 这时数组 B B 被删空了,就再从数组 AA的剩余元素中选一个候选重复上述工作最后 B B 中剩余元素即为最终答案。

我们可以看出数组 BB可以简化为 Ai A i 的计数,添加为 + + ,删除为 −−。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int candidate = nums[];    //指定一个候选元素
        int count = ;              //数组B计数开始
        for (int i =  ; i < nums.size() ; i ++) {
            if (candidate == nums[i])
                //如果与候选元素相同,对数组B进行添加
                count++;
            else
                //如果与候选元素不同,对数组B进行删去
                count--;
            if (count == ) {
                //如果数组B已被删空则重新选定一个候选元素
                candidate = nums[++i];
                count++;
            }
        }
        return candidate;
    }
};
           

Majority Number II

Leetcode:229. Majority Element II

Lintcode:47. Majority Number II

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorithm should run in linear time and in O(1) space.

Lintcode:47. Majority Number II Notice

There is only one majority number in the array.

本题是上一题的简单拓展,众数从超过半数变为超过 ⌊n/3⌋ ⌊ n / 3 ⌋ 。候选众数变为两个。这时需要对最终得到的候选众数进行验证。

注意到,LeetCode的题中众数不唯一。

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        //有几个候选众数
        int k = ;
        //满足是众数的条件
        int floor = nums.size() / ;
        //建立候选众数的容器
        map<int , int> candidates;
        //进行投票模拟
        for (int i =  ; i < nums.size() ; i ++) {
            //如果实际候选数小于应有候选数,加入新的候选数
            if (candidates.size() < k) {
                //如果与已有候选数重复了,已有候选数进行计数添加。否则,添加候选数
                if (candidates.find(nums[i]) != candidates.end())
                    candidates[nums[i]]++;
                else
                    candidates[nums[i]] = ;
            } else {
                //如果实际候选数等于应有候选数
                if (candidates.find(nums[i]) != candidates.end())
                    //如果与候选数中的其中一个相等,则未破坏子数组的特性,对候选数进行计数添加。
                    candidates[nums[i]]++;
                else
                    //如果与候选数都不相等,则从nums中删去子数组 A_i,A_j,A_k
                    for (auto j = candidates.begin() ; j != candidates.end() ; ) {
                        j->second--;
                        if (j->second == )
                            j = candidates.erase(j);
                        else
                            j++;
                    }
            }
        }
        //完成对候选数的验证
        for (auto c = candidates.begin() ; c != candidates.end() ; c ++) {
            c->second = ;
        }
        for (int a : nums) {
            if (candidates.find(a) != candidates.end())
                candidates[a]++;
        }
        vector<int> res;
        for (auto it : candidates) {
            if (it.second > floor)
                res.push_back(it.first);
        }
        return res;
    }
};
           

Majority Number III

Lintcode:48. Majority Number III

Given an array of integers and a number k, the majority number is the number that occurs more than 1/k of the size of the array.

Find it.

Notice

There is only one majority number in the array.

本题其实在在上一题中已经给出答案了。

class Solution {
public:
    /*
     * @param nums: A list of integers
     * @param k: An integer
     * @return: The majority number
     */
    int majorityNumber(vector<int> &nums, int k) {
        // write your code here
        unordered_map<int , int> candidate;
        int size = k - ;
        for (int i =  ; i < nums.size() ; i++) {
            if (candidate.size() < size) {
                if (candidate.find(nums[i]) == candidate.end()) {
                    candidate[nums[i]] = ;
                } else {
                    candidate[nums[i]]++;
                }
            } else {
                if (candidate.find(nums[i]) == candidate.end()) {
                    auto j = candidate.begin();
                    while (true) {
                        if (j == candidate.end()) {
                            break;
                        }
                        (j -> second)--;
                        if (j -> second == ) {
                            j = candidate.erase(j);
                        } else {
                            j++;
                        }
                    }
                } else {
                    candidate[nums[i]]++;
                }
            }
        }
        for (auto i = candidate.begin() ; i != candidate.end() ; i++) {
            i -> second = ;
        }
        int max =  , res = ;
        for (int i =  ; i < nums.size() ; i++) {
            candidate[nums[i]]++;
            if (candidate[nums[i]] > max) {
                max = candidate[nums[i]];
                res = nums[i];
            }
        }
        return res;
    }
};
           
class Solution {
public:
    /*
     * @param nums: A list of integers
     * @param k: An integer
     * @return: The majority number
     */
    int majorityNumber(vector<int> &nums, int k) {
        // write your code here
        //满足是众数的条件
        int floor = nums.size() / k;
        //建立候选众数的容器
        map<int , int> candidates;
        //进行投票模拟
        for (int i =  ; i < nums.size() ; i ++) {
            //如果实际候选数小于应有候选数,加入新的候选数
            if (candidates.size() < k) {
                //如果与已有候选数重复了,已有候选数进行计数添加。否则,添加候选数
                if (candidates.find(nums[i]) != candidates.end())
                    candidates[nums[i]]++;
                else
                    candidates[nums[i]] = ;
            } else {
                //如果实际候选数等于应有候选数
                if (candidates.find(nums[i]) != candidates.end())
                    //如果与候选数中的其中一个相等,则未破坏子数组的特性,对候选数进行计数添加。
                    candidates[nums[i]]++;
                else
                    //如果与候选数都不相等,则从nums中删去子数组 A_i,A_j,A_k
                    for (auto j = candidates.begin() ; j != candidates.end() ; ) {
                        j->second--;
                        if (j->second == )
                            j = candidates.erase(j);
                        else
                            j++;
                    }
            }
        }
        //完成对候选数的验证
        for (auto c = candidates.begin() ; c != candidates.end() ; c ++) {
            c->second = ;
        }
        for (int a : nums) {
            if (candidates.find(a) != candidates.end())
                candidates[a]++;
        }
        vector<int> res;
        for (auto it : candidates) {
            if (it.second > floor)
                res.push_back(it.first);
        }
        return res[];
    }
};