0%

最小的K个数的多种解法

最小的k个数在面试中遇到了4次,记录一下多种解法。

快速选择

  • 初始版本
    • 时间复杂度最坏情况下O(NlogN)
    • 空间复杂度O(logN)
1
class Solution(object):
2
    def getLeastNumbers(self, arr, k):
3
        """
4
        :type arr: List[int]
5
        :type k: int
6
        :rtype: List[int]
7
        """
8
        if k < 0 or k > len(arr): return
9
        if k == 0: return []
10
        self.quickSort(arr, 0, len(arr) - 1, k)
11
        return arr[:k]
12
13
    def quickSort(self, arr, i, j, k):
14
        if i > j: return
15
        p = self.partition(arr, i, j)
16
        if p == k:
17
            return
18
        elif p > k:
19
            self.quickSort(arr, i, p - 1, k)
20
        else:
21
            self.quickSort(arr, p + 1, j, k)
22
23
    def partition(self, arr, i, j):
24
        # if i >= j: return i
25
        pivot = arr[i]
26
        while i < j:
27
            while i < j and arr[j] >= pivot:
28
                j -= 1
29
            arr[i] = arr[j]
30
31
            while i < j and arr[i] <= pivot:
32
                i += 1
33
            arr[j] = arr[i]
34
35
        arr[i] = pivot
36
        return i
  • 优化版本

    三数取中的方法优化选取枢轴

    1
    def partition(self, arr, i, j):
    2
            mid = (i + j) >> 1
    3
            if arr[i] > arr[j]:  # 把小的放到i上去
    4
                arr[i], arr[j] = arr[j], arr[i]
    5
            if arr[mid] > arr[j]:  # 把最大的放到最后去
    6
                arr[mid], arr[j] = arr[j], arr[mid]
    7
            if arr[mid] > arr[i]:
    8
                arr[mid], arr[i] = arr[i], arr[mid]
    9
    10
            pivot = arr[i]
    11
            while i < j:
    12
                while i < j and arr[j] >= pivot:
    13
                    j -= 1
    14
                arr[i] = arr[j]
    15
    16
                while i < j and arr[i] <= pivot:
    17
                    i += 1
    18
                arr[j] = arr[i]
    19
    20
            arr[i] = pivot
    21
            return i

最大堆

要找到最小的K个数,需要建立一个大顶堆,初始化一个k的元素大顶堆,对于剩下的n-k个数,遍历一下,如果遇到比堆顶元素小的,则删除堆顶元素,该元素入堆,更新堆。

时间复杂度:建堆:O(NlogK)

在python中内置的堆为小顶堆,若要找到最小的K个数,将元素取反即可。

1
class Solution(object):
2
    def getLeastNumbers(self, arr, k):
3
        """
4
        :type arr: List[int]
5
        :type k: int
6
        :rtype: List[int]
7
        """
8
        if k < 0 or k > len(arr): return
9
        if k == 0: return []
10
        import heapq
11
        arr = [-a for a in arr]
12
        hp = arr[:k]
13
        heapq.heapify(hp)
14
15
        for i in range(k, len(arr)):
16
            if arr[i] > hp[0]:
17
                heapq.heappop(hp)
18
                heapq.heappush(hp, arr[i])
19
20
        return [-i for i in hp]

计数排序

数据范围有限时直接计数排序就行了:时间复杂度O(N)

1
class Solution(object):
2
    def getLeastNumbers(self, arr, k):
3
        """
4
        :type arr: List[int]
5
        :type k: int
6
        :rtype: List[int]
7
        """
8
9
        counter = [0] * 10000
10
        for a in arr:
11
            counter[a] += 1
12
13
        ans = []
14
        idx = 0
15
16
        for i in range(len(counter)):
17
            while counter[i] > 0 and idx < k:
18
                ans.append(i)
19
                idx += 1
20
                counter[i] -= 1
21
            if idx == k: break
22
        return ans