• 【hihoCoder】#1133 : 二分·二分查找之k小数


    题目描述

    在上一回里我们知道Nettle在玩《艦これ》,Nettle的镇守府有很多船位,但船位再多也是有限的。Nettle通过捞船又出了一艘稀有的船,但是已有的N(1≤N≤1,000,000)个船位都已经有船了。所以Nettle不得不把其中一艘船拆掉来让位给新的船。Nettle思考了很久,决定随机选择一个k,然后拆掉稀有度第k小的船。 已知每一艘船都有自己的稀有度,Nettle现在把所有船的稀有度值告诉你,希望你能帮他找出目标船。

    输入

    第1行:2个整数N,k。N表示数组长度,
    第2行:N个整数,表示a[1..N],保证不会出现重复的数,1≤a[i]≤2,000,000,000。

    输出

    第1行:一个整数t,表示t在数组中是第k小的数,若K不在数组中,输出-1。

    样例输入

    10 4
    1732 4176 2602 6176 1303 6207 3125 1 1011 6600

    样例输出

    1732

    算法

    无意间刷到这题,并且原题已经给出算法的提示。趁着这题让我回顾了下快速排序,并且在这边先记录这题算法的核心思想。

    快速排序每次都能确定一个元素的位置,也就是说,能知道这个元素是数组中第几小的数。那么将k与该元素所在的位置进行比较:
    如果正好就是第k小的数,直接打印退出即可;
    如果该位置比k大,说明第k小的数在该元素左边的那堆数中,往左边走,重复之前的步骤;
    如果该位置比k小,说明第k小的数在该元素右边的那堆数中,往右边走,重复之前的步骤。
    
    由于不是进行全局的交换位置,每次都交换需要寻找的区域,所以时间复杂度为O(logn);但是当遇见一开始就完全有序的情况,或者是从大到小排序的情况就比较蛋疼,所以最后能放置一个标志位,如果一轮下来不曾交换可以直接通过数学的方法计算出第k小的位置。当然,这是在本题中这么说,如果真实的快排中,选择主元是一门比较大的学问。
    
    当然这题也可以用堆排序实现,维护一个N-k这么大的最小堆,最后的堆顶就是需要找的元素,说实话借助优先队列的话,还是十分简单的。
    

    代码

    #include <iostream>
    using namespace std;
    
    void Swap(int &a, int &b)
    {
        int tmp = a;
        a = b;
        b = tmp;
    }
    
    int main()
    {
        // freopen("stdin.txt", "r", stdin);
        int N, k;
        scanf("%d %d", &N, &k);
        int Arr[N];
        for (int i = 0; i < N; i++)
        {
            scanf("%d", &Arr[i]);
        }
        if (k < 1 || k > N)
            printf("-1
    ");
        
        // 算法主体
        int left = 0, right = N-1;
        while(left <= right)
        {
            int pivot = Arr[left];
            int p = left, q = right;
            while (1)
            {
                while (Arr[q] >= pivot && q > p)
                    q--;
                while (Arr[p] <= pivot && p < q)
                    p++;
                if (p < q)
                    swap(Arr[p], Arr[q]);
                else
                    break;
            }
            
            Swap(Arr[left], Arr[p]);
            // for (int f = 0; f < N; f++)
            //     cout << Arr[f] << ' ';
            // cout << endl;
    
            if(p == k-1)
            {
                printf("%d
    ", Arr[p]);
                break;
            }
            else if (p > k-1)
                right = p - 1;
            else
                left = p + 1;
        }
        return 0;
    }
    
  • 相关阅读:
    Connected Components? Codeforces
    洛谷 P1344 [USACO4.4]追查坏牛奶Pollutant Control
    洛谷 P4174 [NOI2006]最大获利 && 洛谷 P2762 太空飞行计划问题 (最大权闭合子图 && 最小割输出任意一组方案)
    表达式求值
    费用流(自用,勿看)
    二分图??(自用,勿看)
    C 标准库
    Linux-socket使用
    C 标准库
    C 标准库
  • 原文地址:https://www.cnblogs.com/shayue/p/10480126.html
Copyright © 2020-2023  润新知