摩爾投票演算法( Boyer-Moore Voting Algorithm)
阿新 • • 發佈:2018-12-09
摩爾投票演算法也可以叫做多數投票演算法,是我在看到 leetcode 169(Majority Element)題目時看到的演算法。這篇文章從 leetcode 169(Majority Element)出發講解摩爾投票演算法的原理和優勢,同時從 leetcode 229(Majority Element2)出發講解摩爾投票演算法的改進和推廣。(本文所有程式碼都是python程式碼)
一、Majority Element題目介紹:給定一個長度為n的陣列的時候,找出其中的主元素,即該元素在陣列中出現的次數大於n/2的取整。題目中已經假定所給的陣列一定含有元素,且主元素一定存在。一下是一些常用方法:
1,用字典遍歷每個元素,並計數:
dic = {}
for x in nums:
if x in dic:
dic[x] += 1
else:
dic[x] = 1
for key,value in dic.items():
if value > len(nums)/2:
return key
2,排序法:排序後,出現次數大於一半的肯定在中間
nums.sort()
return nums[len(nums)//2]
二、摩爾投票演算法:摩爾投票演算法的時間和空間都很低,時間複雜度為O(n),空間複雜度為O(1),這也是選擇遮蓋演算法的原因。
1,演算法原理:每次從陣列中找出一對不同的元素,將它們從陣列中刪除,直到遍歷完整個陣列。由於這道題已經說明一定存在一個出現次數超過一半的元素,所以遍歷完陣列後陣列中一定會存在至少一個元素。
- 演算法在區域性變數中定義一個序列元素(m)和一個計數器(i),初始化的情況下計數器為0;
- 演算法依次掃描序列中的元素,當處理元素x的時候,如果計數器為0,那麼將x賦值給m,然後將計數器(i)設定為1;
- 如果計數器不為0,那麼將序列元素m和x比較,如果相等,那麼計數器加1,如果不等,那麼計數器減1。
- 處理之後,最後儲存的序列元素(m),就是這個序列中最多的元素。
(如果不確定是否儲存的元素m是最多的元素,還可以進行第二遍掃描判斷是否為最多的元素)
2,演算法虛擬碼:
初始化元素m=0,計數器count=0;
遍歷陣列中的每個數x:
if i = 0:
m = x and count = 1
else if m = x:
count = count + 1
else:
count = count − 1
Return m
3,Majority Element的摩爾投票演算法求解:
num,count = nums[0],0
for x in nums:
if count == 0:
num,count = x,1
elif x == num:
count += 1
else:
count -= 1
return num
三、摩爾投票演算法的改進:
1,題目: LeetCode 229 [Majority Element II]
給定一個整型陣列,找到所有主元素,它在陣列中的出現次數嚴格大於陣列元素個數的三分之一。
演算法:每次刪除三個不相同的數,最後留下的一定是出現次數超過1/3的數,這個思想可以推廣到出現次數超過1/k次的元素有哪些。
- 因為出現次數大於n/3的元素最多隻有兩個,所以最開始可以維護兩個數字(num1,num2)和兩個計數器(counter1,counter2);
- 遍歷陣列,當陣列中元素和num1或者num2相同,對應的counter1或者counter2加1;
- 如果counter1或counter2為0,將遍歷到的該元素賦給num1或者nums2;
- 否則counter1和counter2都減1。
2,python程式碼:
num1,count1 = None,0
num2,count2 = None,0
for x in nums:# 演算法核心,找出主要元素的候選值
if x == num1:
count1 += 1
elif x == num2:
count2 += 1
elif count1 == 0:
num1,count1 = x,1
elif count2 == 0:
num2,count2 = x,1
else:
count1 -= 1
count2 -= 1
count1,count2 = 0,0
for x in nums:# 統計確定候選值是真的主要元素
if x == num1:
count1 += 1
if x == num2:
count2 += 1
res = []
if count1 > len(nums)//3:
res.append(num1)
if count2 > len(nums)//3:
res.append(num2)
return res