面试题 17.14. 最小K个数
LeetCode:https://leetcode-cn.com/problems/smallest-k-lcci
设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。
示例:
输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]
提示:
0 <= len(arr) <= 100000
0 <= k <= min(100000, len(arr))
解题思路: 这个题比较简单,使用双路快排,每次标定点k前的[0-k)的元素就是需要返回的数组。注意这里的第K小的数字下标应该是k-1
import java.util.Arrays;
import java.util.Random;
class Solution {
public int[] smallestK(int[] arr, int k) {
if(k == 0) return new int[0];
Random rnd = new Random();
selectK(arr, 0, arr.length - 1, k - 1, rnd);
return Arrays.copyOf(arr, k);
}
private int selectK(int[] arr, int l, int r, int k, Random rnd){
int p = partition(arr, l, r, rnd);
if(k == p) return arr[p];
if(k < p) return selectK(arr, l, p - 1, k, rnd);
return selectK(arr, p + 1, r, k, rnd);
}
private int partition(int[] arr, int l, int r, Random rnd){
// 生成 [l, r] 之间的随机索引
int p = l + rnd.nextInt(r - l + 1);
swap(arr, l, p);
// arr[l+1...i-1] <= v; arr[j+1...r] >= v
int i = l + 1, j = r;
while(true){
while(i <= j && arr[i] < arr[l])
i ++;
while(j >= i && arr[j] > arr[l])
j --;
if(i >= j) break;
swap(arr, i, j);
i ++;
j --;
}
swap(arr, l, j);
return j;
}
private void swap(int[] arr, int i, int j){
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}