题目为
给定两个大小为 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)),但思路简单,代码如下
public double FindMedianSortedArrays(int[] nums1, int[] nums2)
{
if (nums1==null)
{
if (nums2.Length % 2==0)
{
return (nums2[nums2.Length / 2] + nums2[nums2.Length / 2 - 1]) / 2.000;
}
else
{
return nums2[nums2.Length / 2];
}
}
if (nums2 == null)
{
if (nums1.Length % 2 == 0)
{
return (nums1[nums1.Length / 2] + nums1[nums1.Length / 2 - 1]) / 2.000;
}
else
{
return nums1[nums1.Length / 2];
}
}
int allLength= nums2.Length + nums1.Length;
List<int> li = new List<int>();
int left = 0;
int right = 0;
for (int i = 0; i < allLength; i++)
{
if (left>nums1.Length-1)
{
li.Add(nums2[right]);
right++;
continue;
}
if (right > nums2.Length-1)
{
li.Add(nums1[left]);
left++;
continue;
}
if (nums1[left]<=nums2[right])
{
li.Add(nums1[left]);
left++;
}
else
{
li.Add(nums2[right]);
right++;
}
}
if (li.Count % 2 == 0)
{
return (li[li.Count / 2] + li[li.Count / 2 - 1]) / 2.000;
}
else
{
return li[li.Count / 2];
}
}
看了官方题解,二分法求解题解写的一头雾水,看了下面某位老哥的题解,才恍然大雾,附上老哥的题解思路
两个有序数组求中位数,问题一般化为,求两个有序数组的第k个数,当k = (m+n)/2时为原问题的解。
怎么求第k个数?分别求出第一个和第二个数组的第 k / 2个数 a 和 b,然后比较 a 和 b,当a < b ,说明第 k 个数位于 a数组的第 k / 2个数后半段,或者b数组的 第 k / 2 个数前半段,问题规模缩小了一半,然后递归处理就行。
时间复杂度是 O(log(m+n))
这位老哥的题解链接为题解链接
我根据题解写出的c#代码为
public double FindMedianSortedArrays(int[] nums1, int[] nums2)
{
if (nums1 == null)
{
if (nums2.Length % 2 == 0)
{
return (nums2[nums2.Length / 2] + nums2[nums2.Length / 2 - 1]) / 2.000;
}
else
{
return nums2[nums2.Length / 2];
}
}
if (nums2 == null)
{
if (nums1.Length % 2 == 0)
{
return (nums1[nums1.Length / 2] + nums1[nums1.Length / 2 - 1]) / 2.000;
}
else
{
return nums1[nums1.Length / 2];
}
}
int total = nums1.Length + nums2.Length;
if ((total & 1) == 1)
{
return GetNumMedian( 0, nums1, 0, nums2, total / 2 + 1);
}
return (GetNumMedian( 0, nums1, 0, nums2, total / 2) + GetNumMedian( 0, nums1, 0, nums2, total / 2 + 1)) / 2.0;
}
/// <summary>
/// 递归求解方法
/// </summary>
/// <param name="begin1">第一个数组当前开始数</param>
/// <param name="nums1">第一个数组</param>
/// <param name="begin2">第二个数组当前开始数</param>
/// <param name="nums2">第二个数组</param>
/// <param name="k">两个数组中所要寻找的第K个数字</param>
/// <returns></returns>
public double GetNumMedian(int begin1,int[] nums1,int begin2,int[] nums2,int k)
{
//当两个数组中某个数组已经到达末尾了,则中位数在另一个数组的(begin位+第k位)
if (begin1>=nums1.Length)
{
return nums2[begin2 + k - 1];
}
if (begin2 >= nums2.Length)
{
return nums1[begin1 + k - 1];
}
if (k==1)
{
return Math.Min(nums1[begin1], nums2[begin2]);
}
int aMax = int.MaxValue;
int bMax = int.MaxValue;
if (begin1 + k / 2 - 1 < nums1.Length)
aMax = nums1[begin1 + k / 2 - 1];
if (begin2 + k / 2 - 1 < nums2.Length)
bMax = nums2[begin2 + k / 2 - 1];
//如果a数组的第 k / 2 个数小于b数组的第 k / 2 个数,表示总的第 k 个数位于 a的第k / 2个数的后半段,或者是b的第 k / 2个数的前半段
//由于范围缩小了 k / 2 个数,此时总的第 k 个数实际上等于新的范围内的第 k - k / 2个数,依次递归
if (aMax < bMax)
return GetNumMedian(begin1 + k / 2, nums1, begin2, nums2, k - k / 2);
//否则相反
return GetNumMedian(begin1, nums1,begin2 + k / 2, nums2, k - k / 2);
}