描述
- 有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。
- 给定一个整数数组a,同时给定它的大小n和要找的K(1<=K<=n),请返回第K大的数(包括重复的元素,不用去重),保证答案存在。
示例1
输入:
[1,3,5,2,2],5,3
返回值:
2
示例2
输入:
[10,10,9,9,8,7,5,6,4,3,4,2],12,3
返回值:
9
题目框架(Java)
import java.util.*;
public class Solution {
public int findKth(int[] a, int n, int K) {
// write code here
}
}
说明:
去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9
快排思想
取一个基准数,使排序后基准数右边的数都大于基准数,左边的数都小于基准数。
快排实现
- 设置两个变量
low
、high
,排序开始时:low=0
,high=size-1
。 - 默认数组的第一个数为基准数据,赋值给
key
,即key=array[low]
。 - 因为默认数组的第一个数为基准,所以从后面开始向前搜索(
high–-
),找到第一个小于key
的array[high]
,就将array[high]
赋给array[low]
,即array[low] = array[high]
。(循环条件是array[high] >= key
) - 此时从前面开始向后搜索(l
ow++
),找到第一个大于key
的array[low]
,就将array[low]
赋给array[high]
,即array[high] = array[low]
。(循环条件是array[low] <= key
) - 循环 3- 4步骤,直到
low=high
,该位置就是基准位置。 - 把基准数据赋给当前位置。
- 第一趟找到的基准位置,作为下一趟的分界点,递归调用分界点前后的数组充重复2-7操作。
快排实现(Java)
private int fast(int[] a, int low, int high) {
int key = a[low];
while (low != high) {
while (a[high] >= key && high > low) {
high--;
}
a[low] = a[high];
while (a[low] < key && high > low) {
low++;
}
a[high] = a[low];
}
a[low] = key;
return low;
}
题目思想
设置起始头尾指针
int low = 0;
int high = n - 1;
使用快排找出第一个基准位置
key = fast(a, low, high);
- 如果当前基准位置距离数组尾部的长度大于K,则第K大的数位于基准位置的右方,对基准位置右方的子数组进行递归。
- 如果当前基准位置距离尾部的长度小于K,则第K大的数位于基准位置的左方,对基准位置左方的子数组进行递归,并将K减去右方子数组长度作为新的K值。
如果当前基准位置距离尾部的长度等于K,则该基准位置的值为第K大的值。
完整代码
public class Solution {
public int findKth(int[] a, int n, int K) {
// write code here
int low = 0;
int high = n - 1;
int key;
key = fast(a, low, high);
while (true) {
int range = high + 1 - key;
if (range == K) {
return a[key];
} else if (range > K) {
low = key + 1;
key = fast(a, low, high);
} else {
K -= range;
high = key - 1;
key = fast(a, low, high);
}
}
}
private int fast(int[] a, int low, int high) {
int key = a[low];
while (low != high) {
while (a[high] >= key && high > low) {
high--;
}
a[low] = a[high];
while (a[low] < key && high > low) {
low++;
}
a[high] = a[low];
}
a[low] = key;
return low;
}
}