給定一個大小爲 n 的數組,找到其中的衆數。衆數是指在數組中出現次數大於 ⌊ n/2 ⌋ 的元素。
你可以假設數組是非空的,並且給定的數組總是存在衆數。
示例 1:
輸入: [3,2,3]
輸出: 3
示例 2:
輸入: [2,2,1,1,1,2,2]
輸出: 2
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/majority-element
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
解法一:Boyer-Moore 投票算法
想法
如果我們把衆數記爲 +1+1 ,把其他數記爲 -1−1 ,將它們全部加起來,顯然和大於 0 ,從結果本身我們可以看出衆數比其他數多。
算法
本質上, Boyer-Moore 算法就是找 nums 的一個後綴 sufsuf ,其中 suf[0]suf[0] 就是後綴中的衆數。我們維護一個計數器,如果遇到一個我們目前的候選衆數,就將計數器加一,否則減一。只要計數器等於 0 ,我們就將 nums 中之前訪問的數字全部 忘記 ,並把下一個數字當做候選的衆數。直觀上這個算法不是特別明顯爲何是對的,我們先看下面這個例子(豎線用來劃分每次計數器歸零的情況)
[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]
首先,下標爲 0 的 7 被當做衆數的第一個候選。在下標爲 5 處,計數器會變回0 。所以下標爲 6 的 5 是下一個衆數的候選者。由於這個例子中 7 是真正的衆數,所以通過忽略掉前面的數字,** 我們忽略掉了同樣多數目的衆數和非衆數或者更多的非衆數 **。因此, 7 仍然是剩下數字中的衆數。
[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 5, 5, 5, 5]
現在,衆數是 5 (在計數器歸零的時候我們把候選從 7 變成了 5)。此時,我們的候選者並不是真正的衆數,但是我們在 遺忘 前面的數字的時候,要去掉相同數目的衆數和非衆數(如果遺忘更多的非衆數,會導致計數器變成負數)。
因此,上面的過程說明了我們可以放心地遺忘前面的數字,並繼續求解剩下數字中的衆數。最後,總有一個後綴滿足計數器是大於 0 的,此時這個後綴的衆數就是整個數組的衆數。
作者:LeetCode
鏈接:https://leetcode-cn.com/problems/majority-element/solution/qiu-zhong-shu-by-leetcode-2/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
程序:
class Solution(object):
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
count = 0
candidate = None
for num in nums:
if count == 0:
candidate = num
count += 1
else:
count += (1 if num == candidate else -1)
if count >0:
return candidate
解法二:排序
如果所有數字被單調遞增或者單調遞減的順序排了序,那麼衆數的下標爲 n/2。(當n爲偶數時,下標爲n/2+1)
class Solution(object):
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums.sort()
return nums[len(nums)//2]
解法三:哈希表
class Solution(object):
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
counts = collections.Counter(nums)
return max(counts.keys(), key=counts.get)