Boyer-Moore 算法

問題定義

給定一個長度爲 n的數組:java

int[] nums

其中有一個數,它出現的次數大於n/2,稱爲主要元素,找到它。python

看起來不算是個難題,但好玩。算法

這是一個投票問題,能夠模擬咱們在投票表決時的計票過程。用一個hash table或者dictionary,數組中的數做爲key,它們出現的次數爲value。本文想討論的是下邊這些算法。數組

1. 常看法法

1.1 排序

結論很簡單:排序完以後,主要元素必然在下標n/2的位置。看下面兩個例子就很清楚了:code

nums:    1,  1,  1,  2,  2
  i      0   1   2   3   4
n/2
=5/2
=2
nums[2]=1
主要元素是最小的數,排序後集中在最左邊
nums:    1,  1,  2,  2,  2
  i      0   1   2   3   4
n/2
=5/2
=2
nums[2]=2
主要元素是最大的數,排序後集中在最右邊

若是主要元素既不是最大的也不是最小的,那主要元素集中在中間一段,包括n/2。Python一句搞定:排序

def majorityElement(self, nums):
        return sorted(nums)[len(nums)/2]

分析:元素是int型,沒有限制更小的範圍,基於比較的排序算法,最快O(nlogn)。get

1.2 位操做

這裏設int爲32位整數。咱們對這些數以二進制的形式,逐位觀察,嘗試構造出主要元素來。對32位中的每一位,若是1佔多數,則主要元素的對應位爲1,不然爲0。hash

nums:  1,  2,  3,  3,  3
Binary:
  1:   0b0000....0001
  2:   0b0000....0010
  3:   0b0000....0011
  3:   0b0000....0011
  3:   0b0000....0011

major: 0b0000....0011

Java實現:it

public int majorityElement(int[] nums) {
      int res=0,major=nums.length/2;
      for (int i=31;i>=0;i--){
          int pos=0;
          for(int n:nums)
              pos+=(n>>i)&1;
          pos=pos>major? 1:0;
          res|=pos<<i;
        }
      return res;
    }

分析:時間複雜度爲O(n),帶個係數32,實際工做起來仍是很快的。io

2. Boyer-Moore 算法

提出Boyer-Moore 算法的論文

基本思想:

比較直觀的解釋:在數組中找到兩個不相同的元素並刪除它們,不斷重複此過程,直到數組中元素都相同,那麼剩下的元素就是主要元素。

思想並不複雜,可是要憑空想出這個算法來也不是件容易的事。另外,給咱們的是數組,直接在裏面刪除元素是很費時的。取而代之,能夠利用一個計數變量來實現。

def majorityElement(self, nums):
    count,major=0,0
    for n in nums:
        if count==0:
            major=n
        if major==n:
            count+=1
        else:
            count-=1
    return major

對於上面的代碼:

  1. 先隨意肯定一個候選元素,count是候選元素的計數,當遇到一個跟候選元素不一樣的元素時,二者數量上抵消一個,count減1。一旦count變成0,就從新找一個候選元素。

  2. 當遇到一個與候選元素不一樣的元素時,就要抵消。對於候選元素和當前元素,可能存在兩種狀況:
    A. 二者中有一個正好是主要元素

B. 二者都不是主要元素

對於狀況 A,抵消事後,主要元素仍是主要元素;對於狀況 B,能夠說主要的元素的地位獲得了鞏固。因此算法最終能找到主要元素。

相關文章
相關標籤/搜索