这里是两个有序的数组 ,所以两个有序的数组都给它变成固定的奇数个数 ,就是虚拟加入“#”
注意是虚拟加 这样做起来就很方便了 ,所以两个数组总和就是2m+2n+2
假设第一个是m个原来 第二个是n个
这样两个有序数组合并以后的中位数就是m+n+1
这有什么好处呢,为什么这么加?因为这么加完之后,每个位置可以通过/2得到原来元素的位置。
让数组恒为奇数,有没有办法让两个数组长度相加一定为奇数或偶数呢?
其实有的,虚拟加入‘#’(这个trick在manacher算法中也有应用),让数组长度恒为奇数(2n+1恒为奇数)。
Ps.注意是虚拟加,其实根本没这一步,因为通过下面的转换,我们可以保证虚拟加后每个元素跟原来的元素一一对应
之前 len 之后 len
[1 4 7 9] 4 [# 1 # 4 # 7 # 9 #] 9
[2 3 5] 3 [# 2 # 3 # 5 #] 7
映射关系
这有什么好处呢,为什么这么加?因为这么加完之后,每个位置可以通过/2得到原来元素的位置。
/ 原位置 新位置 除2后
0 1 0 1
5 2 5 2
在虚拟数组里表示“割”,不仅如此,割更容易,如果割在‘#’上等于割在2个元素之间,割在数字上等于把数字划到2个部分。
例:
1. 割在4/7之间‘#’,C = 4,L=(4-1)/2=1 ,R=4/2=2
刚好是4和7的原来位置!
2. 割在3上,C = 3,L=(3-1)/2=1,R=3/2 =1,刚好都是3的位置!
Mid = (A[m+n+1]+A[m+n+2])/2
= (Max(L1+L2) + Min(R1+R2) )/2
至于在两个数组里找割的方案,就是上面的方案。
怎么分?
最快的分的方案是二分,有2个数组,我们对哪个做二分呢?
根据之前的分析,我们知道了,只要C1或C2确定,另外一个也就确定了。这里,为了效率,我们肯定是选长度较短的做二分,假设为C1。
L1 | R1 |
L2 | R2 |
怎么治?
也比较简单,我们之前分析了:就是比较L1,L2和R1,R2。
- L1>R2,把C1减小,C2增大。—> C1向左二分
- L2>R1,把C1增大,C2减小。—> C1向右二分
越界问题
如果C1或C2已经到头了怎么办?
这种情况出现在:如果有个数组完全小于或大于中值。可能有4种情况:
- C1 = 0 —— 数组1整体都比中值大,L1=nums1((c1-1)/2)
- C2 = 0 —— 数组1整体都比中值小,L2-nums2((c2-1)/2)
- C1=2*n-----数组1整体都比中值小,R1=nums1(c1/2)
- C2=2*n-----数组2整体都比中值小, R2=nums2(c2/2);
测试代码:
#include
#include
#include
#include
using namespace std;
/*
*找出两个有序数数组的中位数
*/
class leet_04{
public:
double findMediaSortedArray(const vector& nums1,const vector&nums2)
{
int n=nums1.size();
int m=nums2.size();
if(n>m)//确保数组长度最短的进行二分。递归
return findMediaSortedArray(nums2,nums1);
int L1,L2,R1,R2,c1,c2,left=0,right=2*n;//虚拟的加上#号后变成2n+1,但是数组的下标是从零开始的
while(left<=right) //采用二分法
{
c1=(left+right)/2;//c1是二分法的结果
c2=m+n-c1;//k=n+m.确保数组左右加起来等于k
L1=(c1==0)?INT_MIN:nums1[(c1-1)/2];
R1=(c1==2*n)?INT_MAX:nums1[c1/2];
L2=(c2==0)?INT_MIN:nums2[(c2-1)/2];
R2=(c2==2*m)?INT_MAX:nums2[(c2/2)];
if(L1>R2)
right=c1-1;
else if(L2>R1)
left=c1+1;
else
break;
}
return ((max(L1,L2)+min(R1,R2))/2.0);
}
};
//test
int main()
{
int arr1[]={1,2};
int arr2[]={3,4};
vector nums1(arr1,arr1+sizeof(arr1)/sizeof(int));
vector nums2(arr2,arr2+sizeof(arr2)/sizeof(int));
leet_04 test;
double mediaval=test.findMediaSortedArray(nums1,nums2);
cout<