第k大

17082 两个有序数序列中找第k小(必做)

时间限制:1000MS  内存限制:65535K 提交次数:0 通过次数:0 

题型: 编程题   语言: G++;GCC;VC;JAVA

Description

已知两个已经排好序(非减序)的序列X和Y,其中X的长度为m,Y长度为n,
现在请你用分治算法,找出X和Y的第k小的数,算法时间复杂度为O(max{logm, logn})。

此题请勿采用将序列X和Y合并找第k小的O(m+n)的一般方法,要充分利用X和Y已经排好序的这一特性。

输入格式

第一行有三个数,分别是长度m、长度n和k,中间空格相连(1<=m,n<=100000; 1<=k<=m+n)。
第二行m个数分别是非减序的序列X。第三行n个数分别是非减序的序列Y。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #define maxn 100010
 4 int a[maxn],b[maxn],k;
 5 
 6 int f(int la,int ra,int lb,int rb)//类似2分法
 7 {
 8     int halflen, ma, mb;
 9     if(lb > rb) return a[la+k-1];//递归边界
10     if(la > ra) return b[lb+k-1];//递归边界
11     ma=(ra + la) / 2;
12     mb=(rb + lb) / 2;
13     halflen = ma - la + mb - lb + 2;//两个数组左边的数量
14     if(a[ma] < b[mb])
15     {    //如果左边的数量还是比k大,则第k小的在两个数组的左边,而且第k大的坑定比b[mb]小
16          //则将b数组的右边去掉,在进行递归
17         if(k < halflen) return f(la, ra, lb, mb-1);  
18         //如果左边的数量还是比k小,则第k小的在两个数组的右边,而且第k大的坑定比a[ma]大
19          //则将a数组的左边去掉,在进行递归,递归之前,要把k更新,不在是第k小了,而是
20          //k - (ma - la + 1);
21         k = k - (ma - la + 1);
22         return f(ma+1, ra, lb, rb);
23    }
24     else
25     {
26         
27         //同上
28         if(k < halflen) return f(la, ma-1, lb, rb);
29         k = k - ( mb - lb + 1);
30         return f(la, ra, mb+1, rb);
31     }
32 }
33 
34 int main()
35 {
36     int m,n,i;
37 
38     scanf("%d%d%d",&m,&n,&k);
39     for(i=0; i<m; i++)
40         scanf("%d",&a[i]);
41     for(i=0; i<n; i++)
42         scanf("%d",&b[i]);
43     printf("%d\n",f(0,m-1,0,n-1));
44     return 0;
45 }
View Code



原文地址:https://www.cnblogs.com/iwssea/p/4875589.html