九度 1534:数组中第K小的数字(二分法变形)
给定两个整型数组A和B。我们将A和B中的元素两两相加可以得到数组C。
譬如A为[1,2],B为[3,4].那么由A和B中的元素两两相加得到的数组C为[4,5,5,6]。
现在给你数组A和B,求由A和B两两相加得到的数组C中,第K小的数字。
思路
1. 多年前第一次搞这道题就没弄出来, 今天是大概记得做法, 不过 failed again, 总结起来, 仍然是没有意识到 int 的特殊性, 即 (int+int)/2 得到的仍然是 int
2. 涉及到二分查找, 用我以前总结的步骤来做, 非常顺利. 核心就是 mid = target, high = mid-1, 尝试向左. 最后返回的应该是 low
3. target 没有明确给出, 是通过 ini 的特殊性拼凑出来的
4. 曾想将两个数组拼成矩阵, 因为 Leetcode 和剑指 offer 上都有类似的矩阵二分查找题目, 但失败了
代码
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std; long long a[100010]; long long b[100010]; long long search(long long x, long long m, long long n) { long long cnt = 0; long long j = n-1; for(long long i = 0; i < m && j >= 0; i++) { if(a[i] + b[j] <= x) { cnt += (j+1); }else{ while(j >= 0 && a[i]+b[j] > x) { j--; } if(j >= 0) cnt += (j+1); } } //cout << "cnt = " << cnt << endl; return cnt; } long long doCal(long long m, long long n, long long k) { long long low = a[0]+b[0]; long long high = a[m-1] + b[n-1]; while(low <= high) { long long mid = (low+high)>>1; long long cnt = search(mid, m, n); if(cnt >= k) { high = mid -1; }else{ low = mid + 1; } } return low; } int main() { long long m, n, k; //freopen("testcase.txt", "r", stdin); while(scanf("%lld%lld%lld", &m, &n, &k) != EOF) { for(long long i = 0; i < m; i ++) scanf("%lld", &a[i]); for(long long i = 0; i < n; i ++) scanf("%lld", &b[i]); sort(a, a+m); sort(b, b+n); long long res = doCal(m, n, k); printf("%lld\n", res); } return 0; }