方法一:堆排序思想
对n个数建立最小堆,可以得到数组从大到小的排序。
因为只需要最小的k个数,因此只需要调整k次,最后的k个数就是最小的k个数。
O(nlogn)
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
def adjust_heap(arr, i, up):
# i:需要调整的节点
# up:只调整arr[0, up-1],如果调整整个列表是arr[0,n-1]
while 2 * i + 1 < up: # 如果有左子节点
son = 2 * i + 1
if son + 1 < up and arr[son+1] < arr[son]: # 先把son指向最小的儿子
son += 1
if arr[i] > arr[son]: # 判断是否需要交换
arr[i], arr[son] = arr[son], arr[i]
i = son
else:
break
# 建最小堆操作
def build_heap(arr):
n = len(arr)
for i in range(n//2)[::-1]:
adjust_heap(arr, i, n)
n = len(tinput)
# 边界情况:
if n < k or k == 0:
return []
build_heap(tinput)
for i in range(n-1, n-k-1, -1): # 只需要调整k次
tinput[i], tinput[0] = tinput[0], tinput[i] # 交换根节点和待排序的最后一个节点
adjust_heap(tinput, 0, i) # 交换完后调整树,注意已排序的不需要调整了
return tinput[-k:][::-1]
方法二:方法一的改进
用tinput的前k个数建立大小为k的堆,后面的数依次添加并调整堆。
时间复杂度:O(nlogk)
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
def adjust_heap(arr, i, up):
while 2 * i + 1 < up: # 如果有左子节点
son = 2 * i + 1
if son + 1 < up and arr[son+1] > arr[son]: # 先把son指向最小的儿子
son += 1
if arr[i] < arr[son]: # 判断是否需要交换
arr[i], arr[son] = arr[son], arr[i]
i = son
else:
break
# 建最大堆操作
def build_heap(arr):
n = len(arr)
for i in range(n//2-1, -1, -1):
adjust_heap(arr, i, n)
n = len(tinput)
# 边界情况:
ans = []
if n < k or k == 0:
return ans
for i in range(k):
ans.append(tinput[i])
build_heap(ans)
# 依次将后续元素与排好序的最大元素比较,如果小于“最大元素”,替换并调整堆
for i in range(k, n):
if tinput[i] < ans[0]:
ans[0] = tinput[i]
adjust_heap(ans, 0, k)
# 最后,将堆从小到大排序:
for i in range(k-1, -1, -1): # 只需要调整k次
ans[i], ans[0] = ans[0], ans[i] # 交换根节点和待排序的最后一个节点
adjust_heap(ans, 0, i) # 交换完后调整树,注意已排序的不需要调整了
return ans
方法三:快排思想
快排思想很快的找到前k小,但注意这k小是无序的,再用快排对这k个数排序。
时间空间复杂度比方法一大一点点。
O(n+klogk)
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
def partition(nums, left, right):
pivot = nums[left]
while left < right:
while left < right and nums[right] >= pivot:
right -= 1
nums[left] = nums[right]
while left < right and nums[left] <= pivot:
left += 1
nums[right] = nums[left]
nums[left] = pivot
return left
def quickSort(arr, left, right):
if left >= right:
return
pos = partition(arr, left, right)
quickSort(arr, left, pos - 1)
quickSort(arr, pos + 1, right)
n = len(tinput)
if n < k or k == 0:
return []
left = 0
right = n - 1
while left < right:
pos = partition(tinput, left, right)
if pos == k - 1:
break
elif pos < k - 1:
left = pos + 1
elif pos > k - 1:
right = pos - 1
ans = tinput[:k]
quickSort(ans, 0, k - 1)
return ans