给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
public class Solution {
public double FindMedianSortedArrays(int[] nums1, int[] nums2)
{
int m = nums1.Length;
int n = nums2.Length;
int len = m + n;
var resultIndex = len / 2;
List<int> list = new List<int>(nums1);
list.AddRange(nums2);
list.Sort();
if (len % 2 == 0)
{
return (list[resultIndex - 1] + list[resultIndex]) / 2.0;
}
else
{
return list[resultIndex];
}
}
}
public class Solution {
public double FindMedianSortedArrays(int[] nums1, int[] nums2)
{
// nums1 与 nums2 有序添加到list中
List<int> list = new List<int>();
int i = 0, j = 0;
int m = nums1.Length;
int n = nums2.Length;
int len = m + n;
var resultIndex = len / 2;
while (i < m && j < n)
{
if (nums1[i] < nums2[j])
list.Add(nums1[i++]);
else
list.Add(nums2[j++]);
}
while (i < m) list.Add(nums1[i++]);
while (j < n) list.Add(nums2[j++]);
if (len % 2 == 0)
{
return (list[resultIndex - 1] + list[resultIndex]) / 2.0;
}
else
{
return list[resultIndex];
}
}
}
public class Solution {
public double FindMedianSortedArrays(int[] nums1, int[] nums2)
{
int i = 0, j = 0, m = nums1.Length, n = nums2.Length;
int len = m + n;
int resultIndex = len / 2;
int resultIndexPre = resultIndex - 1;
int result = 0, resultPre = 0;
bool isTwoResult = len % 2 == 0;
while (i < m || j < n)
{
var nums1ii = i < m ? nums1[i] : int.MaxValue;
var nums2jj = j < n ? nums2[j] : int.MaxValue;
if (nums1ii < nums2jj)
{
if (i + j == resultIndexPre) resultPre = nums1[i];
if (i + j == resultIndex)
{
result = nums1[i];
if (isTwoResult) return (resultPre + result) / 2.0;
else return result;
}
i++;
}
else
{
if (i + j == resultIndexPre) resultPre = nums2[j];
if (i + j == resultIndex)
{
result = nums2[j];
if (isTwoResult) return (resultPre + result) / 2.0;
else return result;
}
j++;
}
}
return 0;
}
}
方法三中,i 和 j 每次向右移动一位时,相当于去掉了一个不可能是中位数的值,也就是一个一个的排除。由于给定的两个数组是有序的,所以我们完全可以一半一半的排除。假设我们要找第 k 小数,我们每次循环可以安全的排除掉 k/2 个数。
public class Solution {
public double FindMedianSortedArrays(int[] nums1, int[] nums2)
{
int n = nums1.Length;
int m = nums2.Length;
int len = n + m;
int kPre = (len + 1) / 2;
int k = (len + 2) / 2;
if (len % 2 == 0)
return (GetKth(nums1, 0, n - 1, nums2, 0, m - 1, kPre) + GetKth(nums1, 0, n - 1, nums2, 0, m - 1, k)) * 0.5;
else
return GetKth(nums1, 0, n - 1, nums2, 0, m - 1, k);
}
private int GetKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k)
{
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
//让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1
if (len1 > len2) return GetKth(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 GetKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
else
return GetKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
}
}
public class Solution {
public double FindMedianSortedArrays(int[] A, int[] B)
{
int m = A.Length;
int n = B.Length;
//保证第一个数组是较短的
if (m > n) return FindMedianSortedArrays(B, A);
//正在寻找的范围为 [ A[iMin],A[iMax] ) , 左闭右开。二分查找取i=(iMin+iMax)/2
int iMin = 0, iMax = m;
while (iMin <= iMax)
{
int i = (iMin + iMax) / 2;
int j = (m + n + 1) / 2 - i;
if (j != 0 && i != m && B[j - 1] > A[i])
{ // i 需要增大
iMin = i + 1;
}
else if (i != 0 && j != n && A[i - 1] > B[j])
{ // i 需要减小
iMax = i - 1;
}
else
{ // 达到要求,并且将边界条件列出来单独考虑
int maxLeft = 0;
if (i == 0) { maxLeft = B[j - 1]; }
else if (j == 0) { maxLeft = A[i - 1]; }
else { maxLeft = Math.Max(A[i - 1], B[j - 1]); }
if ((m + n) % 2 == 1) { return maxLeft; } // 奇数的话不需要考虑右半部分
int minRight = 0;
if (i == m) { minRight = B[j]; }
else if (j == n) { minRight = A[i]; }
else { minRight = Math.Min(B[j], A[i]); }
return (maxLeft + minRight) / 2.0; //如果是偶数的话返回结果
}
}
return 0.0;
}
}