题目

image.png

思路

思路一:排序

排序,快速排序,然后取出前k个。最大时间复杂度O(nlogn)

  1. class Solution:
  2. def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
  3. arr.sort()
  4. return arr[:k]

思路二:计数排序

维护一个数组,该数组共max(arrd) + 1个元素,初始化每个元素都为0,索引代表值,元素表示相应值出现的次数。

遍历一遍原始数组arr,得到每个数出现的次数。
在顺序遍历一遍计数数组,取出前k个数。
最大时间复杂度O(n)。因为每次遍历都是O(n)。

  1. class Solution:
  2. def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
  3. # 计数排序
  4. countNums = [0] * (max(arr) + 1)
  5. for num in arr:
  6. countNums[num] += 1
  7. ans = []
  8. for num, cnt in enumerate(countNums):
  9. if k == 0:
  10. break
  11. if k - cnt >= 0:
  12. ans += [num] * cnt
  13. k -= cnt
  14. else:
  15. ans += [num] * k
  16. k = 0
  17. return ans

思路三:基于快速排序的思路

快速排序中,每次选择一个pivot,然后partition将原始数组分成两部分,左半部分小于等于pivot,右半部分大于等于pivot。
如果该pivot所在的索引正好是k,那么前k个就是最小的k个数。否则,左半部分去找或者右半部分去找。

  1. class Solution:
  2. def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
  3. # target index is k
  4. # quick sort
  5. size = len(arr)
  6. if size == 0 or size <= k:
  7. return arr
  8. left = 0
  9. right = size - 1
  10. while True:
  11. # print(arr)
  12. ind = self._partition(arr, left, right)
  13. if ind == k:
  14. return arr[:k]
  15. elif ind > k:
  16. right = ind - 1
  17. else:
  18. left = ind + 1
  19. def _partition(self, arr, left, right):
  20. pivot = arr[left]
  21. j = left
  22. for i in range(left+1, right+1):
  23. if pivot > arr[i]:
  24. j += 1
  25. arr[i], arr[j] = arr[j], arr[i]
  26. arr[left], arr[j] = arr[j], arr[left]
  27. return j

思路四:基于堆或者红黑树的思路

image.png