王道P18 T11
输入两个长度相同的升序数组,返回这两个数组合并后的中位数
C++代码:
int bisearch_midNum(int a[],int b[],int n){ int s1=0,s2=0,d1=n-1,d2=n-1,m1,m2; while(s1!=d1 || s2!=d2){//只要a,b序列同时出现了s==d的情况,才能False退出 m1=(s1+d1)/2; m2=(s2+d2)/2; system("pause"); if(a[m1]==b[m2]) return a[m1]; else if(a[m1]<b[m2]){//∈[m1,m2] d2=m2; if((d1-s1)%2){//偶数 m1++;//舍去中间位 } s1=m1; }else{ //∈[0,m1]∪[m2,n] d1=m1; if((d2-s2)%2){//偶数 m2++;//舍去中间位 } s2=m2; } } //返回较小者 return min(a[s1],b[s2]); }
完整代码:
#include <cstdio> #include <memory.h> #include <cmath> #include <string> #include <vector> #include <set> #include <stack> #include <queue> #include <algorithm> #include <map> #include <stdlib.h> #include <time.h> #define I scanf #define OL puts #define O printf #define F(a,b,c) for(a=b;a<c;a++) #define FF(a,b) for(a=0;a<b;a++) #define FG(a,b) for(a=b-1;a>=0;a--) #define LEN 200 #define MAX 0x7FFFFFFF using namespace std; void disp(int * sqList,int length); int bisearch_midNum(int a[],int b[],int n); int main() { while(1){ srand((unsigned)time(NULL)); int a[20]; int *b=a+10; for(int i=0;i<10;i++){a[i]=rand()%20;b[i]=rand()%20;} sort(a,a+10); sort(b,b+10); OL("a:"); disp(a,10); OL("b:"); disp(b,10); O("mid number:"); O("%d ",bisearch_midNum(a,b,10)); sort(a,a+20); OL("merge:"); disp(a,20); system("pause"); system("cls"); } } void disp(int * sqList,int length){ int i=0; FF(i,length){ printf("%d ",sqList[i]); } OL(""); } int bisearch_midNum(int a[],int b[],int n){ int s1=0,s2=0,d1=n-1,d2=n-1,m1,m2; while(s1!=d1 || s2!=d2){//只要a,b序列同时出现了s==d的情况,才能False退出 m1=(s1+d1)/2; m2=(s2+d2)/2; printf("%d %d %d ",s1,d1,m1); printf("%d %d %d ",a[s1],a[d1],a[m1]); printf("%d %d %d ",s2,d2,m2); printf("%d %d %d ",b[s2],b[d2],b[m2]); system("pause"); if(a[m1]==b[m2]) return a[m1]; else if(a[m1]<b[m2]){//∈[m1,m2] d2=m2; if((d1-s1)%2){//偶数 m1++;//舍去中间位 } s1=m1; }else{ //∈[0,m1]∪[m2,n] d1=m1; if((d2-s2)%2){//偶数 m2++;//舍去中间位 } s2=m2; } } //返回较小者 return min(a[s1],b[s2]); }
一步一调理解此题:
●第一组数据:
第一步:a→ ←b
(如果【s1,d1】是偶数,就舍弃m1,即(m1,d1])
第二步:a→ ←b
第三步:←a b→
第四步:←a b→
b的中位数取9是因为【←a b→】这种情况要舍弃左边的m。
m1==s1,m2==s2,终止。在a【s1】与 b【s2】中取最小者,即6。
两个数组融合后的中位数也为6:
我的一些理解:
1.关于偶数时舍弃m:
在迭代的最后,a,b中都只剩下两个元素。
情况1:a→ ←b
这时候b的m会自动定位到左边然后==s1,但是a的m也会往左定位,就不满足a→ 了。所以要舍弃m。
情况2: ←b a→
同理可得。
2.关于返回较小的变量:
如图,此时有两个候选变量,一个是6,一个是9。因为二分搜索的性质,在偶数的情况下,其实定位的m是那个偏小的元素,并且输入的数组都是升序。
感悟:
感觉这题难爆了,只能想出O(N)的算法。本题的思想是用了两个数组都是升序的特点,通多二分查找找到两个尽可能相等的数a[m1]和b[m2] 。