Median of Two Sorted Arrays
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Example 1:nums1 = [1,3]
nums2 = [2]
The median is 2.0
Example 2:
nums1 = [1,2]
nums2 = [3,4]
The median is (2+3)/2 = 2.5
以下内容可能表达的不是太好,凑合着看吧,感觉思路其实并不会很复杂,就是考虑的东西比较多。
解题思路:
这道题一看复杂度要求为O(log (m+n)),觉得应该利用二分查找来获得中间值。
我的想法是,相当于将这些数平均分成两堆,其中一堆的值(称为小堆)都小于另一堆的值(大堆)。那在代码中,主要要判断的点有这几个:
(1)堆中数的数量是否满足要求
(2)小堆中的数是否都小于大堆中的数
(3)总数是奇数还是偶数(我感觉这个应该会有更好的办法来处理,但是我没想出来,所以也导致了代码很长)
那么,先将这两个数组看作长数组la和短数组sa,把小堆的数量表示为len,目标数量为midlen,la中的二分查找的获得的值的下标为i,数值为la[i],sa中二分查找的获得的值的下标为j,数值为sa[j],假设包括这la[i]和sa[j]在内以及在它们之前的数都归在小堆里面,则len = i+j+2(下标从0开始)
if len<midlen
if la[i] < sa[j]
i 向右折叠
else
j 向右折叠
else if len>midlen
if la[i] < sa[j]
j 向左折叠
else
i 向左折叠
不断迭代直到满足要求。
可能我考虑的东西有点多,导致代码写起来好多...等以后有空再来想想改进的地方,或者求大神们给出些建议。不过效果还是不错的,run那个示例是用了1ms,submit的结果基本都是在70ms左右。
public class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
double answer = 0.0;
int totallen = nums1.length + nums2.length;
int midlen = (totallen+1)/2;
boolean isEven = true;
if(totallen%2 != 0)
isEven = false;
int[] numlong = nums1,numshort = nums2;
//必须保证长数组跟短数组的顺序
if(nums1.length <nums2.length)
{
numlong = nums2;
numshort = nums1;
}
//考虑其中一个数组为空
if(numshort.length == 0)
{
if(isEven == true)
return((numlong[(numlong.length-1)/2]+numlong[(numlong.length-1)/2+1])/2.0);
else
return(numlong[numlong.length/2]);
}
int ls = 0,lm = (numlong.length-1)/2,ll = numlong.length-1;
int ss = 0,sm = numshort.length-1,sl = numshort.length-1;
if(ll == 0)
return (numlong[0]+numshort[0])/2.0;
int num1,num2;
while(true)
{
int len = lm+1+sm+1;
int a = numlong[lm];
int b = numshort[sm];
//当其中一个数组已经利用二分法缩小到只有一个值
if((ls == ll) || (ss == sl))
{
int[] numm;
int k1,k2,mm,ml;
if(ss == sl)
{
numm = numlong;
k1 = b;
k2 = a;
mm = lm;
ml = numlong.length-1;
}
else
{
numm = numshort;
k1 = a;
k2 = b;
mm = sm;
ml = numshort.length-1;
}
//此时两堆的大小符合要求
if(len == midlen)
{
if(k1>=k2 && k1<=numm[mm+1])
{
num1 = k1;
num2 = numm[mm+1];
}
else if(k1>numm[mm+1])
{
num1 = numm[mm+1];
if (mm+2 <= ml)
num2 = Math.min(k1, numm[mm+2]);
else
num2 = k1;
break;
}
else
{
num1 = k2;
num2 = numm[mm+1];
break;
}
}
//如果两堆的大小不符合要求
else
{
//主要针对其中一个数组中的所有值都大于另一个数组中的值
//此时小堆中的最大值和大堆中的最小值都出自于同一数组
//例如[1,2,3,4,5],[6]
if(k1>=numm[mm+midlen-len+2])
{
num1 = numm[mm+midlen-len+1];
num2 = numm[mm+midlen-len+2];
}
//针对某种情况...具体是哪种我忘了。如果在这里提前判断奇偶的话就不用这个了
else if(mm+midlen-len >= 0)
{
int x1 = numm[mm+midlen-len];
int x2 = numm[mm+midlen-len+1];
num1 = Math.min(Math.max(k1, x1), x2);
num2 = Math.max(Math.max(k1, x1), x2);
}
else
{
num1 = k1;
num2 = numm[mm+midlen-len+1];
}
}
break;
}
//利用二分法进行迭代查找
if(len > midlen)
{
if(a>=b)
ll = lm;
else
sl = sm;
}
else if(len < midlen)
{
if(a>=b)
ss = sm+1;
else
ls = lm+1;
}
//当迭代到两个堆中的数量满足要求,判断此时两边的数的分布是否满足要求
else
{
if(a>=b)
{
if(a<=numshort[sm+1])
{
num1 = a;
num2 = Math.min(numshort[sm+1], numlong[lm+1]);
break;
}
else
ll = lm;
}
else
{
if(b<=numlong[lm+1])
{
num1 = b;
num2 = Math.min(numshort[sm+1], numlong[lm+1]);
break;
}
else
ls = lm+1;
}
}
lm = (ll+ls)/2;
sm = (sl+ss)/2;
}
//判断总数是奇数还是偶数
if(isEven == true)
answer = (num1+num2)/2.0;
else
answer = num1;
return answer;
}
}