一、前言
leetcode做的一道比较难的题,主要是算法有关的知识掌握不牢。
题目如下:
题目里默认有两个数组均为从小到大排列,如果不放心可以加一段比较两个元素然后逆序的过程后再运算。
二、思路
寻找两个有序数组的中位数,可以转变为求两个有序数组中第k小的数的问题:
1、当两个数组中元素个数为奇数n时,中位数即为第(n-1)/2小的数。
2、当两个数组中元素个数为偶数n时,中位数即为第n/2小的数和第(n/2)-1小的数的平均数。
求两个有序数组第k小的数求解思路有两种:
法1、假设两个数组第一个数字分别为m、n,比较哪个小就去掉哪个,一直找到第k个数,但时间复杂度为O(k),不太符合题目要求。
法2、二分法。
因为要求第k小,所以需要找一个边界,左边都比右边的数小,且左边有k个元素。左边最大的元素就是我们需要的数。时间复杂度为O(log(m+n))。
思路学习于这篇文章,笔者手写的代码。
def gets(nums):
l=len(nums)
if l%2==0:
return ((nums[l//2-1]+nums[l//2])/2)
else:
return (nums[(l-1)//2])
def find(nums1,nums2,k):
l1,l2=len(nums1),len(nums2)
#k恰好处于两端,可直接返回
if k==l1+l2:
return max(nums1[l1-1],nums2[l2-1])
elif k==1:
return min(nums1[0],nums2[0])
#两个数组没有重叠,可直接返回
if nums1[0]>=nums2[l2-1]:
if l2>=k:
return nums2[k-1]
else:
return nums1[k-l2-1]
elif nums2[0]>=nums1[l1-1]:
if l1>=k:
return nums1[k-1]
else:
return nums2[k-l1-1]
#两个数组有重叠,获取两个边界c1、c2的初始值
if l1<l2:
c1=l1//2
c2=k-c1
else:
c2=l2//2
c1=k-c2
if c1==0:
c1+=1
c2-=1
elif c2==0:
c1-=1
c2+=1
while(1):
#左右边界判断
if c1==0:
return nums2[k-1]
elif c2==0 :
return nums1[k-1]
if c1==l1:
if nums1[c1-1]>nums2[c2]:
c1-=1
c2+=1
continue
else:
return max(nums1[c1-1],nums2[c2-1])
elif c2==l2:
if nums2[c2-1]>nums1[c1]:
c2-=1
c1+=1
continue
else:
return max(nums1[c1-1],nums2[c2-1])
#核心边界移动代码
if nums1[c1-1]<=nums2[c2] and nums2[c2-1]<=nums1[c1]:
return max(nums1[c1-1],nums2[c2-1])
elif nums1[c1-1]>nums2[c2]:
c1-=1
c2+=1
elif nums2[c2-1]>nums1[c1]:
c1+=1
c2-=1
continue
return ;
class Solution:
def findMedianSortedArrays(self, nums1, nums2) :
l1,l2=len(nums1),len(nums2)
if l1==0:
return 0.0+gets(nums2)
elif l2==0:
return 0.0+gets(nums1)
if (l1+l2)%2==0:
x,y=(l1+l2)//2,(l1+l2)//2+1
return 0.0+(find(nums1[0:x],nums2[0:x],x)+find(nums1[0:y],nums2[0:y],y))/2
else:
z=(l1+l2-1)//2+1
return 0.0+find(nums1[0:z],nums2[0:z],z)
if __name__=="__main__":
nums1,nums2=[3,4],[1,2]
a=Solution()
ret=a.findMedianSortedArrays(nums1, nums2)
print(ret)