题目描述
解题思路
归并排序
public int[] getLeastNumbers(int[] arr, int k) {// 归并排序mergeSort(arr, 0, arr.length - 1);return Arrays.copyOf(arr, k);}/*** 归并排序** @param nums* @param l* @param r*/public void mergeSort(int[] nums, int l, int r) {if (l >= r) {return;}int mid = (l + r) / 2;mergeSort(nums, l, mid);mergeSort(nums, mid + 1, r);int[] tempArray = new int[r - l + 1];for (int i = l; i <= r; i++) {tempArray[i - l] = nums[i];}int i = 0, j = mid - l + 1; // 分别指向左右子数组的首个元素for (int k = l; k <= r; k++) {if (i == mid - l + 1) {nums[k] = tempArray[j++];} else if (j == r || tempArray[j] >= tempArray[i]) {nums[k] = tempArray[i++];} else if (tempArray[j] < tempArray[i]) {nums[k] = tempArray[j++];}}}
快速排序
public int[] getLeastNumbers(int[] arr, int k) {// 归并排序// mergeSort(arr, 0, arr.length - 1);// 快排quickSort(arr,k, 0, arr.length - 1);return Arrays.copyOf(arr, k);}/*** 快速排序** @param arr* @param l* @param r*/public void quickSort(int[] arr, int l, int r) {if (l >= r) {return;}int i = l, j = r;while (i < j) {while (i < j && arr[j] >= arr[l]) j--;while (i < j && arr[i] <= arr[l]) i++;swap(arr, i, j);}swap(arr, l, i); // 交换最后位置// 递归左右数组进行快速排序quickSort(arr, l, i - 1);quickSort(arr, i + 1, r);}public void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
基于快速排序的数组划分
题目只要求返回最小的 k 个数,对这 k 个数的顺序并没有要求。因此,只需要将数组划分为 最小的 k 个数 和 其他数字 两部分即可,而快速排序的哨兵划分可完成此目标。
根据快速排序原理,如果某次哨兵划分后 基准数正好是第 k+1 小的数字 ,那么此时基准数左边的所有数字便是题目所求的 最小的 k 个数 。
根据此思路,考虑在每次哨兵划分后,判断基准数在数组中的索引是否等于 k ,若 true 则直接返回此时数组的前 k 个数字即可。
步骤
哨兵划分:
划分完毕后,基准数为 arr[i] ,左 / 右子数组区间分别为 [l, i - 1][l,i−1] , [i + 1, r][i+1,r] ;
递归或返回:
- 若 k < i ,代表第 k + 1 小的数字在 左子数组 中,则递归左子数组;
- 若 k > i ,代表第 k + 1 小的数字在 右子数组 中,则递归右子数组;
- 若 k = i ,代表此时 arr[k] 即为第 k + 1 小的数字,则直接返回数组前 k 个数字即可;
也就是找到哨兵和k的关系,如果哨兵等于 k+1 , 那么前面的k个数都是小于哨兵的,因为不需要返回k个数都是有序,所以直接返回前面的k个数。
/*** 基于快速排序的数组划分** @param arr* @param l* @param r*/public void quickSort(int[] arr, int k, int l, int r) {if (l >= r) {return;}int i = l, j = r;while (i < j) {while (i < j && arr[j] >= arr[l]) j--;while (i < j && arr[i] <= arr[l]) i++;swap(arr, i, j);}swap(arr, l, i); // 交换最后位置if (i > k) quickSort(arr, k, l, i - 1); // i > k,表示需要的元素在左数组if (i < k)quickSort(arr, k, i + 1, r); // i < k,表示需要的元素在右数组// 相等表示左边就是 k 个元素,而基准此时就是 k + 1,所以直接返回前面k个数}
