【leetcode】4. Median of Two Sorted Arrays
Problem Description
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Solutions
核心思想是要将中位数的定义转化为“Dividing a set into two equal length subsets, that one subset is always greater than the other.”
代码思路:
1. 第一种情况:两个list中有一个list为空;直接返回另一个list的中位数。
这里有两种方式可解决元素个数的奇/偶需分开讨论的问题:1) 利用向下取整的trick,见代码;2)利用list[m]和list[~m];虽然本质是一样的
2. 在算法中,根据‘two equal length subsets’的约束条件,我们只需loop查询两个list中的一个list即可,因为知道list1的cut的位置,根据等长约束,list2中cut的位置即可计算出。为了提高效率,使时间复杂度为 O(log(min(m,n)))(m, n分别为list1和list2的元素个数),不妨假设m<=n,不满足时调换两个list的位置即可
3. 两个list均非空的情况;寻找使‘left is always greater than right’约束条件成立的list1中cut的位置。这里分三种情况:1) l1 > r2, cut1 需左移;2) l2 > r1, cut1 需右移 3) l1 < r2 and l2 < r1,stop。
4. 有两种边缘特殊情况需考虑:1) max(nums1) < min(nums2) 2) min(nums1) > max(nums2);这里有一个非常巧妙的处理——在list两端分别添加MIN_VALUE和MAX_VALUE,便于将两种边缘特殊情况与普通情况一起处理
5. 两个list均非空的情况返回结果时,需分别考虑元素个数奇偶情况:偶数——返回 (max(left)+min(right))/2;奇数——因为是向下取整,所以右边会多一个元素,返回min(right)即可。
详细代码如下: Github link
# Runtime: 92 ms
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
MAX_VALUE = float('Inf')
MIN_VALUE = -float('Inf')
# 获取list元素个数
m = len(nums1)
n = len(nums2)
if m == 0: # nums1为空
# 这里有个小trick
# n为奇数时,nums2[int((n-1)/2)]和nums2[int(n/2)]是同一个数,即中位数
# n为偶数时,nums2[int((n-1)/2)]和nums2[int(n/2)]分别为最中间的两个数
# 这是因为int(n/2)是向下取整,int(1.5) == 1
# 向下取整的功能也可以通过 '//' 运算符实现
return float((nums2[int((n - 1) / 2)] + nums2[int(n / 2)]) / 2)
if n == 0: # 同理,nums2为空
return float((nums1[(m - 1) // 2] + nums1[m // 2]) / 2)
if m > n: # 为了提高效率,保证进行loop遍历的是较短的list
return Solution.findMedianSortedArrays(self, nums2, nums1)
# 两个list均非空的情况
# 割的范围初始化
size = m + n
CutL = 0
CutR = m
cut1 = m // 2 # 短list的割的位置
while cut1 <= m: # 寻找满足 l1<r2 and l2<r1的割的位置
cut1 = (CutR - CutL) // 2 + CutL # 短list的割的位置
cut2 = size // 2 - cut1 # 长list的割的位置
# 在list两端分别添加MIN_VALUE和MAX_VALUE,便于将两种边缘特殊情况与普通情况一起处理
# 两种边缘特殊情况即:1. max(nums1)<min(nums2) 2. min(nums1)>max(nums2)
# 获取割两边的值
l1 = MIN_VALUE if cut1 == 0 else nums1[cut1 - 1] # 相当于Java中的三目运算符'?:',只有当min(nums1)>max(nums2)时,l1取值MIN_VALUE
l2 = MIN_VALUE if cut2 == 0 else nums2[cut2 - 1] # 同上,其实取不到特殊情况?
r1 = MAX_VALUE if cut1 == m else nums1[cut1] # 只有当max(nums1)<min(nums2时,l1取值MIX_VALUE
r2 = MAX_VALUE if cut2 == n else nums2[cut2]
if l1 > r2: # l1>r2, cut1需左移
CutR = cut1 - 1
elif l2 > r1: # l2>r1, cut1需右移
CutL = cut1 + 1
else: # 满足 l1<r2 and l2<r1
if size % 2 == 0: # 两个list的元素总个数为偶数
l = l1 if l1 > l2 else l2
r = r1 if r1 < r2 else r2
return float((l + r) / 2)
else: # 两个list的元素总个数为奇数
r = r1 if r1 < r2 else r2
return float(r)
这是符合时间复杂度要求O(log (m+n))的一种解法,实际时间复杂度为O(log(min(m,n)))
另外有一种时间复杂度为O(nlogn)的解法(考虑sort时间复杂度,虽然这两种解法都可以被accepted),代码简短,各取所需
# sample 88 ms submission
# 我提交这种方案仍然是 Runtime: 92 ms
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
num = nums1 + nums2
num = sorted(num)
l = len(num)
if l % 2 == 0:
return (num[l//2-1]+num[l//2])/2*1.0
else:
return num[l//2]*1.0
# sample 92 ms submission
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
nums1 += nums2
nums1.sort()
m = int(len(nums1) / 2)
return (nums1[m] + nums1[~m]) / 2
推荐阅读
-
【LeetCode】Two Sum & Two Sum II - Input array is sorted & Two Sum IV - Input is a BST
-
LeetCode 21. 合并两个有序链表 Merge Two Sorted Lists
-
[LeetCode]Merge Two Sorted Lists(Python)
-
【LeetCode】4. Median of Two Sorted Arrays
-
1.Merge Two Sorted Arrays. py/合并排序有序数列
-
LeetCode 4. 两个排序数组的中位数 Median of Two Sorted Arrays
-
算法练习(3):Median of Two Sorted Arrays
-
LeetCode算法系列:4、Median of Two Sorted Arrays
-
4. Median of Two Sorted Arrays
-
4. Median of Two Sorted Arrays