(java)leetcode-4

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;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值