第k小数1

对于给定的n个元素的无序数组,要求从中找出第k小的元素

二分法+快速排序

例如一列由10个元素组成的数组:[5, 7, 1, 2, 3, 9, 8, 10,  4, 6],假设找出k = 4 的元素。

将第一个元素5作为参照物, 将比5小的数放在5的左边,比5大的数放在5的右边,则数组第一次调整为【2,1,4,3】5【10,9,8,7】。

比5小的数由4个,所以将搜索范围缩小到5的左边数组即【2,1,4,3】舍弃右边的数组。

以2为参照物, 将比2小的数字放在2的左边,比2大的数字放在2的右边。则数组的第二次调整为:【1】2【4,3】。

可以看出,2为数组中第2小的数字,所以将搜索范围缩小到2的右边数组【4,3】,舍弃左边的数组。

最后一次找到第4小的数字为4。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<algorithm>
 6 using namespace std;
 7 int a[100001], b[100001];
 8 int i, j, m, k, l;
 9
10 void Swap()
11 {
12     swap(a[i], a[j]);
13     swap(i, j);
14 }
15
16 void Operation(int START, int END)
17 {
18     i = START;
19     j = END;
20     while(i != j)
21     {
22         if(i < j)
23         {
24             if(a[i] > a[j])
25                 Swap();
26             else
27                 j--;
28         }
29         else
30         {
31             if(a[i] < a[j])
32                 Swap();
33             else
34                 j++;
35         }
36     }
37     if(i < k)
38         Operation(i + 1, END);
39     else if(i == k)
40     {
41         for(l = 1; l <= m; l++)
42         {
43             if(b[l] == a[i])
44             {
45                 cout << l << endl;
46                 break;
47             }
48         }
49     }
50     else
51         Operation(START, i - 1);
52 }
53 int main()
54 {
55     cin >> m >> k;
56     for(int i = 1; i <= m; i++)
57     {
58         cin >> a[i];
59         b[i] = a[i];
60     }
61     Operation(1, m);
62     return 0;
63 }

如果在线性时间内找到划分的基准,则可以在最坏情况下复杂度为O(n)时找到第k小的数。

方法如下

(1)将数组a五个数为一组,分为【n/5】个组。

(2)对【n/5】个组的数进行组内排序,采用冒泡排序等任何方法均可。

(3)选择每组的中位数,将这些中位数交换到数组的最前面,此时a[0 ~(end - start)/ 5 - 1]中存的就是这些中位数。

(4)对a[0 ~(end - start)/ 5 - 1]个中位数进行排序,取出排序后这些中位数的中位数x,则x就是需要的划分标准。

(5)以x为基准再次进行二分,比较,递归寻找即可。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<algorithm>
 6 using namespace std;
 7 int a[100001], b[100001];
 8 int i, j, m, k, l;
 9 int cmp(int x, int y)
10 {
11     return x < y;
12 }
13 void Swap()
14 {
15     swap(a[i], a[j]);
16     swap(i, j);
17 }
18
19 void Operation(int START, int END)
20 {
21     i = START;
22     j = END;
23     while(i != j)
24     {
25         if(i < j)
26         {
27             if(a[i] > a[j])
28                 Swap();
29             else
30                 j--;
31         }
32         else
33         {
34             if(a[i] < a[j])
35                 Swap();
36             else
37                 j++;
38         }
39     }
40     if(i < k)
41         Operation(i + 1, END);
42     else if(i == k)
43     {
44         for(l = 1; l <= m; l++)
45         {
46             if(b[l] == a[i])
47             {
48                 cout << l << endl;
49                 break;
50             }
51         }
52     }
53     else
54         Operation(START, i - 1);
55 }
56 int main()
57 {
58     cin >> m >> k;
59     for(int i = 1; i <= m; i++)
60     {
61         cin >> a[i];
62         b[i] = a[i];
63     }
64     for(i = 6; i <= m + 1; i = i + 5)
65     {
66         sort(a + i - 5, a + i, cmp);
67     }
68     for(i = 1; i <= m/5; i++)
69         swap(a[i], a[i * 5 - 2]);
70     sort(a + 1, a + i, cmp);
71     swap(a[1], a[i / 2]);
72     Operation(1, m);
73     return 0;
74 }

原文地址:https://www.cnblogs.com/CZT-TS/p/8447696.html

时间: 2024-10-13 11:15:31

第k小数1的相关文章

关于利用快排思想求第K小数的分析

最近复习快排算法,记得当时最有意思的是可以用快排的partition函数求出第K小数 于是上网搜索一番,发现都只是贴出了代码.无奈只好自己研究了下 利用快排partition求第k小数不得不从partition函数开始说: 快速排序的思想是在一组待排序的数中,找出一个数作为分界,使得它前面的数都比它小,后面的数都比它大.这个数叫做枢轴 当求出一组数的枢轴以后,一组数就可以以枢轴为界限分成两组,我们可以递归的找出这两个组的枢轴,只到每组只有一个数 这里我们应该注意的是,partition函数返回的

Bsoj 1322 第K小数

第K小数 Description 现在已有N个整数,你有以下三种操作: 1 A:表示加入一个值为A的整数: 2 B:表示删除其中值为B的整数: 3 K:表示输出这些整数中第K小的数: Input 第一行,两个整数N,M,表示最开始有N个整数,总共有M个操作 第二行用空格隔开的N个整数 接下来M行,每行表示一个操作 Output 若干行,一行一个整数,表示所求的第K小的数字 Sample Input 5 5 6 2 7 4 9 1 8 1 6 3 10 2 4 3 3 Sample Output

hiho week 37 P1 : 二分&#183;二分查找之k小数

P1 : 二分·二分查找之k小数 Time Limit:10000ms Case Time Limit:1000ms Memory Limit:256MB 描述 在上一回里我们知道Nettle在玩<艦これ>,Nettle的镇守府有很多船位,但船位再多也是有限的.Nettle通过捞船又出了一艘稀有的 船,但是已有的N(1≤N≤1,000,000)个船位都已经有船了.所以Nettle不得不把其中一艘船拆掉来让位给新的船.Nettle思考了很久, 决定随机选择一个k,然后拆掉稀有度第k小的船. 已知

【COGS 1534】 [NEERC 2004]K小数 &amp;&amp;【COGS 930】 [河南省队2012] 找第k小的数 可持久化01Trie

板子题,只是记得负数加fix最方便 #include <cstdio> const int A=19,N=100010; namespace FIFO { char ch,B[1<<20],*S=B,*T=B; #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<20,stdin),S==T)?0:*S++) #define isd(c) (c>='0'&&c<='9') int aa,bb

第K 小数

[问题描述]有两个正整数数列,元素个数分别为N和M.从两个数列中分别任取一个数相乘,这样一共可以得到N*M个数,询问这N*M个数中第K小数是多少.[输入格式]输入文件名为number.in.输入文件包含三行.第一行为三个正整数N,M和K.第二行为N个正整数,表示第一个数列.第三行为M个正整数,表述第二个数列.[输出格式]输出文件名为number.out.输出文件包含一行,一个正整数表示第K小数.[输入输出样例1 1 ]number.in 2 3 41 22 1 3 number.out3[输入输

HDU 2852 KiKi&#39;s K-Number(动态过程求第K小数)

题意: 给出三种操作, 0 在容器中插入一个数. 1 在容器中删除一个数. 2 求出容器中大于a的第k大元素. 思路:可以用树状数组和线段树,显然a[1]+...+a[i]随i有明显的单调性,所以可以二分出答案 线段树时间复杂度比树状数组的常数大了几倍...所以线段树擦边过了 还有另外一种思路:二分只是二分出a[1]+...+a[i]的上界i,所以可以逆向考虑,从a[1]开始累加,直到到达k,这样的复杂度就由原来的 O(lgN*lgN) 变成O(lgN)了.难在累加的过程,线段树和树状数组是同样

OJ2237第k小数题解

题目描述: 有n个数,请你找出第k小的数. 输入描述: 第一行有2个正整数n,k(n,k<=10^7)第二行有n个非负数ai(ai<=10^5) 输出描述: 输出第k小的数. 输入样例: 5 21 5 3 4 5 输出样例: 3 题目分析: 这道题目言简意赅,其实很明显我们就能想到一种解法:就是排序.将这n个数字进行排序后,输出第k小的数字就可以了.在这里,我们发现sort函数非常适合解这道题目,因为数据是百万级别的,并且sort函数是默认从小到大排序的.接下来代码就很容易实现了. 代码: #

hiho#1133 : 二分&#183;二分查找之k小数

#1133 : 二分·二分查找之k小数 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 在上一回里我们知道Nettle在玩<艦これ>,Nettle的镇守府有很多船位,但船位再多也是有限的.Nettle通过捞船又出了一艘稀有的船,但是已有的N(1≤N≤1,000,000)个船位都已经有船了.所以Nettle不得不把其中一艘船拆掉来让位给新的船.Nettle思考了很久,决定随机选择一个k,然后拆掉稀有度第k小的船. 已知每一艘船都有自己的稀有度,Nettle现在把所有

数组第K小数

题目描述 给定一个整数数组a[0,...,n-1],求数组中第k小数 输入描述 首先输入数组长度n和k,其中1<=n<=5000, 1<=k<=n 然后输出n个整形元素,每个数的范围[1, 5000] 输出描述 该数组中第k小数 样例输入 4 2 1 2 3 4 样例输出 2 其实可以用 堆 来做,保证根节点为最小值,然后逐步剔除.不过当然也可以直接排序.权当熟悉一下STL: 1 #include <vector> 2 #include <algorithm>

求两个有序序列合并成新有序序列的中位数,求第k小数

此算法涉及一个重要数学结论:如果A[k/2-1]<B[k/2-1],那么A[0]~A[k/2-1]一定在第k小的数的序列当中,可以用反证法证明. 更加一般的结论是:k=pa+pb,如果A[pa-1]<B[pb-1],那么A[0]~A[pa-1]一定在第k小的数的序列当中. 算法思想如下: 1,假设A长度为m,B长度为n,m>n,反之亦然. 2,拆分k=pa+pb. 3,如果A[pa-1]<b[pb-1],那证明第A[0]~A[pa-1]一定在合并后k小数序列中.所以,可以把A的前面