方法一:直接排序
public static int[] getLeastNumbers(int[] arr, int k) { Arrays.sort(arr); int[] result = new int[k]; for(int i = 0; i < k; i++){ result[i] = arr[i]; } return result; }方法二:大根堆 1.保持堆的大小为k,小于k时,遍历数组插入 2.堆顶元素为最大,继续遍历数组大于对顶元素的继续遍历, 小于堆顶元素将堆顶元素删除后插入堆
public static int[] getLeastNumbersTwo(int[] arr,int k){ //1.遍历数组插入元素为k个 PriorityQueue<Integer> priorityQueue = new PriorityQueue<>((v1, v2) -> v2 - v1); for(int i = 0; i < k; i++){ priorityQueue.add(arr[i]); } //2.比较后k+1个元素 for(int j = k; j < arr.length; j++){ if(priorityQueue.peek() > arr[j]){ priorityQueue.poll(); priorityQueue.add(arr[j]); } } //3.将堆转换为数组 int[] result = new int[priorityQueue.size()]; int i = 0; for(int num : priorityQueue){ result[i ++] = num; } return result; }方法三:快排 注意找前 K 大/前 K 小问题不需要对整个数组进行 O(NlogN)O(NlogN) 的排序! 例如本题,直接通过快排切分排好第 K 小的数(下标为 K-1),那么它左边的数就是比它小的另外 K-1 个数啦~
public static int[] getLeastNumbersThree(int[] arr, int k) { if (k == 0 || arr.length == 0) { return new int[0]; } // 最后一个参数表示我们要找的是下标为k-1的数 return quickSearch(arr, 0, arr.length - 1, k - 1); } private static int[] quickSearch(int[] nums, int lo, int hi, int k) { // 每快排切分1次,找到排序后下标为j的元素,如果j恰好等于k就返回j以及j左边所有的数; int j = partition(nums, lo, hi); if (j == k) { return Arrays.copyOf(nums, j + 1); } // 否则根据下标j与k的大小关系来决定继续切分左段还是右段。 return j > k? quickSearch(nums, lo, j - 1, k): quickSearch(nums, j + 1, hi, k); } // 快排切分,返回下标j,使得比nums[j]小的数都在j的左边,比nums[j]大的数都在j的右边。 private static int partition(int[] nums, int lo, int hi) { int v = nums[lo]; int i = lo, j = hi + 1; while (true) { while (++i <= hi && nums[i] < v); while (--j >= lo && nums[j] > v); if (i >= j) { break; } int t = nums[j]; nums[j] = nums[i]; nums[i] = t; } nums[lo] = nums[j]; nums[j] = v; return j; }