解题思路:
第一种想到的解法是二分查找,但是来点创意总是好的,这时候归并的思路就来了。
我们知道归并排序将子序列合成的过程就是一个比较两个有序子序列的头的过程,那么正好可以拿来处理这道题。
设置一个计数器,每舍弃一个数,计数器加一,当加到mid时,输出当前舍弃的数即可。时间复杂度为O(n),
额外的空间复杂度为O(1),完全可接受。
代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1000000 + 5;
int num1[maxn], num2[maxn];
int main()
{
int n, m, cnt = 0; //cnt 计数
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &num1[i]);
scanf("%d", &m);
for(int i = 0; i < m; i++)
scanf("%d", &num2[i]);
int i = 0, j = 0, flag; //flag标记本轮舍弃的是哪个数组的数据
int mid = (n+m+1)/2; //mid设置比较关键,由于总是输出当前舍弃的前一位,
//为了统一奇数和偶数的操作,将奇数情况下的mid+1。
if(n > 0 && m > 0) flag = num1[i] <= num2[j] ? 1 : 0;
while(i < n || j < m)
{
if(i < n && j < m)
{
if(num1[i] <= num2[j]) {i++; cnt++; flag = 1;}
else {j++; cnt++; flag = 0;}
}
else if(i < n) {i++; cnt++; flag = 1;}
else if(j < m) {j++; cnt++; flag = 0;}
if(cnt == mid)
{
if(flag) printf("%d\n", num1[i-1]);
else printf("%d\n", num2[j-1]);
break;
}
}
return 0;
}
————————————————
补充,参考了一下大神的代码,发现在每个数组后加一个表示无穷大的值,能统一操作,代码更清晰:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1000000 + 5;
const int INF = 0x3fffffff;
int num1[maxn], num2[maxn];
int main()
{
int n, m, cnt = 0; //cnt 计数
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &num1[i]);
scanf("%d", &m);
for(int i = 0; i < m; i++)
scanf("%d", &num2[i]);
num1[n] = num2[m] = INF;
int i = 0, j = 0, flag; //flag标记本轮舍弃的是哪个数组的数据
int mid = (n+m+1)/2; //mid设置比较关键,由于总是输出当前舍弃的前一位,
//为了统一奇数和偶数的操作,将奇数情况下的mid+1。
if(n > 0 && m > 0) flag = num1[i] <= num2[j] ? 1 : 0;
while(cnt < mid)
{
if(num1[i] <= num2[j]) {i++;flag = 1;}
else {j++;flag = 0;};
cnt++;
}
if(flag) printf("%d\n", num1[i-1]);
else printf("%d\n", num2[j-1]);
return 0;
}