给出一个数组,从中找到第K小的数,这可以算是一个经典的算法题了。今天在这里给出几种解法:
1.最简单的方法,就是对数组进行排序,然后选取其中前K个数即可。排序算法一般我们可以用快速排序,这样的话时间复杂度就是O(NlgN)。但是以上这种方法还是显得有些慢,那有没有比它更快的方法呢?
2.参考快速排序,快排在递归的过程中,需要不断将数组分为两部分,且一部分总是小于另外一部分,我们可以用这种方法对数组进行递归,直到分出前K个元素作为几个集合为止。代码如下:
def partition(numbers, begin, end):
assert begin <= end
if begin == end:
return begin
mid = numbers[begin]
index = begin + 1
for i in xrange(begin+1, end+1):
if numbers[i] > mid:
continue
else:
tmp = numbers[i]
numbers[i] = numbers[index]
numbers[index] = tmp
index += 1
tmp = numbers[index-1]
numbers[index-1] = mid
numbers[begin] = tmp
return index-1
def getLeastKnumber(numbers, k):
l = len(numbers)
begin = 0
end = l-1
index = partition(numbers, begin, end)
while index != k-1:
if index < k-1:
begin = index + 1
else:
end = index - 1
index = partition(numbers, begin, end)
return numbers[index]
该方法的时间复杂度为O(N)。
3.以上的两个方法都需要对所有数据遍历多次,如果数据量太大,都没办法全部装进内存了,此时也就没法对数组排序,那么此时该怎么做呢?
我们可以先拿出前K个元素建一个最大堆,堆顶元素是其中最大的数。然后遍历数组其他元素,与堆顶的元素进行比较。
有这么几种情况:
遍历的数>=堆顶元素,那么可以跳过,因为我们要寻找第K小的数,遍历的数比K个数中最大那个都要大,那它肯定不是第K小的数(有K个数都要比它小呢)。
遍历的数<堆顶元素,那么这个数和堆顶元素互换,并重新维护堆。
一直到遍历结束,取出堆顶的数就是第K小的数了。
该算法的时间复杂度为O(NlgK)
这个逻辑比较简单,就不写代码了。