題目:數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。
方法一:基于Partition函數的O(n)算法
數組中有一個數字出現的次數超過了數組長度的一半,那么這個數一定是這個數組的中位數。我們需要找到這個數組的第n/2大的數字。所以問題轉化成找數組中第k大的數這樣的問題。
跟快速排序的Partition函數一樣,我們隨機選擇數組中的一個數字,調整數組中數字的順序,使得比選中數字小的都在它的左邊,其它的都在它右邊。如果這個選中的數字的下標剛好是n/2,那么這個數字就是數組中的中位數。如果它的下標大于n/2,那么中位數應該位于它的左邊,如果它的下標小于n/2,那么中位數位于它的右邊。
方法二:
在遍歷數組的時候保存兩個值:一個是數組中的一個數字,一個是次數。當遍歷下一個數字的時候,如果上一個數字和之前保存的數字相同,則次數加1,如果不同,則次數減1。如果次數為零,則需要保存下一個數字,并把次數設為1。
下面的Python代碼分別實現了上面兩種方法:
#encoding=utf8
'''
題目:數組中有一個數字出現的次數超過數組長度的一半,找出這個數字
'''
def partition(num_list, start, end):
'''將num_list從start開始,到end結束的部分分組,以start位置的數字為基準,返回基準最后所在的位置'''
pivot = num_list[start]
while start < end:
while start < end and num_list[end] >= pivot:end -= 1
if start < end:num_list[start] = num_list[end]
while start < end and num_list[start] <= pivot:start += 1
if start < end:num_list[end] = num_list[start]
num_list[start] = pivot
return start
def find_half_num_1(num_list):
'''返回num_list中間的數字'''
if type(num_list) != type([]) or len(num_list) == 0:
return None
start = 0
end = len(num_list) - 1
middle = end / 2
index = partition(num_list, start, end)
while index != middle:
if index > middle:
end = index - 1
index = partition(num_list, start, end)
else:
start = index + 1
index = partition(num_list, start, end)
return num_list[middle]
def find_half_num_2(num_list):
if type(num_list) != type([]):
return None
result = None
time = 0
for i in range(0, len(num_list)):
if time == 0:
result = num_list[i]
time = 1
else:
if num_list[i] == result:
time += 1
else:
time -= 1
return result
if __name__ == '__main__':
l_1 = [1,2,3,4,5,6,7,8,2,2,2,2,2,2,2,2,2,2,2,2]
l_2 = []
l_3 = [1,2,3,4,5,6,7,8,9,9,9,9,9,9,9,9,9,9,9,9]
l_4 = None
l_5 = [5]
print find_half_num_1(l_1)
print find_half_num_1(l_2)
print find_half_num_1(l_3)
print find_half_num_1(l_4)
print find_half_num_1(l_5)
print find_half_num_2(l_1)
print find_half_num_2(l_2)
print find_half_num_2(l_3)
print find_half_num_2(l_4)
print find_half_num_2(l_5)