题目:有两个n长的非递减序列a和b,将b连接在a的后面成为2n长的序列c。 设计算法求c的中值(第n个小数)。
思路: O(N )的算法很容易找到,但关键是用二分思想设计logn算法。 这个问题的关键是要很好地利用a和b排列中的脚注和作为固定值的要素的大小关系。
直观的想法是,如果中值位于阵列a中,那么对于a[m] b [n-m-1],小于a[m]的数量至少有n个,a[m]不是第n个小数,且不能很大地更新右边界。 如果a[m]介于b[n-m-2]和b [n-m-1]之间,则a[m]正好是第n个小数。 中值与数组b的情况类似。
#包含
using namespace std;
intfindnthnumber(inta (,int n ),int n ) {
int l=0,r=n -1;
int m;
wile(L=R ) {
m=(LR )/2;
if(m==n-1||a[m]b[n-m-2] ) {
//此时,小于a[m]的数最多只有n-2个。 也就是说,a[m]不是第n个小数,而是将左界更新为较小
l=m 1;
}
ELSEif(a[m]b[n-m-1] ) ) ) ) ) ) ) ) ) ) ) )。
//此时,小于a[m]的数正好有n-1个,a[m]是第n个小数,返回
return a[m];
}
else r=m - 1; //此时,小于a[m]的数量至少有n个。 也就是说,a[m]不是第n个小数,而是大大地更新右边界
}
//中值在b数组中时,与上相似
l=0,r=n -1;
wile(L=R ) {
m=(LR )/2;
if(m==n-1||b[m]a[n-m-2] ) {
l=m 1;
}
elseif(b(m ) a ) n-m-1 ) ) {
return b[m];
}
else r=m - 1;
}
}
int main ()。
inta [ ]={ 1,3,4,9,11,20,21 };
intb [ ]={ 2,7,8,10,70,76,79 };
出局
返回0;
}
也可以取a[m]和b[n-m-2]中较大的一个,与a[m 1]和b[n-m-1]进行比较。 简化的代码如下
#包含
using namespace std;
intfindnthnumber(inta (,int n ),int n ) {
int l=0,r=n -1;
int m,tmp;
wile(L=R ) {
m=(LR )/2;
TMP=(a[m]b[n-m-2] )? b[n - m - 2] : a[m];
//tmp取a[m]和b[n-m-2]中较大的一个,与a[m 1]和b[n-m-1]进行比较
if(tmpB(n-m-1 ) ) }
r=m - 1;
}
ELSEif(tmpa[m1] ) {
l=m 1;
}
else return tmp;
}
}
int main ()。
inta [ ]={ 1,3,10,11,12,20,21 };
intb [ ]={ 2,7,8,9,70,76,79 };
出局
返回0;
}