通过率 56.9%
题目描述:
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
思路:
1. 库函数 sort + slice
2. 堆 C++可以直接用priority_queue优先队列,遍历数组,用优先队列维护最小的k个值,一旦当前遍历到的数小于大顶堆堆顶的数,就将堆顶的数弹出让当前的数入队,最后返回该优先队列中的数
3. 快速排序 每排一次都会将数组分为两组排序,设分割点的值为x,那么左边那组数都比x小,右边的都比x大,于是,当x===k-1时,直接返回数组前k个数(由题可知,返回的数组可以无序,只要保证是前k小的数就行);当x<k-1,则只须排右边那组;当x>k-1,只须排左边那组
代码:
1. 库函数 sort + slice
1 /*JavaScript*/ 2 /** 3 * @param {number[]} arr 4 * @param {number} k 5 * @return {number[]} 6 */ 7 var getLeastNumbers = function(arr, k) { 8 arr.sort((a, b) => a - b) 9 return arr.slice(0, k) 10 };
2. 堆(优先队列)
1 /*C++*/ 2 class Solution { 3 public: 4 vector<int> getLeastNumbers(vector<int>& arr, int k) { 5 vector<int> res; 6 priority_queue<int> q; 7 8 if(!k) return res; 9 for(int i = 0; i < k; i++) { 10 q.push(arr[i]); 11 } 12 for(int i = k; i < arr.size(); i++) { 13 if(arr[i] < q.top()) { 14 q.pop(); 15 q.push(arr[i]); 16 } 17 } 18 while(q.size()) { 19 res.push_back(q.top()); 20 q.pop(); 21 } 22 return res; 23 } 24 };
3. 快排
这里将第一个数作为基准点会好分析一些,最后跳出循环时一定是i===j,而以其他数作为基准点的话我往往很难确定到底是i还是j是分割点,分治就是这点令人头疼,不知道分到最后是个什么情况,说到底还是对这个不熟
1 /*JavaScript*/ 2 /** 3 * @param {number[]} arr 4 * @param {number} k 5 * @return {number[]} 6 */ 7 var quickSort = function(arr, left, right) { 8 let i = left, j = right, v = arr[left] 9 while(i < j) { 10 while(i < j && arr[j] >= v) j-- 11 arr[i] = arr[j] 12 while(i < j && arr[i] <= v) i++ 13 arr[j] = arr[i] 14 } 15 arr[i] = v 16 return i 17 } 18 19 var partition = function(arr, left, right, k) { 20 const x = quickSort(arr, left, right, k) 21 if(x === k) return arr.slice(0, k) 22 return x < k ? partition(arr, x + 1, right, k) : partition(arr, left, x - 1, k) 23 } 24 25 var getLeastNumbers = function(arr, k) { 26 return partition(arr, 0, arr.length - 1, k) 27 };