AcWing786第k个数
题目:
题目大意:
给定一个未排序数组和数字k,输出从小到大排序后第k(1 <= k <= n)个数。
数据范围:
如图所示
思路:
首先明确,第k大的数X在有序数组中的位置为k-1(i ∈ [0,n-1]),采用快排分治思想,每次可只处理X所在的那一半区间,所以在进行快排找分界点时,找到此次递归的数组分界点j,将此次递归区间[l, r] 分为 [l, j]、[j + 1, r]左右两个区间,并确定左右区间中的数,这些数在有序数组中也处于该区间,这样就可以根据j来确定k-1在左区间还是在右区间,如果 k - 1 <= j,说明k - 1在左区间,则递归的处理左区间,舍去(不处理)右区间。反之如果k - 1 > j,说明k - 1在右区间,则递归的处理右区间,舍去(不处理)左区间。 不断递归,区间长度为1时,则找到了在有序数组中下标为k-1的数X。
代码:
import java.util.Scanner;
public class Main {
public static int N = 100010;
public static int[] nums = new int[N];
public static int quickSort(int[] nums, int l, int r, int k){
if (l >= r)
return nums[l];
int mid = nums[l + r >> 1];
int i = l - 1, j = r + 1;
while (i < j){
while (nums[++ i] < mid);
while (nums[-- j] > mid);
if (i < j){
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
}
//选择k所在的区间进行下一步处理
if (k <= j)
return quickSort(nums, l, j, k);
else
return quickSort(nums, j + 1, r, k);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(), k = scanner.nextInt();
for (int i = 0; i < n; i ++ ){
nums[i] = scanner.nextInt();
}
System.out.println(quickSort(nums, 0, n - 1, k - 1));
}
}
时空复杂度分析等:
-
时间复杂度 : O(n)
- 分析 : n + n/2 + n/4 + … = n (1 + 1/2 + 1/4 + …) <= 2n
-
空间复杂度 : O(logn) ~ O(n)