【leetcode】4. 寻找两个有序数组的中位数
题目描述
给定两个大小为 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
思路1
直接将两个数组执行归并排序合并为一个数组nums,然后便可以得到中位数。
时间复杂度:o(n)o(n)o(n)
空间复杂度:o(n)o(n)o(n)
代码
def findMedianSortedArrays(self, nums1, nums2): """ 先进行归并排序,然后直接取中位数 :param nums1: :param nums2: :return: """ nums = [] i = j = 0 while i < len(nums1): n1 = nums1[i] while j < len(nums2): n2 = nums2[j] if n2 < n1: nums.append(n2) j += 1 else: break nums.append(n1) i += 1 if j < len(nums2): nums.extend(nums2[j:]) len_nums = len(nums) if len_nums % 2 == 1: return nums[(len_nums - 1) // 2] else: return float(nums[len_nums // 2 - 1] + nums[len_nums // 2]) / 2
思路2
这种方法比思路1要复杂很多,需要有两个定理支持:
定理一:从有序序列seq1seq1seq1的首尾区域(不包含中值)内随机剥离等数目的数值得到新的有序序列seq2seq2seq2,seq1seq1seq1与seq2seq2seq2的中位数相同。
定理二:对于有序序列seq1seq1seq1、seq2seq2seq2及其中位数med1med1med1、med2med2med2,当从中位数更小的序列的左侧、中位数更大的序列的右侧删除等数目的元素后,新得到序列seq1′seq1'seq1′和seq2′seq2'seq2′,seq1seq1seq1合并seq2seq2seq2的中位数与seq1′seq1'seq1′合并seq2′seq2'seq2′的中位数相同(基于定理一)。而当med1med1med1与med2med2med2相同时,med1med1med1即为合并后的中位数。
基于上面两个定理,算法如下所述:
- 从nums1和nums2中分别算得中位数m1,m2
- 用两个中位数进行比较,取中间的两段——即较大中位数所在数组的左段,较小中位数所在数组的右段。 左右两段形成时,需要从原本数组中剥离等数量的数值。
- 从新的两端数组中寻找中位数,形成递归
- 当其中一个数组长度较小时,直接快速得到中位数
时间复杂度:o(n)o(n)o(n) 但理论上上比思路一要小
空间复杂度:o(0)o(0)o(0)
代码
def find_median(self, nums): len_nums = len(nums) if len_nums % 2 == 0: # 偶数返回中间两值的均值,同时index为右边 return (nums[len_nums >> 1] + nums[(len_nums >> 1) - 1]) / 2., len_nums >> 1 else: return nums[((len_nums + 1) >> 1) - 1], ((len_nums + 1) >> 1) - 1 def findMedianSortedArrays(self, nums1, nums2): len_nums1 = len(nums1) len_nums2 = len(nums2) # 递归终止,找到了中位数 if len_nums1 == 0: # 其中一个数组为空 median, _ = self.find_median(nums2) return median if len_nums2 == 0: median, _ = self.find_median(nums1) return median if len_nums1 <= 2 or len_nums2 <= 2: # 其中一个数组长度不足 nums = [] nums.extend(nums1) nums.extend(nums2) nums.sort() median, _ = self.find_median(nums) return median median1, med_idx1 = self.find_median(nums1) median2, med_idx2 = self.find_median(nums2) if median1 == median2: # 两数组的中位数相等,直接返回 return median1 else: # 不等进入递归 if median1 > median2: # 取nums1的左侧,nums2的右侧 if len_nums2 % 2 == 0: # 偏移偶数数组nums2的指针,从而子数组能够包含中间两位 med_idx2 -= 1 strip_len = min(len(nums1) - med_idx1 - 1, med_idx2) # 这里需要等额剥离相同长度。依据原理:从有序序列的首尾区域(不包含中值)内随机剥离等量的数值,最终的中位数不变 new_num1 = nums1[0:len(nums1) - strip_len] new_num2 = nums2[-(len(nums2) - strip_len):] else: if len_nums1 % 2 == 0: med_idx1 -= 1 strip_len = min(len(nums2) - med_idx2 - 1, med_idx1) new_num2 = nums2[0:len(nums2) - strip_len] new_num1 = nums1[-(len(nums1) - strip_len):] return self.findMedianSortedArrays(new_num1, new_num2)
参考
- [1] leetcode原题
- [2] 详尽源码
- [leetcode] Median of Two Sorted Arrays 寻找两个有序数组的中位数
- 寻找两个有序数组的中位数(LeetCode)
- LeetCode第4题--寻找两个有序数组的中位数
- 【LeetCode】第四题:寻找两个有序数组的中位数
- LeetCode刷题-寻找两个有序数组的中位数
- LeetCode4.python实现:寻找两个有序数组中的中位数问题☆☆☆
- LeetCode题解(python)-4. 寻找两个有序数组的中位数
- [leetcode 4] 寻找两个有序数组的中位数 python
- 基础算法之寻找两个有序数组的中位数(LeetCode-4)
- leetcode 寻找两个有序数组的中位数
- leetcode 寻找两个有序数组的中位数 median of two sorted arrays
- LeetCode-4 :寻找两个有序数组的中位数 ★★★★★
- leetcode之数组类之数组的旋转与分治类-----OJ 189/33/81/153/154 数组旋转 旋转数组搜索 88 有序数组合并 4 两个有序数组寻找第K个元素/中位数 35 寻找插入位置
- Leetcode-寻找两个有序数组的中位数
- LeetCode--4. 寻找两个有序数组的中位数(Median of Two Sorted Arrays)
- Leetcode(C++)——4. 寻找两个有序数组的中位数
- [LeetCode]4. 寻找两个有序数组的中位数/C++
- leetcode 4. 寻找两个有序数组的中位数(Java版)
- @LeetCode寻找两个有序数组的中位数--Median of Two Sorted Arrays[C++]
- [LeetCode] 求两个有序数组的中位数