1. 程式人生 > >摩爾投票演算法(Boyer–Moore majority vote algorithm)

摩爾投票演算法(Boyer–Moore majority vote algorithm)

問題描述:

1. The majority vote problem is to determine in any given sequence of choices whether there is a choice with more occurrences than half of the total number of choices in the sequence and if so, to determine this choice. Note how this definition contrasts with the mode in which it is not simply the choice with the most occurrences, but the number of occurrences relative to the total length of the sequence. Mathematically, given a finite sequence (length n) of numbers, the object is to find the majority number defined as the number that appears more than ⌊ n/2 ⌋ times.

2. 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.

演算法描述:

The algorithm is carried out in two steps:

  1. Eliminate all elements except one.
    Iterating through the array of numbers, maintain a current candidate and a counter initialized to 0. With the current element x in iteration, update the counter and (possibly) the candidate: if the counter is 0, set the current candidate to x and the counter to 1. If the counter is not 0, 
    increment or decrement
     the counter based on whether x is the current candidate.
  2. Determine if the remaining element is a valid majority element.
    With the candidate acquired in step 1, iterate through the array of numbers and count its occurrences. Determine if the result is more than half of the sequence's length. If so, the candidate is the majority. Otherwise, the sequence doesn't contain a majority.

Note that the counter can be a maximum of {\displaystyle n}n which requires {\displaystyle O(\log n)}O(\log n) space. In practice, however, a constant number of bits should suffice as a {\displaystyle 128}{\displaystyle 128} bit counter can go upto {\displaystyle 2^{128}}2^{128} which is large enough for any practical computation. The time complexity remains {\displaystyle O(n)}O(n), even considering the amount of time it takes to increment the counter because it can be incremented in constant amortized time.

演算法實現:

1. Given a finite sequence (length n) of numbers, the object is to find the majority number defined as the number that appears more than ⌊ n/2 ⌋ times. 
import java.util.*;
public class MajorityVote {
    public int majorityElement(int[] num) {
        int n = num.length;
        int candidate = num[0], counter = 0;
        for (int i : num) {
            if (counter == 0) {
                candidate = i;
                counter = 1;
            } else if (candidate == i) {
                counter++;
            } else {
                counter--;
            }
        }

        counter = 0;
        for (int i : num) {
            if (i == candidate) counter++;
        }
        if (counter <= n / 2) return -1;
        return candidate;

    }
    public static void main(String[] args) {
        MajorityVote s = new MajorityVote();
        System.out.format("%d\n", s.majorityElement(new int[] {1, 2, 3}));
        System.out.format("%d\n", s.majorityElement(new int[] {2, 2, 3}));
    }
}
2. 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.

分析:
因為要找出的是出現次數大於⌊ n/3 ⌋的元素,因此最多隻可能存在兩個這樣的元素,而且要求O(1)的空間複雜度,因此只能使用摩爾投票法。首先我們遍歷一遍陣列找出兩個候選元素,接著再遍歷一遍陣列,判斷候選元素的出現次數是否超過三分之一即可。我們如何確定兩個候選元素呢?當有候選元素未設定時,先將當前遍歷到的元素設定為候選元素。若遍歷到的元素和其中一個候選元素相等時,候選元素的計數器加一,若和兩個候選元素都不相等,則兩個候選元素的計數器都減一。
其實摩爾投票法的本質就是將元素進行分組,每組中都是不同的元素,最後剩下的那些元素就可能是出現次數最多的元素。例如上文中的解法就是將所有元素分成若干個三元組,每組中的數字都是各不相同的。如果一個元素出現的次數超過了三分之一,那麼它必然在剩下的元組中存在,因此它能成為候選元素。

public class Solution {
    public List<Integer> majorityElement(int[] nums) {
        int num1 = 0, num2 = 1;
        int count1 = 0, count2 = 0;
        for(int num: nums) {
            if (count1 == 0) {
                num1 = num;
                count1 = 1;
            } else if (num1 == num) {
                count1 ++;
            } else if (count2 == 0) {
                num2 = num;
                count2 = 1;
            } else if (num2 == num) {
                count2 ++;
            } else {
                count1 --;
                count2 --;
                if (count1 == 0 && count2 > 0) {
                    num1 = num2;
                    count1 = count2;
                    num2 = 0;
                    count2 = 0;
                }
            }
        }
        if (count1 > 0) {
            count1 = 0;
            for(int num: nums) if (num1 == num) count1 ++;
        }
        if (count2 > 0) {
            count2 = 0;
            for(int num: nums) if (num2 == num) count2 ++;
        }
        List<Integer> results = new ArrayList<>();
        if (count1*3>nums.length) results.add(num1);
        if (count2*3>nums.length) results.add(num2);
        return results;
    }
}

Reference:

1. https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_majority_vote_algorithm

2. Moore的主頁上有這個演算法的介紹:A Linear Time Majority Vote Algorithm 和 這個演算法的一個簡單示例演示,連結如下:

http://www.cs.utexas.edu/~moore/best-ideas/mjrty/index.html

3. https://leetcode.com/problems/majority-element-ii/