编程题实例
滴滴2018校招笔试题编程题2:
找出数组中第K大的元素
输入
45,66,58,22
2
输出 45
编程原理
这道题与
- 剑指Offer面试题29:数组中出现次数超过一半的数字;
- 剑指Offer面试题30:数组中最小的k个数;
本质上是相同的,都是在双路快排的过程中(剑指Offer用的是单路快排,不如双路高效简单),当划分值的下标与所求相同,将数组分为大于划分值与小于划分值的两部分,时间复杂度O(logN)小于顺序遍历的O(N)。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//输入一行数字字符串并转化为整形数组
Scanner input =new Scanner(System.in);
String inputString=input.nextLine();
String[] chars=inputString.split(" ");
int array[] = new int[chars.length];
for (int i = 0; i < chars.length; i++) {
array[i] = Integer.valueOf(chars[i]);
}
//输入要查找的第K大值
int K=input.nextInt();
System.out.println(new Main().quickSortFindMax(array,K));
}
public int quickSortFindMax(int[] array,int K) {
int start=0;
int end=array.length-1;
int index=-1;
while(true){
//返回当前分治元素的下标 下标<index的都是大于array[index] 反之则小于
index = partition(array, start, end);
//第K大元素对应的下标应该是K-1 当index==K-1 即找到了第K大元素
if(index==K-1)
break;
else if(index>K-1)
end=index-1;
else
start=index+1;
}
return array[index];
}
//核心部分 双路快排将数组分为两部分
public int partition(int array[],int i,int j){
swap(array,i,randomInRange(i,j)); //随机选取一个数作为分治的标准,并放在第一位;
int target=array[0];
int start=i+1; //从下一个元素开始遍历
int end=j;
while(start<=end){
while (array[start]>target&&start<j)
start++;
while (array[end]<=target&&end>i) //注意一定是小于等于,否则end有可能一直停在j最后一位 end应该停留在最后一个大于等于target的元素
end--;
if (start<end)
swap(array,start,end);//交换target与最后一个大于等于target的元素并返回target的下标
}
swap(array,i,end); //最后的end指针指向最后一个>=target的数;
return end;
}
public static void swap(int array[],int i,int j){
int temp=array[i];
array[i]=array[j];
array[j]=temp;
}
public static int randomInRange(int i,int j){
if (i>j)
throw new IllegalArgumentException();
return (int) (i+Math.random()*(j-i+1));
}
}
运行结果
普通用例
45 666 7 -90
2
45
特殊用例
19
1
19