给两个有序的整数数组nums1和nums2,另有两个整数m和n,分别表示nums1和nums2中的元素数目
请合并nums2到nums1 中,使合并后的数组同样有序排列
注意:合并后的数组不应由函数返回,而是存储在数组nums1中,假设nums1的初始长度为m+n,其中前m个元素表示应合并的元素,后n个元素为0,nums2的长度为n
题目链接:合并两个有序数组
合并后同样以递增顺序排序
nums2合并到nums1后面
设计实现一个时间复杂度为O(m+n)的算法
时间复杂度为O((m+n)log(m+n))
空间复杂度为O(log(m+n))
p1指针复制nums1,p2指针遍历nums2
比较p1和p2指针的元素大小,按从小到大装进nums1,覆盖里面的函数
因为题目给出m为nums1的元素数量,nums1初始长度为m+n,实际元素只有m个,其余皆为0(n个,且应忽略)
受已排序条件影响,nums1数组中的元素已有序排列,且m个元素后使用0填充
实际可理解为nums1数组长度只有m,元素也只有m个
因此,p1在遍历复制的nums1过程中,无需考虑m个元素后存在p2与nums1中的m个元素后的0比较问题
但该思路缺点在于nums1和nums2都需要全部遍历才能结束
因此,时间复杂度为O(m+n),空间复杂度为O(m+n)
在思路二的基础上,取消临时数组,结合nums1初始长度为m+n的特点,使用双指针的方式一边逆向遍历nums2,一边将比较的元素添加到nums1中
设p1、p2为nums1、nums2最后一位元素
在遍历过程中的任意时刻:
nums1数组中有m-1-p1个元素被放入nums1的后半部分
nums2数组中有n-1-p2个元素被放入nums1的后半部分
在指针p1后面,nums1数组有m+n-p1-1个位置,则有
m + n - p1 - 1 ≥ m - 1 - p1 + n - p2 - 1
转换得:p2 ≥ -1
可证明p1后面永远足够容纳被插入的元素,不会产生nums1元素被覆盖的情况
nums1.length == m+n
nums2.length == n
m + n - p1 - 1 ≥ m - 1 - p1 + n - p2 - 1
# 思路一
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
nums1[m:] = nums2 # 切片到m元素之后的元素等于nums2的元素
nums1.sort() # 因为只是合并而已,仍需重新排序
# 思路二
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
sorted = [] # 建立一个临时变量
p1, p2 = 0, 0 # 从头开始遍历
while p1 < m or p2 < n: # 循环条件
if p1 == m: # nums1完全遍历时,只剩下nums2的元素未遍历
sorted.append(nums2[p2]) # 因为nums2为有序排序,则只需要不断添加nums2的元素即可
p2 += 1
elif p2 == n: # nums2完全遍历时,只剩下nums1的元素未遍历
sorted.append(nums1[p1]) # 因为nums1为有序排序,则只需要不断添加nums1的元素即可
p1 += 1
elif nums1[p1] < nums2[p2]: # 比较两个数组元素且nums2当前元素较大时
sorted.append(nums1[p1])
p1 += 1
else: # 比较两个数组元素且nums1当前元素较大时
sorted.append(nums2[p2])
p2 += 1
nums1[:] = sorted # sorted数组为所求数组,仅需将nums1等于sorted即可
# 思路三 官方代码
class Solution:
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 = m - 1, n - 1 # 设p1、p2为两个数组的最后一位有效元素
tail = m + n - 1 # 设tail为nums1最后一位元素
while p1 >= 0 or p2 >= 0: # 若条件不成立,则已遍历完成
if p1 == -1: # 当nums1数组全部遍历后
nums1[tail] = nums2[p2] # 仅需添加nums2的元素即可
p2 -= 1
elif p2 == -1: # 当nums2数组全部遍历后
nums1[tail] = nums1[p1] # 仅需添加nums1的元素即可
p1 -= 1
elif nums1[p1] > nums2[p2]: # nums1元素比nums2大时
nums1[tail] = nums1[p1]
p1 -= 1
else: # nums2元素比nums1大时
nums1[tail] = nums2[p2]
p2 -= 1
tail -= 1 # 触发条件后,tail逆向移动一位
若难以理解,可通过观看官方解说视频或执行以下代码逐步观察其代码逻辑
Python Tutor - Visualize Python, Java, JavaScript, C, C++, Ruby code execution
nums1 = [1,2,3,0,0,0]
nums2 = [2,5,6]
m = 3
n = 3
class Solution:
def plusOne(self, nums1,nums2):
p1, p2 = m - 1, n - 1
tail = m + n - 1
while p1 >= 0 or p2 >= 0: # 若条件不成立,则已遍历完成
if p1 == -1: # 当nums1数组全部遍历后
nums1[tail] = nums2[p2] # 仅需添加nums2的元素即可
p2 -= 1
elif p2 == -1: # 当nums2数组全部遍历后
nums1[tail] = nums1[p1] # 仅需添加nums1的元素即可
p1 -= 1
elif nums1[p1] > nums2[p2]: # nums1元素比nums2大时
nums1[tail] = nums1[p1]
p1 -= 1
else: # nums2元素比nums1大时
nums1[tail] = nums2[p2]
p2 -= 1
tail -= 1 # 触发条件后,tail逆向移动一位
return nums1
if __name__ == '__main__':
s = Solution()
S = s.plusOne(nums1,nums2)
print(S)
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
p1, p2 = m - 1, n - 1
tail = len(nums1) - 1
while p2 >= 0:
if p1 < 0 or nums1[p1] <= nums2[p2]:
nums1[tail] = nums2[p2]
p2 -= 1
else:
nums1[tail] = nums1[p1]
p1 -= 1
tail -= 1
思路二是正向双指针遍历,其中最后的nums[:] = sorted 而不是用nums1 = sorted 是因为nums1 = sorted是赋值,只改变形参,未改变实参的内存
思路二倒过来就是思路三了,利用已排序的条件和nums1初始长度为m + n,可减少临时变量的参数,直接修改nums1
【LeetCode】第66题:加一_inganxu-CSDN博客
【leecode】第53题:最大子序和_inganxu-CSDN博客
【leecode】第35题:搜索插入位置_inganxu-CSDN博客
【leecode】第27题:移除元素_inganxu-CSDN博客
【leecode】第1题:两数之和_inganxu-CSDN博客