解题思路
- 思路一:遍历一遍数组并用哈希表统计次数,然后遍历一遍哈希表去查找次数符合题目要求的数 时间复杂度:o(n),空间复杂度o(n)
- 思路二:先排序然后取中间的元素,则必为符合题意的数 时间复杂度:o(nlogn),空间复杂度o(1)或0(n)
- 思路三:快排思想,停止条件是partition的k正好为长度的一半的索引值,此时的索引对应的值必定符合题意。相较于思路二,该算法并不需要对数组中的所有值排序
【反证法:假设该值value大于题意值m,则前半区间必定小于value,m必定全部位于前半区间,由于m的个数大于区间长度一半,那么m必定会覆盖到value,value的索引值会被挤到大于区间一半,与假设不符;value<m同理,m位于后半段并必定会使value索引值往前靠;综上,当k为区间长度一半时,array[k]必为m】
代码实现:[实际提交时会超时,看了下超时用例是会使得快排复杂度为o(n^2)的情况emm]
def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
start, end = 0, len(numbers)-1
while True:
m = self.quicksort(numbers, start, end)
if m == len(numbers)//2:
print(numbers)
return numbers[len(numbers)//2]
elif m < len(numbers)//2:
start = m + 1
else:
end = m - 1
def quicksort(self, numbers, start, end)-> int:
i, j, pivot = start, end, numbers[start]
while i < j:
while numbers[j] >= pivot and j > i: j-=1
numbers[i] = numbers[j]
while numbers[i] <= pivot and j > i: i+=1
numbers[j] = numbers[i]
numbers[i] = pivot
return i
- 思路四:
遇见一个友军就抱成团,遇见一个敌军就同归于尽,那么最后战场上剩余的肯定就是人数(出现次数)最多的那个队伍(数字)的思想。
先选取一个候选者,然后往后遍历,当遇见一个相同的数计数器就加一否则减一,当计数器为0时,更换下一位位候选者,重新操作,直至遍历完所有元素,最后一个候选者一定是数量过半的数。
证明:假设第一个候选者是要找的x,那么当count为0时,这段区间友军和敌军各损一半,后半段还是友军比敌军多;假设第一个候选者不是x,那么当count为0时,消耗的敌军一定比友军多【因为可能还有别的敌军去消耗他们】,剩下区间的友军也一定比敌军多。由于每次剩余区间的友军数>敌军,那么一定不可能出现敌军候选者遍历到元素最后的情况,最终只能是友军剩(胜)。
该方法十分巧妙,充分利用题目条件,时间复杂度是o(n),空间复杂度是o(1)while写法
class Solution:
def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
i, lenth = 0, len(numbers)
while i < lenth:
candidate = numbers[i]
count = 1
i += 1
while i < lenth and count != 0:
count = count+1 if numbers[i] == candidate else count-1
i += 1
return candidate
for写法
class Solution:
def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
count = 0
for number in numbers:
if count == 0:
candidate = number
count = count+1 if number == candidate else count-1
return candidate