• 求一个数组中第K小的数


    面试南大夏令营的同学说被问到了这个问题,我的第一反应是建小顶堆,但是据他说用的是快排的方法说是O(n)的时间复杂度,

    但是后来经过我的考证,这个算法在最坏的情况下是O(n^2)的,但是使用堆在一般情况下是O(n+klogn),最坏的情况是O(nlogn)

    把两种方法整理一下,我还是推荐使用小顶堆的方法,因为它不仅可以求第K大,还可以求前K大。。。

    一。快排。借用了快排的partition思想,其实是一种分治的方法。对于一个partition,他左边的数小于他,右边的数全大于他

    那么:

      1.如果他本身就是第K个数,直接返回。

      2.如果他的下标是比K大的某个数,那么第K小数肯定出现在他左边。那么到partition的左边递归地求解

      3.如果他的下标是比K小的某个数,那么第K小数肯定出现在他右边。那么到partition的右边递归地求解

    唯一需要注意的地方是,要注意在递归的过程中,第K小数是一个相对值,即相对于区间[l,r]的左边界l;

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1000;
    int a[maxn];
    int n = 10,k = 6;
    
    int part(int low, int high)
    {
        int pivot = a[low];
        while(low < high){
            while(low < high&&a[high] >= pivot) high--;
            a[low] = a[high];
            while(low < high&&a[low] <= pivot) low++;
            a[high] = a[low];
        }
        a[low]=pivot;
        return low;
    }
    
    int quicksort(int l, int r, int k){
        int pos = part(l,r);
        if(pos - l + 1 == k) return a[pos];
        else if(pos - l + 1> k) return quicksort(l,pos-1,k);
        else return quicksort(pos+1,r,k-(pos-l+1));
    }
    
    int main()
    {
        srand((unsigned)time(NULL));
        for(int i = 0; i < n; ++i){
            a[i] = rand()%(n<<1);
        }
        for(int i = 0; i < n; ++i)
            printf("%d ",a[i]);
        printf("
    ");
        int x = quicksort(0,n-1,k);
        printf("%d
    ", x);
    }

    二。小顶堆

    使用堆可以求出最小的元素,通过不断地弹出元素,就可以找到第K大的元素

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1000;
    int a[maxn];
    int n,k;
    
    void adjust_heap(int rt,int n)
    {
        int x=a[rt],pos = rt;
        while(rt <= n){
            int lc = rt << 1,rc = lc|1;
            if(lc <= n&&a[lc] < x) pos = lc;
            if(rc <= n&&a[rc] < a[pos]) pos = rc;
            if(pos == rt) break;
            a[rt] = a[pos];
            rt = pos;
        }
        a[pos] = x;
    }
    
    int search_k()
    {
        for(int i = n/2;i >= 1; --i){//建堆的复杂度是O(n)的
            adjust_heap(i,n);
        }
        int sz = n;
        for(int i = 1; i < k; ++i){//每次弹出要向下调整,调整K次,复杂度为O(Klogn)
            a[1] = a[sz--];
            adjust_heap(1,sz);
        }
        return a[1];
    }
    int main()
    {
        srand((unsigned)time(NULL));
        scanf("%d%d",&n,&k);
        for(int i = 1; i <= n; ++i){
            a[i] = rand()%(n<<1);
        }
        for(int i = 1; i <= n; ++i)
            printf("%d ",a[i]);
        printf("
    ");
        int x = search_k();
        printf("%d
    ", x);
    }
  • 相关阅读:
    构建之法阅读笔记07
    7-第一阶段SCRUM冲刺
    第一阶段个人冲刺博客第十天
    第一阶段个人冲刺博客第九天
    第九周学习进度博客
    java项目(学习和研究)
    让计算机干活
    os基础
    树和图的一些算法
    java代码理解
  • 原文地址:https://www.cnblogs.com/Norlan/p/5502927.html
Copyright © 2020-2023  润新知