首页 > 其他 > 详细

第k小数3

时间:2018-02-14 00:40:27      阅读:326      评论:0      收藏:0      [点我收藏+]

给定两个升序的整型数组A和B。将A和B中的元素两辆相加可以得到数组C,现在给你数组A和B,求由数组A和B两辆相加得到的数组C中,第k小的数字时多少。

采用二分的方法

显然答案在【a[1] + b[1],a[n] + b[m]】的区间,即下界为a[1] + b[1], 上界为a[n] + b[m],反复枚举上下界的中间值mid与k比较以缩小范围即可找到答案。

假设a[] = 【1,2, 3, 4, 5】,b[] = 【6,7,8,9,10】,mid = a[1] + b[1] = 7, max = a[5] + b[5] = 15, mid = (min + max) / 2 = 11。

从a[1]到a[m],一次逆序与b数组的元素相加,若某一轮中a[i] 加到b[j]时两数和不大于k,则该轮中比k值小的元素的个数为j。

下一轮a[i + 1]与b数组逆序相加时,直接从b[j]开始加即可,因为很显然的,a[i + 1] > a[i]。

累加所有比k值小的元素个数即为mid在两数组中的排序数。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long LL;
 7 LL A[100000], B[100000];
 8 
 9 int compare(const void *p, const void *q)//函数指针
10 /*在这句话里 p,q肯定是一个指针变量
11 (int *)p是表示把p强制转换成一个int型的指针。
12 如果以前p是char型,编译器会认为p指向的那一个字节的内存单元是p里面的东西
13 把a转换成int型,编译器会认为a指向的连续四个字节里的东西都是p里面的。
14 *(int *)p就是取p指向的内容的意思,跟*p的那个*作用一样*/
15 {
16     return *(LL *)p - *(LL *)q;
17 }
18 
19 LL cal(LL A[], LL m, LL B[], LL n, LL mid)//计算mid值在两数组中的排序数
20 {
21     LL i, j;
22     LL cnt = 0;
23     j = n - 1;
24     for(i = 0; i < m; ++i)
25     {
26         while(j >= 0 && A[i] + B[j] > mid)//定位B数组中相加比mid小的位置
27             --j;                            //累计
28         cnt += (j + 1);
29     }
30     return cnt;
31 }
32 LL findKth(LL A[], LL m, LL B[], LL n, LL k)
33 {
34     LL min = A[0] + B[0];
35     LL max = A[m - 1] + B[n - 1];
36     LL mid;
37     LL ans;
38 
39     while(min <= max)
40     {
41         mid = ((max - min) >> 1) + min;
42         if(k <= cal(A, m, B, n, mid))
43             max = mid - 1;
44         else
45             min = mid + 1;
46     }
47 }
48 
49 int main()
50 {
51     LL m, n, k, i;
52     while(scanf("%lld%lld%lld", &m, &n, &k) != EOF)
53     {
54         for(i = 0; i < m; ++i)
55             cin >> A[i];
56         for(i = 0; i < n; ++i)
57             cin >> B[i];
58         qsort(A, m, sizeof(LL), compare);
59         qsort(B, n, sizeof(LL), compare);
60         cout << findKth(A, m, B, n, k);
61     }
62     return 0;
63 }

将cal函数也采用二分查找的方式计算小于等于k的数字个数

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 long long a[109999];
 8 long long b[109999];
 9 long long n, m;
10 
11 
12 long long cmp(long long a, long long b)
13 {
14     return a < b;
15 }
16 
17 long long cal(long long v)
18 {
19     long long ll, rr, mid, i, add = 0;
20     long long min, max;
21     for(i = 1; i <= n; i++)
22     {
23         min = a[i] + b[1];
24         max = a[i] + b[m];
25         if(v < min)
26             break;
27         if(v >= max)
28         {
29             add += m;
30             continue;
31         }
32         ll = 1;
33         rr = m;
34         while(ll <= rr)
35         {
36             mid = (ll + rr) / 2;
37             if(v < (a[i] + b[mid]))
38                 rr = mid - 1;
39             else
40                 ll = mid + 1;
41         }
42         if(v != (a[i] + b[ll]))
43             ll--;
44         add += ll;
45     }
46     return mid;
47 }
48 
49 long long find(long long ll, long long rr, long long k)
50 {
51     long long mid, i;
52     while(ll <= rr)
53     {
54         mid = (ll + rr) / 2;
55         if(k < cal(mid))
56             rr = mid - 1;
57         else
58             ll = mid + 1;
59     }
60     return ll;
61 }
62 
63 int main()
64 {
65     long long k, ll, rr;
66     while(scanf("%ld%ld%ld", &n, &m, &k) != EOF)
67     {
68         long long i;
69         for(i = 1; i <= n; i++)
70             cin >> a[i];
71         for(i = 1; i <= m; i++)
72             cin >> b[i];
73         sort(&a[1], &a[n + 1], cmp);
74         sort(&b[1], &b[1 + m], cmp);
75 
76         ll = a[1] + b[1];
77         rr = a[n] + b[m];
78 
79         cout << find(ll, rr, k) << endl;
80     }
81     return 0;
82 }

 

第k小数3

原文:https://www.cnblogs.com/CZT-TS/p/8447760.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!