剑指Offer/滴滴2018校招笔试题-找出数组中第K大元素-双路快排实现

编程题实例

滴滴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 = 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&&startwhile (array[end]<=target&&end>i)  //注意一定是小于等于,否则end有可能一直停在j最后一位 end应该停留在最后一个大于等于target的元素
                end--;
            if (startarray,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

你可能感兴趣的:(算法)