leetcode-最小的k个数
题目链接:题目传送门
题目大意是给定一个数组,然后寻找数组中的前k小个元素。
乍一看,这个题目倒是很符合它的简单标签,直接对原数组进行冒泡排序操作,之后复制出前k个元素即可得到目标数组,但是这样做耗时过大,所以,我们来温习下快速排序的步骤
- 找到一个基准位置,通常取数组范围的首位
- 确定哨兵i和哨兵j,分别指向数组的两端
- 对于哨兵i,从左到右寻找,直到找到一个比基准数值大的数字
- 对于哨兵j,从右到左寻找,直到找到一个比基准数值小的数字
- 将两个哨兵找到的数值对调位置,继续寻找过程,直到两个哨兵找到的位置相重合,即i==j
- 将基准位置的数值和哨兵i的位置的元素调换位置
实际开发中,可以先让哨兵j出发,如此操作可以保证,最后两个哨兵重合的位置的值是小于基准位置的,方便后面的交换。
把上面的流程翻译成代码就是下面的样子
public int[] getLeastNumbers(int[] arr, int k) {
int[] result = new int[k];
quickSort(arr, 0, arr.length-1);
for(int i = 0; i < k; i++) {
result[i] = arr[i];
}
return result;
}
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++;
}
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
int t = arr[l];
arr[l] = arr[i];
arr[i] = t;
quickSort(arr, l, i-1);
quickSort(arr, i+1, r);
}
实际上,对于这样的题目,可以这样想,在快速排序的过程中,当一个基准确定位置后,就可以得知,在最后的排序完成的数组中,基准位置还是这个位置,所以不必要排序整个数组,只需要进行一部分的排序就可以解决top K问题
public int[] quickSort(int[] arr, int l, int r, int k) {
int i = l, j = r;
while(i < j) {
while((i < j)&&(arr[j] >= arr[l])) {
j--;
}
while((i < j)&&(arr[i] <= arr[l])) {
i++;
}
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
int t = arr[l];
arr[l] = arr[i];
arr[i] = t;
//此时已经确定了arr[l]就是位于最终数组下标为i的位置
if(i > k) {
//最终的结果小数组位于i的左边
return quickSort(arr, l, i-1, k);
}
if(i < k) {
//最终的结果小数组位于i的右边
return quickSort(arr, i+1, r, k);
}
return Arrays.copyOf(arr, k);
}
以前怎么都学不会的,现在能看进去了,奇怪的人类