【leetcode】Median of Two Sorted Arrays

高效解决两个已排序数组的中位数问题

https://leetcode.com/problems/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)).

题目原文在这里

这里,关注算法的递归写法,保持了num1和nums2的长短关系。

class Solution {
public:
    // n1 is always the shorter one
    // here k=1 means the first one
    int findKth(vector<int>& nums1, int st1, int ed1, vector<int>& nums2, int st2, int ed2, int k) {
        if(ed1-st1 > ed2-st2) {
            return findKth(nums2, st2, ed2, nums1, st1, ed1, k);
        }
        if(ed1 == st1) {
            return nums2[st2+k-1];
        }
        if(1 == k) {
            return min(nums1[st1], nums2[st2]);
        }
        
        int movea = min(k>>1, ed1-st1), moveb = k-movea;
        int i = st1+movea-1, j = st2+moveb-1;
        if(nums1[i] == nums2[j]) {
            return nums1[i];
        } else if(nums1[i] < nums2[j]){
            return findKth(nums1, st1+movea, ed1, nums2, st2, ed2, k-movea);
        } else {
            return findKth(nums1, st1, ed1, nums2, st2+moveb, ed2, k-moveb);
        }
    }
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size(), n = nums2.size();
        if(!m && !n) {
            return 0;
        }
        int l = m+n;
        if(l&1) {
            return findKth(nums1, 0, m, nums2, 0, n, (l+1)>>1);
        } else {
            return (findKth(nums1, 0, m, nums2, 0, n, l>>1) + findKth(nums1, 0, m, nums2, 0, n, (l>>1)+1))/2.0;
        }
    }
};


循环实现:

public class Solution {
	public double findMedianSortedArrays(int[] nums1, int[] nums2) {
	    if(null == nums1 || null == nums2) {
	        return findKth(nums1, nums2);
	    } 
		int lena = nums1.length, sta = 0;
		int lenb = nums2.length, stb = 0;
		// num is the number of first midian and numbers before it
		// for [1,2,3,4], num = 2; 
		int len = lena + lenb, num = (len+1)>>1;
		if(0 == len) {
			return 0.0;
		}
		
		while(sta < lena && stb < lenb) {
			int n = min(num>>1, lena-sta, lenb-stb);
			if(0 == n) {
				return pick(nums1, sta, nums2, stb, num, 1 == (len&0x1));
			}
			int va = nums1[sta+n-1], vb = nums2[stb+n-1];
			if(va == vb) {
				return pick(nums1, sta, nums2, stb, n, num, 1 == (len&0x1));
			} else if(va <= vb){
				sta = sta + n;
			} else {
				stb = stb + n;
			}
			num -= n;
		}
		if(sta < lena) {
			return pick(nums1, sta, num, 1 == (len&0x1));
		} else {
			return pick(nums2, stb, num, 1 == (len&0x1));
		}
	}
	
	// when n==0
	private double pick(int[] nums1, int sta, int[] nums2, int stb, int num, boolean odd) {
		if(odd) {
			return Math.min(nums1[sta], nums2[stb]);
		}
		return pick(nums1, sta, nums2, stb, num);
	}

	// pick when need two number 
	private double pick(int[] nums1, int ia, int[] nums2, int ib, int num) {
		if(0 < num) {
			return pickCheckNext(nums1, ia, nums2, ib);
		}
		return (nums1[ia] + nums2[ib])/2.0;
	}

	private double pickCheckNext(int[] nums1, int ia, int[] nums2, int ib) {
		int a=nums1[ia], b=nums2[ib];
		if(ia+1<nums1.length && b>nums1[ia+1]) {
			b = nums1[ia+1];
		}
		if(ib+1<nums2.length && a>nums2[ib+1]) {
			a = nums2[ib+1];
		}
		return (a+b)/2.0;
	}

	// when there are two number that are the same
	private double pick(int[] nums1, int sta, int[] nums2, int stb, int n, int num, boolean odd) {
		if(odd) {
			if(n+n == num) {
				return nums1[sta+n-1];
			}
			return Math.min(nums1[sta+n], nums2[stb+n]);
		} else {
			if(n+n == num) {
				return (nums1[sta+n-1]+Math.min(nums1[sta+n], nums2[stb+n]))/2.0;
			} else {
				return pick(nums1, sta+n, nums2, stb+n, num);
			}
		}
	}

	private double pick(int[] nums, int st, int num, boolean odd) {
		if(odd) {
			return nums[st+num-1];
		}
		return (nums[st+num-1] + nums[st+num])/2.0;
	}

	private double findKth(int[] a, int[] b) {
	    if(null == a && null == b) {
	        return 0;
	    }
	    if(null == a) {
	        return findKth(b);
	    } else {
	        return findKth(a);
	    }
	}
	
	private double findKth(int[] a) {
	    int len = a.length;
	    if(1 == len) {
	    	return a[0];
	    }
	    return (a[len>>1]+a[(len-1)>>1])/2.0;
	}

	private int min(int a, int b, int c) {
		if(a < b) {
			if(a < c) {
				return a;
			}
		} else {
			if(b < c) {
				return b;
			}
		}
		return c;
	}
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值