有这样的一个面试题,求一个数组的第K 大值。
一般人会想到的是下面第一,二种方法,
第一种方法,先排序,再按照索引求值
'''
黄哥Python培训 黄哥所写
Python 3
'''
def get_k_max_value(lst, k):
"""先排序,再按照索引取值,时间复杂度是 O(n log n)"""
lst.sort(reverse=True)
return lst[k - 1]
if __name__ == '__main__':
lst = [3, 7, 12, 2, 6, 18, 11, 9]
k = 3
print(get_k_max_value(lst, k))
第二种方法:
'''
黄哥Python培训 黄哥所写
Python 3
'''
def get_k_max_value(lst, k):
'''先取k个元素到一个list中,再在剩下的len(lst) - k 中和
排序好的lst1 中的最后一个元素比较,比它小抛弃,大,插入到相应位置。
时间复杂度 O(klogk + n * klogk)
'''
lst1 = lst[0:k]
lst2 = lst[k:]
lst1.sort(reverse=True)
for i in lst2:
if i < lst1[-1]:
continue
else:
lst1[-1] = i
lst1.sort(reverse=True)
print(lst1)
return lst1[-1]
if __name__ == '__main__':
lst = [3, 7, 12, 2, 6, 18, 11, 9]
k = 3
print(get_k_max_value(lst, k))
上面二种方法,如果数组元素有几百万之多,当k = 500000 时,上面二个算法都不能在合理的时间里完成。
第三种方法:
在计算机科学中,快速选择(英语:Quickselect)是一种从无序列表找到第k小元素的选择算法。它从原理上来说与快速排序有关。与快速排序一样都由托尼·霍尔提出的,因而也被称为霍尔选择算法。同样地,它在实际应用是一种高效的算法,具有很好的平均时间复杂度,然而最坏时间复杂度则不理想。快速选择及其变种是实际应用中最常使用的高效选择算法。快速选择的总体思路与快速排序一致,选择一个元素作为基准来对元素进行分区,将小于和大于基准的元素分在基准左边和右边的两个区域。不同的是,快速选择并不递归访问双边,而是只递归进入一边的元素中继续寻找。这降低了平均时间复杂度,从O(n log n)至O(n),不过最坏情况仍然是O(n2)。
与快速排序一样,快速选择一般是以原地算法的方式实现,除了选出第k小的元素,数据也得到了部分地排序。
该算法的伪代码
QuickSelect(A, k)
let r be chosen uniformly at random in the range 1 to length(A)
let pivot = A[r]
let A1, A2 be new arrays
# split into a pile A1 of small elements and A2 of big elements
for i = 1 to n
if A[i] < pivot then
append A[i] to A1
else if A[i] > pivot then
append A[i] to A2
else
# do nothing
end for
if k <= length(A1):
# it's in the pile of small elements
return QuickSelect(A1, k)
else if k > length(A) - length(A2)
# it's in the pile of big elements
return QuickSelect(A2, k - (length(A) - length(A2))
else
# it's equal to the pivot
return pivot
'''
黄哥Python培训 黄哥修改
Python 3
'''
import random
def get_k_max_value(lst, k):
'''时间复杂度O(n)'''
if len(lst) == 0:
return None
pivot = random.choice(lst)
lst1, lst2 = [], []
for i in lst:
if i > pivot:
lst1.append(i)
elif i < pivot:
lst2.append(i)
if k <= len(lst1):
return get_k_max_value(lst1, k)
elif k > len(lst) - len(lst2):
return get_k_max_value(lst2, k - (len(lst) - len(lst2)))
return pivot
if __name__ == '__main__':
lst = [3, 7, 12, 2, 6, 18, 11, 9]
k = 3
print(get_k_max_value(lst, k))
总结: 如果没有学习过快速选择算法,一般人是想不到这个算法的,所以要学习已经发明的算法,并应用到工作中或面试中。
如果不学习算法,不会想到第三种方法,那么写出第一,二种算法的代码,就不会通过面试,所以一定要学习算法。
参考文章
TimeComplexity - Python Wiki
QuickSelect
https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E9%80%89%E6%8B%A9
黄哥Python培训是这样训练学员的
黄哥Python培训是这样训练学员的
黄哥Python提醒:转行当程序员修炼之路
黄哥Python提醒:转行当程序员修炼之路
黄哥Python:提醒要转行当程序员的朋友,学习要分先后主次
黄哥Python:提醒要转行当程序员的朋友,学习要分先后主次