/* 快速排序主函数 */
void sort(int[] nums) {
// 一般要在这用洗牌算法将 nums 数组打乱,
// 以保证较高的效率,我们暂时省略这个细节
sort(nums, 0, nums.length - 1);
}
/* 快速排序核心逻辑 */
void sort(int[] nums, int lo, int hi) {
if (lo >= hi) return;
// 通过交换元素构建分界点索引 p
int p = partition(nums, lo, hi);
// 现在 nums[lo..p-1] 都小于 nums[p],
// 且 nums[p+1..hi] 都大于 nums[p]
sort(nums, lo, p - 1);
sort(nums, p + 1, hi);
}
int partition(int[] nums, int lo, int hi) {
if (lo == hi) return lo;
// 将 nums[lo] 作为默认分界点 pivot
int pivot = nums[lo];
// j = hi + 1 因为 while 中会先执行 --
int i = lo, j = hi + 1;
while (true) {
// 保证 nums[lo..i] 都小于 pivot
while (nums[++i] < pivot) {
if (i == hi) break;
}
// 保证 nums[j..hi] 都大于 pivot
while (nums[--j] > pivot) {
if (j == lo) break;
}
if (i >= j) break;
// 如果走到这里,一定有:
// nums[i] > pivot && nums[j] < pivot
// 所以需要交换 nums[i] 和 nums[j],
// 保证 nums[lo..i] < pivot < nums[j..hi]
swap(nums, i, j);
}
// 将 pivot 值交换到正确的位置
swap(nums, j, lo);
// 现在 nums[lo..j-1] < nums[j] < nums[j+1..hi]
return j;
}
// 交换数组中的两个元素
void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
int p = partition(nums, lo, hi);
int findKthLargest(int[] nums, int k) {
int lo = 0, hi = nums.length - 1;
// 索引转化
k = nums.length - k;
while (lo <= hi) {
// 在 nums[lo..hi] 中选一个分界点
int p = partition(nums, lo, hi);
if (p < k) {
// 第 k 大的元素在 nums[p+1..hi] 中
lo = p + 1;
} else if (p > k) {
// 第 k 大的元素在 nums[lo..p-1] 中
hi = p - 1;
} else {
// 找到第 k 大元素
return nums[p];
}
}
return -1;
}
int findKthLargest(int[] nums, int k) {
// 首先随机打乱数组
shuffle(nums);
// 其他都不变
int lo = 0, hi = nums.length - 1;
k = nums.length - k;
while (lo <= hi) {
// ...
}
return -1;
}
// 对数组元素进行随机打乱
void shuffle(int[] nums) {
int n = nums.length;
Random rand = new Random();
for (int i = 0 ; i < n; i++) {
// 从 i 到最后随机选一个元素
int r = i + rand.nextInt(n - i);
swap(nums, i, r);
}
}