# 引言

题目链接:https://leetcode.com/problems/median-of-two-sorted-arrays/description/

# 题目大意

给出两个升序的有序序列,找到两个序列合并后序列的中位数

Hint: You may assume nums1 and nums2 cannot be both empty.

官方希望复杂度为 O(log(m+n))

# 题解

对于一个长度为 n 的已排序数列 nums ,

若 n 为奇数,中位数为 nums[n/2]

若 n 为偶数,则中位数 (nums[n/2-1] + nums[n/2]) / 2

# 方法一

# 一句话题解

走一次归并排序逻辑 (先确定中位数下标过程中注意计算即可)

复杂度 O(m+n) , (明显和官方要求复杂度不是一个级别,目测后台数据比较水所以过了)

# 方法二

转换为寻找第 k 大的数据,类似于快排递归调整数据使得左边所有数据小于当前数据,右边大于等于当前数据这一步骤

详解

假设 nums1nums2 数组中元素个数都是大于 k/2 的,且从 0 开始编号,比较 a = nums1[k/2-1]b = nums2[k/2-1]

  1. 如果 a < b 那么 nums1[0]nums1[k/2-1]k/2 个数在合并后的有序数组中,一定在第 k 小的数左边 ———— nums1 数组中比 a 小的数一共是 k/2-1 个。 nums2 数组中比 a 小的数最多有 k/2-1 个。因而合并后比 a 小的数最多有 k/2-1+k/2-1 < k-2, 即 a 最多是第 k-1 小的数。因此 nums1 数组前 k/2 个数可以剔除了
  2. 如果 a > b 同理,剔除掉 nums2 数组前 k/2 个数
  3. 如果 a = b, a 即为所求

实际中若 nums1nums2 数组中元素个数不足 k/2 个的话,只需要前两者分割数据个数等于 k 即可

复杂度:每次剔除掉 k 一半个元素,即时间复杂度是 O(logk) , 对于此题, k=(m+n)/2 即复杂度 O(log(m+n))

# AC 代码

c++ 版本一 (归并排序法,也是博主 AC 方法,为了不使用额外空间代码写得很挫,不够优雅)

class Solution
{
  public:
    double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2)
    {
        int total = nums1.size() + nums2.size();
        if (0 == total)
        {
            return 0;
        }
        if (2 == total)
        {
            if (0 == nums1.size())
            {
                return (nums2[0] + nums2[1]) * 1.0 / 2;
            }
            if (0 == nums2.size())
            {
                return (nums1[0] + nums1[1]) * 1.0 / 2;
            }
            return (nums1[0] + nums2[0]) * 1.0 / 2;
        }
        double medianNumSum = 0;
        int medianNum1Index = ((total + 1) >> 1) - 1;
        int medianNum2Index = total >> 1;
        int i = 0;
        int j = 0;
        for (; i < nums1.size() && j < nums2.size();)
        {
            if (nums1[i] < nums2[j])
            {
                ++i;
            }
            else
            {
                ++j;
            }
            if (i + j == medianNum1Index && i < nums1.size() && j < nums2.size())
            {
                medianNumSum += (nums1[i] < nums2[j] ? nums1[i] : nums2[j]);
            }
            if (i + j == medianNum2Index && i < nums1.size() && j < nums2.size())
            {
                medianNumSum += (nums1[i] < nums2[j] ? nums1[i] : nums2[j]);
            }
        }
        if (i + j <= medianNum2Index && i < nums1.size())
        {
            for (; i < nums1.size(); ++i)
            {
                if (i + j == medianNum1Index)
                {
                    medianNumSum += nums1[i];
                }
                if (i + j == medianNum2Index)
                {
                    medianNumSum += nums1[i];
                }
            }
        }
        if (i + j <= medianNum2Index && j < nums2.size())
        {
            for (; j < nums2.size(); ++j)
            {
                if (i + j == medianNum1Index)
                {
                    medianNumSum += nums2[j];
                }
                if (i + j == medianNum2Index)
                {
                    medianNumSum += nums2[j];
                }
            }
        }
        return medianNumSum / 2;
    }
};

c++ 版本二

class Solution
{
  public:
    double findKthValue(vector<int> &nums1, vector<int> &nums2, int start1, int len1, int start2, int len2, int k)
    {
        if (len1 > len2)
        {
            return findKthValue(nums2, nums1, start2, len2, start1, len1, k);
        }
        if (0 == len1)
        {
            return nums2[start2 + k - 1];
        }
        if (1 == k)
        {
            return nums1[start1] < nums2[start2] ? nums1[start1] : nums2[start2];
        }
        int p = k / 2 < len1 ? k / 2 : len1;
        int q = k - p;
        if (nums1[start1 + p - 1] > nums2[start2 + q - 1])
        {
            return findKthValue(nums1, nums2, start1, len1, start2 + q, len2 - q, k - q);
        }
        else if (nums1[start1 + p - 1] < nums2[start2 + q - 1])
        {
            return findKthValue(nums1, nums2, start1 + p, len1 - p, start2, len2, k - p);
        }
        else
        {
            return nums1[start1 + p - 1];
        }
    }
    double findMedianSortedArrays(vector<int> &nums1, vector<int> &nums2)
    {
        int total = nums1.size() + nums2.size();
        if (total & 1)
        {
            return findKthValue(nums1, nums2, 0, nums1.size(), 0, nums2.size(), (total >> 1) + 1);
        }
        else
        {
            return (findKthValue(nums1, nums2, 0, nums1.size(), 0, nums2.size(), total >> 1) +
                findKthValue(nums1, nums2, 0, nums1.size(), 0, nums2.size(), (total >> 1) + 1)) / 2;
        }
    }
};

go 版本

func findKthValue(nums1, nums2 []int, start1, len1, start2, len2, k int) float64 {
	if len1 > len2 {
		return findKthValue(nums2, nums1, start2, len2, start1, len1, k)
	}
	if 0 == len1 {
		return float64(nums2[start2+k-1])
	}
	if 1 == k {
		return math.Min(float64(nums1[start1]), float64(nums2[start2]))
	}
	var p, q int
	if k/2 < len1 {
		p = k / 2
	} else {
		p = len1
	}
	q = k - p
	if nums1[start1+p-1] > nums2[start2+q-1] {
		return findKthValue(nums1, nums2, start1, len1, start2+q, len2-q, k-q)
	} else if nums1[start1+p-1] < nums2[start2+q-1] {
		return findKthValue(nums1, nums2, start1+p, len1-p, start2, len2, k-p)
	} else {
		return float64(nums1[start1+p-1])
	}
}
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
	lens := len(nums1) + len(nums2)
	if 1 == lens&1 {
		return findKthValue(nums1, nums2, 0, len(nums1), 0, len(nums2), lens/2+1)
	} else {
		return (findKthValue(nums1, nums2, 0, len(nums1), 0, len(nums2), lens/2) +
			findKthValue(nums1, nums2, 0, len(nums1), 0, len(nums2), lens/2+1)) / 2
	}
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

yx.zhang 微信支付

微信支付

yx.zhang 支付宝

支付宝