最快效率求出乱序数组中第k小的数

题目:以尽量高的效率求出一个乱序数组中按数值顺序的第k 的元素值

思路:这里很容易想到直接排序然后顺序查找,可以使用效率较高的快排,但是它的时间复杂度是O(nlgn),我们这里可以用一种简便的方法,不一定需要排序,使用快速排序中双向分区的扫描方法,扫描出主元下标,然后根据主元的值将数组划分成一半大,一半小。然后再根据主元下标与k进行比较,如果相等,说明主元就是我们要找的数,如果大于k,说明k所代表的值在小的那边,继续向小的那部分递归,如果小于k,说明k代表的值在大的那边,继续向大的那部分递归。这样即可得出正确答案。这种方法的时间复杂度为O(n),因为每次递归都相当于舍弃掉了差不多一半的数。

代码:

import java.util.Arrays;

public class SelectK {

    public static void main(String[] args) {

        int arr[] = new int[10];
        for(int i=0;i<10;i++){
            arr[i] = (int) ((Math.random()+1)*10);
        }

        System.out.println("查找前数组:"+Arrays.toString(arr));
        int k = selectK(arr, 0, arr.length-1, 5);
        System.out.println("查找出第k小的元素:"+k);

    }

    /**
     *
     * @param arr
     * @param p 开始下标
     * @param r    结束下标
     * @param k 求第k小元素  (递增第k个元素)
     * @return
     */
    public static int selectK(int[] arr,int p,int r,int k){
        int q = partition2(arr, p, r);  // 主元的下标
        int qk = q - p + 1;   // 主元是第几个元素
        if (qk==k) {
            return arr[q];
        }else if (qk>k) {
            return selectK(arr, p, q-1, k);
        }else {
            return selectK(arr, q+1, r, k-qk);
        }

    }
    //双向扫描分区法
    public static int partition2(int[] arr, int p, int r) {
        int left = p + 1; //左侧扫描指针
        int right = r; //右侧指针
        int pivot = arr[p];
        while(left <= right) {
            // left不停往右走,直到遇到大于主元的元素
            // 循环退出时,left一定是指向第一个大于主元的位置
            while(left <= right && arr[left] <= pivot) {
                left++;
            }
            // right不停往左走,直到遇到小于主元的元素
            // 循环退出时,right一定是指向从右到左第一个小于于主元的位置
            while(left <= right && arr[right] > pivot) {
                right--;
            }
            if(left < right)
                swap(arr, left, right);
        }
        // 循环退出时,两者交错,且right指向的最后一个小于等于主元的位置,也就是主元应该待的位置
        swap(arr, p, right);
        return right;
    }

    private static void swap(int[] A, int p, int bigger) {
        int temp = A[p];
        A[p] = A[bigger];
        A[bigger] = temp;

    }
}

结果:

  

原文地址:https://www.cnblogs.com/xiaoyh/p/10272482.html

时间: 2024-10-12 20:46:46

最快效率求出乱序数组中第k小的数的相关文章

算法导论:快速找出无序数组中第k小的数

题目描述: 给定一个无序整数数组,返回这个数组中第k小的数. 解析: 最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(1).使用快排的思想,但是每次只对patition之后的数组的一半递归,这样可以将时间复杂度将为O(n). 在<算法导论>有详细叙述 这里主要用C++实现,实现思路就是先选取当前数组的第一个数作为"主轴",将后面所有数字分成两部分,前面一部分小于"主轴",后面一部

求数组中第k小的数,有快速排序的验证

// The_Least_K_number.cpp : 定义控制台应用程序的入口点. //数组中第k小的数,例如a[1000]中第250小的数// #include "stdafx.h" #include <iostream> using namespace std; void swap(int *p, int *q) { int temp = *p; *p = *q; *q = temp; } int patition(int a[], int first, int la

求出10个整数中的最大值

//求出10个整数中的最大值#include <stdio.h>int main(){ int arr[10];//定义存放10个整数的数组 int i; int tmp;//定义中间变量 printf("请输入10个整数:\n"); for(i=0;i<10;i++)//数组的初始化 {  scanf("%d",&arr[i]); } for(i=0;i<10;i++)//寻找10个整数中的最大值 {  if(arr[0]<=

18.n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始, 每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。 当一个数字删除后,从被删除数字的下一个继续删除第m个数字。 求出在这个圆圈中剩下的最后一个数字。

转载请注明出处:http://www.cnblogs.com/wuzetiandaren/p/4263868.html 声明:现大部分文章为寻找问题时在网上相互转载,此博是为自己做个记录记录,方便自己也方便有类似问题的朋友,本文的思想也许有所借鉴,但源码均为本人实现,如有侵权,请发邮件表明文章和原出处地址,我一定在文章中注明.谢谢. 题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始, 每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字). 当一个数字

【C++】用结构体完成:编程求出3个学生中某个学生的平均成绩

//用结构体完成:编程求出3个学生中某个学生的平均成绩 #include <iostream> #include <string.h> using namespace std; struct student { char *name; double score[3]; }; struct student stu[3]={{"han",80,90,95},{"zhao",78,85,92},{"dan",75,60,59}}

XTUOJ ABK(求出A和B的第K大公约数)

Accepted : 21   Submit : 171 Time Limit : 1000 MS   Memory Limit : 65536 KB  题目描述 ABK是一个比A+B还要简单的题目,给出两个整数A,B,求出A和B的第K大公约数. 输入 第一行是一个整数N(N ≤ 10000),表示样例的个数. 以后每行一个样例,为3个整数A,B,K (1≤A,B≤109 , 1≤K≤10) 输出 每行输出一个整数d,表示A,B的第K大公约数 若没有第K大的公约数则输出-1. 思路:先求出a和b

分治法题目整理分析 找第k小的数/求逆序对数目/派

设计一个平均时间为O(n)的算法,在n(1<=n<=1000)个无序的整数中找出第k小的数. 提示:函数int partition(int a[],int left,int right)的功能是根据a[left]~a[right]中的某个元素x(如a[left])对a[left]~a[right]进行划分,划分后的x所在位置的左段全小于等于x,右段全大于等于x,同时利用x所在的位置还可以计算出x是这批数据按升非降序排列的第几个数.因此可以编制int find(int a[],int left,

找出整数中第k大的数

一  问题描述: 找出m个整数中第k(0<k<m+1)大的整数. 二  举例: 假设有12个整数:data[1, 4, -1, -4, 9, 8, 0, 3, -8, 11, 2, -9],请找出第5大的数(容易知道是0). 三   算法思路:        一种基于快排思想的算法可以在O(n)复杂度内找到第k大的数,首先要知道partition这个函数,它可以调整一个序列 使小于key的元素都排在key左边,大于key的元素都排在key右边,key可以在这个序列中任意选择,一般选择给定序 列

Quick-Select 1亿个数快速求第K小的数 分治法

Quick-Select  1亿个数快速求第K小的数  分治法 利用快速排序的思想,一开始选取中枢元,然后左右调整,接着比对中枢元p和K的大小,如果 p+1 = k (数组从0开始), 那么a[p] 就是答案,因为在p之前的,肯定都是小于a[p]的, 在p之后的,肯定大于p, 所以 a[p] 就是第 p+1 小.假如 p+1 不等于K, 那么根据大小,进行左右调整.调整过程中,理想状态下,每次都砍掉一半,数组的起始坐标要进行调整. 代码: // 快速排序法的修改 #include <iostre