Understand and implement the Moore voting algorithm

There is a sequence of hearing the truth, and there is a specialization in the art industry, and that's it. ——Han Yu, "Teacher's Talk"

1 Problem definition

First of all, the Moore voting algorithm does not solve the problem of finding the mode of a group of numbers, it has one more constraint. That is, find the number of occurrences exceeding n/2 among n numbers . That is to say, there are only two results for a given n number, either the number does not exist more than n/2, or the number exists more than n/2, if it does not exist, return does not exist, if it exists, returns the number of times More than n/2.
Leikou Reference: Interview Question 17.10. Main Elements and 169. Most Elements

2 Understanding the algorithm

First of all, the problem can be solved by any algorithm for finding the mode, but the time and space efficiency is better by the Moore voting method, with O(1) space complexity and O(n) time complexity. The Moore voting method makes full use of the condition of exceeding n/2 . I like to understand it with the same end . For example, suppose that the six major sects besieged Guangmingding. There are many Mingjiao followers, and one Mingjiao and the followers of any sect die together. If there are enough Mingjiao followers, then Mingjiao will win, otherwise, Mingjiao will be destroyed.

3 Specific algorithm logic

Traverse the array and maintain two variables, count and num_now, to count the number and value of the most frequent element. Initialize count=0,num_now=nums[0]. These numbers nums[i] (believers) step onto the ring one by one.
Traversing to any number (believers) has 3 results:
1.count=0. That is, the arena is now empty, then board the arena, count=1,num_now=nums[i];
2.count!=0 && num_now==nums[i]. That is, there are people in the ring, all of whom
belong to my sect. Then I will join them, count++; 3.count!=0 && num_now!=nums[i]. That is, there are people in the ring, but they belong to other schools. Let them send someone to die with me, count- -;

4 java implementation

4.1 Likou【169. Most Elements】

class Solution {
    
    
    public int majorityElement(int[] nums) {
    
    
        //维护两个变量
        int count=0;//出现次数
        int num_now=0;//当前的数字
        for(int i=0;i<nums.length;i++){
    
    
            //当前无人,站上擂台
            if(count==0){
    
    
                num_now = nums[i];
                count++;
            }
            //有和我一样的人,站队
            else if(nums[i]==num_now) count++;
            //擂台上的和我不一样,同归于尽
            else count--;
        }
        //返回
        return num_now;
    }
}

4.2 Likou [Interview Question 17.10. Main Elements]
Note that this question is somewhat different from the above question. It does not guarantee that the given array must have a number of occurrences exceeding n/2, so judgment is required.

class Solution {
    
    
    public int majorityElement(int[] nums) {
    
    
        //维护两个变量
        int count=0;//出现次数
        int num_now=0;//当前的数字
        for(int i=0;i<nums.length;i++){
    
    
            //当前无人,站上擂台
            if(count==0){
    
    
                num_now = nums[i];
                count++;
            }
            //有和我一样的人,站队
            else if(nums[i]==num_now) count++;
            //擂台上的和我不一样,同归于尽
            else count--;
        }
        //统计确认是不是大于n/2
        count=0;
        for(int i=0;i<nums.length;i++){
    
    
            if(nums[i]==num_now) count++;
        }
        if(count>nums.length/2) 
            return num_now;
        else 
            return -1;
    }
}

5 Advanced

Force button: 229. Find the Mode II. Given an array of size n, find all the elements that appear more than ⌊ n/3 ⌋ times.
At this time, Guangmingding may not have only one winner, at most two sects will become winners. Therefore, two sets of count and now_num need to be maintained. There are five possibilities when a new number is traversed:
1. Standing on the ring and forming Martial Art 1;
2. Standing on the ring and forming Martial Art 2;
3. Joining Martial Art 1;
4. Joining Martial Art 2;
5. Three people die together .
Many bloggers and Likou's answers are very concise in the judgment sentence, which can be optimized, but you need to think more about it. The point to note here is that when establishing a martial art, you must first determine whether you belong to the other martial art, and you cannot establish two centers. In addition, when counting the number of last occurrences, consider the case where num_now1 and num_now2 are the same number (the input is only one number).

class Solution {
    
    
    public List<Integer> majorityElement(int[] nums) {
    
    
        //保存输出的list
        ArrayList<Integer> out = new ArrayList<Integer>();
        //为空检测
        if(nums.length==0) return out;
        //维护四个变量
        int count1 = 0;//出现次数
        int num_now1 = nums[0];//当前的数字
        int count2 = 0;//出现次数
        int num_now2 = nums[0];//当前的数字
        for (int i = 0; i < nums.length; i++) {
    
    
            //新成立门派1
            if (count1 == 0 && num_now2 != nums[i]) {
    
    
                num_now1 = nums[i];
                count1++;
                continue;
            }
            //新成立门派2
            if (count2 == 0 && num_now1 != nums[i]) {
    
    
                num_now2 = nums[i];
                count2++;
                continue;
            }
            //加入门派1
            if (num_now1 == nums[i]) {
    
    
                count1++;
                continue;
            }
            //加入门派2
            if (num_now2 == nums[i]) {
    
    
                count2++;
                continue;
            }
            //不是上面所有情况,同归于尽
            count1--;
            count2--;
        }
        //统计最多的两个数的个数
        count1 = 0;
        count2 = 0;
        for (int i = 0; i < nums.length; i++) {
    
    
            if (nums[i] == num_now1)
                count1++;
            else if(nums[i] == num_now2)
                count2++;
        }
        //如果超过1/3就返回
        if (count1 > nums.length / 3)
            out.add(num_now1);
        if (count2 > nums.length / 3)
            out.add(num_now2);
        return out;
    }
}

What if the number of occurrences is greater than n/4? What about n/5? How to solve it.

6 Summary

This question does not involve complex data structures, but the application of several if-else is very delicate, worthy of a good taste, the use of continue can also reduce the amount of code. It is better to sum up one question with ten questions, and to extend the derivation by analogy.

Guess you like

Origin blog.csdn.net/weixin_44215363/article/details/108356550