題目描述
數組中有一個數字出現次數超過數組長度的一半,請找出這個數字。
例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2
解題思路
第一個想法是排序,時間複雜度O(nlogn)
解法一:基於Partition函數的O(n)算法
數組的特性,如果數組中有一個數字出現的次數超過了數組長度的一半。如果把這個數組排序,那麼排序之後位於數組中間的數組一定就是那個出現次數超過數組長度一半的數字。數組的中位數,長度爲n的數組中的第N/2大的數組。
在隨機快速排序算法的啓發,在隨機快速排序算法中,我們先在數組中隨機選擇一個數字,然後調整數組中數字的順序,使得比選中的數字小數字都排在它的左邊,比選中的數字大的數字都排在它的右邊。如果這個選擇的數字的下標剛好是n/2,那麼這個數字就是數組的中位數。下標大於n/2,那麼中位數位於左邊,接着在左邊部分的數組中查找。如果下標小於n/2,中位數位於右邊。典型的遞歸過程。
解法二:根據數組特點找出O(n)的算法
有一個數字出現的次數超過數組長度的一半,它出現的次數比其他所有數字出現次數的和還要多。考慮在遍歷數組的時候保存兩個值:一個是數組中的一個數字,一個是次數。當我們遍歷到下一個數字的時候,如果下一個數字和我們之前保存的數字相同,則次數加1;如果下一個數字和我們之前保存的數字不同,則次數減1.如果次數爲0,需要保存下一個數字,把次數設爲1.那麼要找的數字肯定是最後一次把次數設爲1時對應的數字。
Python代碼
# -*- coding:utf-8 -*-
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
if not numbers:
return 0
res = numbers[0]
times = 1
length = len(numbers)
for i in range(1, length):
if times == 0:
res = numbers[i]
times = 1
elif res == numbers[i]:
times += 1
else:
times -= 1
import collections
return res if collections.Counter(numbers)[res] * 2 > length else 0