题目:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
牛客网:链接
第一种方法:快排。这个思路应该是最简单的,将整个数组排序,然后取出前k个数据就可以了,这个算法的时间复杂度为nlogn。
# -*- coding:utf-8 -*-
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
length = len(tinput)
if not tinput or k < 0 or k > length:
return []
start = 0
end = length - 1
self.partition(tinput, start, end)
return tinput[:k]
def partition(self, tinput, start, end):
if end <= start:
return start
base = tinput[start]
index1, index2 = start, end
while start < end:
''' 从右往左遍历 如果比base大 就接着遍历 直到比base小 '''
while start < end and tinput[end] >= base:
end -= 1
''' 比base小都赋值给左指针 '''
tinput[start] = tinput[end]
''' 从左往右遍历 如果比base小 就接着遍历 直到比base大 '''
while start < end and tinput[start] <= base:
start += 1
''' 比base大都赋值给右指针 '''
tinput[end] = tinput[start]
'''将base赋值给重合位置'''
tinput[start] = base
self.partition(tinput, index1, start-1)
self.partition(tinput, start+1, index2)
if __name__ == '__main__':
a = Solution()
print(a.GetLeastNumbers_Solution([4,23,23,1], 2))
第二种方法:是在第一种解法上面的一种改进,快速排序的思想大家都已经知道,现在我们只需要最小的k个数,所以如果我们在某次快速排序中,选择的基准的大小刚好是整个数组的第k小的数据,那么在这次排序完成之后,这个基准数之前的数据就是我们需要的(尽管他们并不是有序的)。这个方法同样改变了数组,但是可以将时间复杂度压缩到O(n),只有当我们可以修改输入的数组时可用。
# -*- coding:utf-8 -*-
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
length = len(tinput)
if not tinput or k <= 0 or k > length:
return []
start = 0
end = length - 1
index = self.partition(tinput, start, end)
while index != k-1:
print(index)
print(k-1)
if index > k-1:
index = self.partition(tinput, start, index-1)
elif index < k-1:
index = self.partition(tinput, index+1, end)
return sorted(tinput[:k])
def partition(self, tinput, start, end):
if end <= start:
return start
base = tinput[start]
while start < end:
while start < end and tinput[end] >= base:
end -= 1
tinput[start] = tinput[end]
while start < end and tinput[start] <= base:
start += 1
tinput[end] = tinput[start]
tinput[start] = base
return start
第三种方法(海量数据):创建一个大小为k的数据容器来存储最小的k个数字,接下来每次从输入的n个整数中读入一个数。如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中;如果容器中已有k个数字了,也就是容器已满,此时我们不能再插入新的数字而只能替换已有的数字。找出这已有的k个数中的最大值,然后拿这次待插入的整数和最大值进行比较,如果待插入的值比当前已有的值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还要大,那么这个数不可能是最小的k个整数之一,于是我们抛弃这个整数。我们可以使用最大堆来实现这个容器,在最大堆中,根节点的值总是大于它的子树中任意节点的值。于是我们可以在O(1)时间内得到已有的k个数字中的最大值,但需要O(logk)时间完成删除及插入操作。建堆时间是O(k),调整一次的时间O(logk),一共调整k次,所以堆排序的时间是O(klogk)。
堆排序:点我
# -*- coding:utf-8 -*-
def HeadAdjust(input_list, parent, length):
'''
函数说明:堆调整,调整为最大堆
Parameters:
input_list - 待排序列表
parent - 堆的父结点
length - 数组长度
'''
temp = input_list[parent] # temp保存当前父节点
child = 2 * parent + 1 # 先获得左孩子
while child < length:
# 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
if child + 1 < length and input_list[child] < input_list[child+1]:
child += 1
# 如果父节点的值比孩子结点大 跳出这次循环
# 一定要用temp比 因为在没有最终调整好之后 temp是不能赋值给结点的
if temp >= input_list[child]:
break
# 把孩子结点的值赋给父结点
input_list[parent] = input_list[child]
# 选取孩子结点的左孩子结点,继续向下筛选
parent = child
child = 2 * parent + 1
'''把最初的父节点赋值给经过筛选之后的父节点'''
input_list[parent] = temp
def HeadSort(input_list):
if len(input_list) == 0:
return []
sorted_list = input_list
length = len(sorted_list)
'''循环建立初始最大堆 length//2-1是最后一个非叶子结点 '''
for i in range(0, length // 2)[::-1]:
HeadAdjust(sorted_list, i, length)
'''进行n-1次循环,完成排序'''
for j in range(1, length)[::-1]:
# 最后一个元素和第一元素进行交换
sorted_list[0], sorted_list[j] = sorted_list[j], sorted_list[0]
# 筛选 R[0] 结点,得到i-1个结点的堆
HeadAdjust(sorted_list, 0, j)
print('第%d趟排序:' % (length - j), end = '')
print(sorted_list)
return sorted_list
if __name__ == '__main__':
input_list = [6, 4, 8, 9, 2, 3, 1]
print('排序前:', input_list)
sorted_list = HeadSort(input_list)
print('排序后:', sorted_list)
最小的k个数(nlogk):
# -*- coding:utf-8 -*-
class Solution:
def HeadAdjust(self, input_list, parent, length):
temp = input_list[parent]
child = 2 * parent + 1
while child < length:
if child + 1 < length and input_list[child+1] > input_list[child]:
child += 1
if temp >= input_list[child]:
break
input_list[parent] = input_list[child]
parent = child
child = 2 * parent + 1
input_list[parent] = temp
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
if not tinput or k <= 0 or k > len(tinput):
return []
'''选取k个数构建堆'''
sorted_list = tinput[:k]
'''构建最大堆'''
for i in range(k//2)[::-1]:
self.HeadAdjust(sorted_list, i, k)
for j in tinput[k:]:
cur_max = sorted_list[0]
'''如果值比最大堆值小,重新构建最大堆'''
if j < cur_max:
sorted_list[0] = j
self.HeadAdjust(sorted_list, 0, k)
'''堆排序'''
for j in range(1, k)[::-1]:
sorted_list[0], sorted_list[j] = sorted_list[j], sorted_list[0]
self.HeadAdjust(sorted_list, 0, j)
return sorted_list
if __name__ == '__main__':
a = Solution()
print(a.GetLeastNumbers_Solution([4,5,1,6,2,7,3,8], 4))