輸入整數數組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