输入整数数组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