最小的k個數

輸入整數數組arr,找出其中最小的k個數。例如,輸入四、五、一、六、二、七、三、8這8個數字,則最小的4個數字是一、二、三、4。算法

示例 1:數組

輸入:arr = [3,2,1], k = 2
輸出:[1,2] 或者 [2,1]app

示例 2:dom

輸入:arr = [0,1,2,1], k = 1
輸出:[0]函數

限制:測試

  • 0 <= k <= arr.length <= 10000
  • 0 <= arr[i] <= 10000

解題思路

找一個亂序數組中的最小的k個數,本質來講是一個排序問題,將數組從小到大排序,而後取出前k個數
使用十大排序算法均可解決, 對應的時間複雜度-空間複雜度爲
冒泡排序: O(n2)-O(1)
選擇排序: O(n2)-O(1)
插入排序: O(n2)-O(1)ui

快排: O(nlgn)-O(lgb)
堆排序: O(nlgn)-O(1)
歸併排序:O(nlgn)-O(n)code

希爾排序:O(1.3nlgn)-O(1)
基數排序:O(kn)-O(n+k)
計數排序
桶排序排序

題中測試數據最大爲10000, 5位數, 使用基數排序算法複雜度爲O(5n)索引

class Solution(object):
    def getLeastNumbers(self, arr, k):
        """
        :type arr: List[int]
        :type k: int
        :rtype: List[int]
        """
        # 5位數
        n = 5
        # 第幾位數, 0表示個位數
        i = 0
        while i < n:
            # key爲0~9, value爲當前比較位數爲對應key的值列表
            t = defaultdict(list)
            for a in arr:
                # 計算數字在該位的值
                a_t = int((a / (10 ** i)) % 10)
                # 放入位數的值對應的列表中
                t[a_t].append(a)

            j = 0
            # 將當前按照位數分類的數字取出,放回原數組中
            for k in range(10):
                temp = t[k]
                for t1 in temp:
                    arr[j] = t1
                    j += 1
            # 將要計算的數字位數加1
            i += 1
        return arr

經觀察,若是咱們只須要前k個數的話,實際上不須要對全部數字進行排序,只須要確保前k個數字是最小的,不須要關心第k個數字以後的列表是否有序

快排

import random

class Solution(object):
    def getLeastNumbers(self, arr, k):
        """
        :type arr: List[int]
        :type k: int
        :rtype: List[int]
        """
        # 使用快排選擇前k個數
        self.quick_sort(arr, 0, len(arr) - 1, k)
        return arr[:k]
       
    def quick_sort(self, arr, left, right, k):
        """
        :type arr: List[int]
        :type left: 當前須要進行排序的區域的左開始點
        :type right: 當前須要進行排序的區域的右結束點
        :type k: 該次排序中的目標k, 須要從left到right中選取前k小的數字
        """
        if left < right:
            # 分區, 將數組分紅左半區和右半區,左半區比右半區小, pos爲中間位置索引
            pos = self.partition(arr, left, right)
            # 該次排序中左半區的數量
            num = pos - left + 1
            # 左半區的數量剛好等於k, 已經找到須要的數字
            if num == k:
                return
            # 若是左半區的數量大於須要篩選的k, 則繼續對左半區進行劃分, 直到知足等於k
            if num > k:
                # 左半區排序區間爲left 到pos-1
                self.quick_sort(arr, left, pos - 1, k)
            else:
                # 左半區的數組數量小於k, 須要從右半區選擇剩餘的k-num個數字,做爲整個數組的前k個數字
                self.quick_sort(arr, pos + 1, right, k - num)
                
    def random_select(self, arr, left, right):
        # 在左和右中隨機選擇一個位置
        pos = random.randint(left, right)
        # 交換該位置和左位置的值
        arr[pos], arr[left] = arr[left], arr[pos]
        return pos
      
    def partition(self, arr, left, right):
        """
        分區函數
        :type arr: List[int]
        :type left: 分區的左開始位置
        :type right: 分區的右結束位置
       
        """
        # 隨機選擇一個值, 並和left位置進行交換
        self.random_select(arr, left, right)
        # 取出分區的選擇的中間值, 左半區須要比該值小, 右半區比該值大
        temp_value = arr[left]
        while left < right:
            while left < right and arr[right] > temp_value:
                # 從右向左推動, 遇到第一個比中間值小的數字, 將它放在本來中間值的位置上, 即left位置
                right -= 1
            arr[left] = arr[right]
            while left < right and arr[left] <= temp_value:
          
                left += 1
            arr[right] = arr[left]
            
        arr[left] = temp_value
        return left
相關文章
相關標籤/搜索