方法一 合并+排序
合并,排序,end
简单,只需一行代码,但是时间复杂度高
python代码
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
nums1[:] = sorted(nums1[:m] + nums2)
时间复杂度O((m+n)log(m+n))
空间复杂度O(1)
方法二 双指针
思路
有一个典型的双指针问题,就是将两个有序数组合并为一个有序数组,与此题几乎一致,只不过此题又多给了一些条件和限制:
- 两个数组中的有效元素个数为m和n,第一个数组的长度为m+n,以及需要将最终结果存储在第一个数组中。
我们大可以按照原来的思路做,采用双指针方法,将两个数组合并为一个新数组,再把新数组复制给数组1。在这里可以用一些技巧来把空间复杂度降为O(1),也就是不用开辟新数组。
方法是:把数组1的前m个有效元素移动到最后面,然后再对数组1和数组2采用双指针方法进行合并
举例:nums1 = [1,2,3,4,0,0]; nums2 = [1,2]; m=4; n=2
- 先将
nums1
的前m个有效元素移动到后面,nums1
变为[1,2,1,2,3,4]
- 采用双指针算法进行合并,
nums1
的指针p1=n
,也就是指向第三个元素1,nums2
的指针p2=0
- 然后采用经典的双指针算法进行合并排序到nums1就可以了。
python代码
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
nums1[n:] = nums1[:m] # 将nums1的前m个元素复制到后面
p1, p2 = n, 0 # 定义双指针
p = 0
# 经典的双指针算法
while p1 < m+n and p2 < n:
if nums1[p1] < nums2[p2]:
nums1[p] = nums1[p1]
p1 += 1
else:
nums1[p] = nums2[p2]
p2 += 1
p += 1
while p1 < m+n:
nums1[p] = nums1[p1]
p += 1
p1 += 1
while p2 < n:
nums1[p] = nums2[p2]
p += 1
p2 += 1
因为是合并到nums1中,所以nums2中的元素都复制到nums1中之后,就完成任务了,所以第二个while循环其实可以去掉
时间复杂度O(m+n)
空间复杂度O(1)
方法三 双指针+从后向前
思路
与方法二相比,更加快,这次我们改进双指针算法,把指针设置为m-1, n-1
,采取从后向前,由大到小的排列顺序进行,这样就省去了方法二中复制数组1的时间
python代码
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
p1, p2, p = m-1, n-1, m+n-1
while p1 >= 0 and p2 >= 0:
if nums1[p1] > nums2[p2]:
nums1[p] = nums1[p1]
p1 -= 1
else:
nums1[p] = nums2[p2]
p2 -= 1
p -= 1
while p2 >= 0:
nums1[p] = nums2[p2]
p2 -= 1
p -= 1
利用Python特性将最后一个循环去掉,局部代码如下
while p1 >= 0 and p2 >= 0:
if nums1[p1] > nums2[p2]:
nums1[p] = nums1[p1]
p1 -= 1
else:
nums1[p] = nums2[p2]
p2 -= 1
p -= 1
nums1[:p2+1] = nums2[:p2+1]