给定一个长度为 n 的整数数列,以及一个整数 k,请用快速选择算法求出数列从小到大排序后的第 k 个数。
输入格式
第一行包含两个整数 n和 k。
第二行包含 n个整数(所有整数均在 1∼∼109范围内),表示整数数列。
输出格式
输出一个整数,表示数列的第 k 小数。
数据范围
1≤n≤1100000,
1≤k≤n
输入样例:
5 3
2 4 1 5 3
输出样例:
3
自己下意识思路是:根据前面所学的快排,把数据从小到大的顺序排序,然后根据下标来找第k小个数,代码如下:
package com.zy.Acwing.quickSort;
import java.util.*;
//本方法是直接先把所有数据进行快排,然后根据下标来找到第k小个数,所以是对两边都进行快排;
public class P786_V1 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int k = scan.nextInt();
int[] arr = new int[n];
for(int i=0;i<n;i++) {
arr[i] = scan.nextInt();
}
quick_sort(arr,0,n-1);
System.out.print(arr[k-1]);
}
public static void quick_sort(int[] arr,int l,int r) {
if(l>=r) return;
int x = arr[l+r>>1],i = l-1,j=r+1;
while(i<j) {
while(arr[++i]<x);
while(arr[--j]>x);
if(i<j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
quick_sort(arr,l,j);
quick_sort(arr,j+1,r);
}
}
提交代码之后也可以AC,但根据其他人写的有更优解,代码如下:
package com.zy.Acwing.quickSort;
import java.util.*;
//本方法是对P786_V1的改进,V1的方法左右两端都进行了递归;
//实则可以根据输入的k值来进行判断第k个小的数是在左端还是右端,只用递归一部分就行
public class P786_V2 {
static int N = 100010;
static int[] arr = new int[N];
static int n,k;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
k = scan.nextInt();
for(int i=0;i<n;i++) {
arr[i] = scan.nextInt();
}
System.out.println(quick_sort(0,n-1,k-1));
}
public static int quick_sort(int l,int r,int k) {
if(l>=r) return arr[k];
int x = arr[l+r>>1],i = l-1,j=r+1;
while(i<j) {
while(arr[++i]<x);
while(arr[--j]>x);
if(i<j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
if(k<= j) return quick_sort(l,j,k);//不是(k<j),否则会把j给漏掉;
else return quick_sort(j+1,r,k);
}
}
自己对于上面代码的一些知识点的补充:
- 采用static修饰变量 : Java中没有全局变量,但可以通过public static成员变量来模拟全局变量。
- Java中没有全局变量这一概念
- 题目中给出常量的值。为什么在编写程序时要在最大值上加上10呢?
在编程中,为常量设定一个比预期最大值稍大的值通常是为了处理边界情况和避免数组越界等错误。例如,如果我们正在处理一些数据并且知道这些数据的最大索引是100000,我们可能会创建一个大小为100010的数组来存储这些数据。这样做的目的是为了确保数组有足够的空间来存储所有可能的数据,即使实际数据的最大索引稍微超过了100000。此外,这样做也可以使代码更加健壮和可靠。通过预留一些额外的空间,我们可以确保在输入数据稍有变化或超出预期时,程序仍能正常运行而不会引发错误。这有助于避免数组越界异常等潜在问题,并减少调试和维护的工作量。总之,为了确保程序的稳定性和可靠性,通常会在定义常量时预留一些额外的空间来处理边界情况和潜在的输入变化。这是一种常见的编程技巧,可以帮助我们编写出更加健壮和可维护的代码。