寻找两个有序数组的中位数

题目描述

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

示例

示例一:

nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0

示例二:

nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5

题解

中位数的意义:将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。
分别将nums1和nums2划分为两个子集,划分位置定义为i和j,将nums1Left和nums2Left合并称为Left,将nums1Right和nums2Right合并称为right。要确保left中的元素小于right中的元素,即nums1Left[i-1]要小于nums2Right[j],nums2Left[j-1]要小于nums1right[i]。

如果上述条件成立则证明我们找到了目标对象;
起初设定i=nums1.length/2;j=(nums1.length+nums2.length+1)/2-i;(前提假设m小于等于n,因为j不能为负值)

如果nums1Left[i-1]>nums2Right[j],则证明i太大了,应该减小,因为i越小,nums1Left[i-1]就会减小,j会增大,则nums2Right[j]也会增大。
如果nums2Left[j-1]>nums1Right[i],则证明i太小了,应该增大,因为i越大,nums1Right[i]就会增大,j则会减小,nums1Left[j-1]就会减小。

	 double median=0.0;
		 int m=nums1.length,n=nums2.length;
		 if(m>n) {
			 int []temp=nums1;nums1=nums2;nums2=temp;
			 int tmp=m;m=n;n=tmp;
		 }
		 int imin=0,imax=m,halfLen=(m+n+1)/2;
		 while(imin<=imax) {
			 int i=(imin+imax)/2;
			 int j=halfLen-i;
			 if(i>imin&&nums1[i-1]>nums2[j])// i too big
				 imax=i-1;
			 else if(i<imax&&nums2[j-1]>nums1[i])//i too small
				 imin=i+1;
			 else {
				 double maxLeft=0,minRight=0;
				 if(i==0) 
					 maxLeft=nums2[j-1];
				 else if(j==0) 
					 maxLeft=nums1[i-1];
				 else 
					 maxLeft=Math.max(nums1[i-1], nums2[j-1]);
				if((m+n)%2!=0)
					return maxLeft;
				if(i==m)
					minRight=nums2[j];
				else if(j==n)
					minRight=nums1[i];
				else 
					minRight=Math.min(nums1[i], nums2[j]);
				median=(maxLeft+minRight)/2.0;
				return median;
				}
			 }
		 return median;
	 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 请找出这两个有序数组中位数,并且要求算法的时间复杂度为 O(log(m+n))。 你可以假设 nums1 和 nums2 不会同时为空。 示例 1: nums1 = [1, 3] nums2 = [2] 则中位数是 2.0 示例 2: nums1 = [1, 2] nums2 = [3, 4] 则中位数是 (2 + 3)/2 = 2.5 解题思路: 题目要求时间复杂度为 O(log(m+n)),很明显是要用到二分查找的思想。 首先,我们需要确定中位数的位置。对于两个长度分别为 m 和 n 的有序数组,它们的中位数位置为 (m+n+1)/2 和 (m+n+2)/2,因为当 m+n 为奇数时,这两个位置的值是相同的;当 m+n 为偶数时,这两个位置的值分别为中间两个数。 然后,我们需要在两个数组中分别找到第 k/2 个数(k 为中位数位置),比较它们的大小,如果 nums1[k/2-1] < nums2[k/2-1],则说明中位数位于 nums1 的右半部分和 nums2 的左半部分之间,此时可以舍弃 nums1 的左半部分,将 k 减去 nums1 的左半部分的长度,继续在 nums1 的右半部分和 nums2 的左半部分中寻找第 k/2 个数;反之,如果 nums1[k/2-1] >= nums2[k/2-1],则说明中位数位于 nums1 的左半部分和 nums2 的右半部分之间,此时可以舍弃 nums2 的左半部分,将 k 减去 nums2 的左半部分的长度,继续在 nums1 的左半部分和 nums2 的右半部分中寻找第 k/2 个数。 当 k=1 时,中位数两个数组中的最小值。 Java代码实现: class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { int m = nums1.length; int n = nums2.length; int k = (m + n + 1) / 2; double median = findKth(nums1, 0, m - 1, nums2, 0, n - 1, k); if ((m + n) % 2 == 0) { int k2 = k + 1; double median2 = findKth(nums1, 0, m - 1, nums2, 0, n - 1, k2); median = (median + median2) / 2; } return median; } private double findKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) { int len1 = end1 - start1 + 1; int len2 = end2 - start2 + 1; if (len1 > len2) { return findKth(nums2, start2, end2, nums1, start1, end1, k); } if (len1 == 0) { return nums2[start2 + k - 1]; } if (k == 1) { return Math.min(nums1[start1], nums2[start2]); } int i = start1 + Math.min(len1, k / 2) - 1; int j = start2 + Math.min(len2, k / 2) - 1; if (nums1[i] > nums2[j]) { return findKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1)); } else { return findKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1)); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值