返回

探索 LeetCode 4:两个有序数组中的中位数

见解分享

在 LeetCode 的题库中,一道经典题目——"4. 两个有序数组中的中位数"一直备受算法爱好者的关注。这道题看似简单,却暗藏玄机,蕴含着求解数组中位数的巧妙方法。本文将深入剖析这道题目的多种解法,带你领略算法之美。

LeetCode 4:两个有序数组中的中位数

题目

给你两个有序整数数组 nums1 和 nums2,请你找出这两个有序数组的中位数。

示例:

  • 输入:nums1 = [1, 3], nums2 = [2]
  • 输出:2.00000
  • 解释:合并数组为 [1, 2, 3],中位数为 2.

解法:

2.1. 方法一:合并排序

由于两个数组都是排好序的,因此首先可以想到的思路就是利用归并排序把两个数组合并成一个有序的长数组,然后直接取出中位数即可。

def findMedianSortedArrays(nums1, nums2):
    # 合并两个数组
    merged_nums = sorted(nums1 + nums2)
    
    # 取中位数
    n = len(merged_nums)
    if n % 2 == 0:
        return (merged_nums[n // 2 - 1] + merged_nums[n // 2]) / 2
    else:
        return merged_nums[n // 2]

因为要遍历两个数组,所以时间复杂度为 O(m+n) ,而题目中要求算法的时间复杂度为 O(log(m+n)) ,因此应该是有更高效的算法,借助于二分查找,我们可以优化解法。

2.2. 方法二:二分查找

二分查找的本质是基于有序数组的性质,通过不断缩小搜索区间来快速定位目标元素。对于本题,我们可以将两个数组看成一个整体的有序数组,并使用二分查找来找到中位数。

具体步骤如下:

  1. 计算合并后数组的总长度 n = m + n
  2. 确定中位数索引 mid = n // 2
  3. 在两个数组中进行二分查找,找到满足 nums1[i] <= merged_nums[mid]nums2[j] >= merged_nums[mid] 的下标 ij ,其中 i + j = mid
  4. 如果 n 为偶数,则中位数为 (nums1[i] + nums2[j]) / 2 ;如果 n 为奇数,则中位数为 merged_nums[mid]
def findMedianSortedArrays(nums1, nums2):
    m, n = len(nums1), len(nums2)
    
    def get_kth_element(k):
        index1, index2 = 0, 0
        while index1 < m and index2 < n:
            if nums1[index1] < nums2[index2]:
                if index1 + index2 == k:
                    return nums1[index1]
                index1 += 1
            else:
                if index1 + index2 == k:
                    return nums2[index2]
                index2 += 1
        
        # 当一个数组已经全部遍历完
        if index1 == m:
            return nums2[k - index1]
        else:
            return nums1[k - index2]
    
    n = m + n
    if n % 2 == 0:
        return (get_kth_element(n // 2 - 1) + get_kth_element(n // 2)) / 2
    else:
        return get_kth_element(n // 2)

时间复杂度:O(log(m+n)) ,其中 mn 分别是两个数组的长度。

总结:

通过分析 LeetCode 4 题解,我们了解了合并排序和二分查找两种求解两个有序数组中位数的算法。其中,二分查找算法的时间复杂度更优,为 O(log(m+n)) 。掌握这些算法不仅可以帮助我们解决实际问题,更能加深我们对算法原理的理解和运用。