1:题目描述
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
2:解题方法
题目中给出的数组方式:nums1中本身有效的数字是前m位,nums1的长度为m+n,因此正好可以放下nums1[0:m]+nums2[0:n]。
合并两个有序数组,可以想到归并排序。归并排序是把两个有序的数组合并,放到另外一个数组中。空间复杂度是O(M+N)的。
因为最终的结果是要按非递减顺序排序,因此需要比较nums1[0:m]和nums2[0:n]中数字的大小。
有两种思路:
思路一:如果两个数组从开头向结尾(数字从小到大)进行比较,那么每次比较之后的数字放到nums1中的前面,则需要把nums1中第k个位置(与nums2中进行比较的位置)后面的元素向后移动,这样移动次数较多。
思路二:如果两个数组从结尾向开头(数字从大到小)进行比较,那么每次把比较之后的数字放置到nums1中的后面,由于后面的数字本身就是提供出来的多余的位置,都是0,因此不需要对nums1进行移动。
显然思路二更好。
从后向前进行比较
1:当m>0并且n>0时,从后向前比较nums1[m-1]和muns2[n-1]:
如果是nums1[m-1]大,则把nums1[m-1]放到nums1中的m+n-1的位置,并让m-=1,
如果是nums2[n-1]大,则把nums2[n-1]放到nums1中的m+n-1的位置,并让n-=1。
2:当上面遍历条件结束的时候,此时m和n至少有一个为0.
当m==0时,说明nums1中的数字已经遍历完了,此时nums2中可能还剩元素,需要把nums2中还剩余的元素复制到nums1的头部,
当n==0时,说明nums2中的数字已经遍历完了,此时nums1中可能还剩元素,由于剩余的元素一定是nums1和nums2中最小的元素,所以不用移动位置,直接留在原地就行。
以nums1 = [2,3,5,0,0],m = 3,nums2 = [1,6],n = 0为例,绿色是正在比较的元素,红色是刚刚放置过的元素。
具体思路展示:
代码展示:
class Solution:
def merge(self, nums1, m, nums2, n):
k = m+n-1 #数组nums1最后一个元素的位置
while m>0 and n>0:
if nums1[m-1]>nums2[n-1]:
nums1[k] = nums1[m-1]
m -= 1
else:
nums1[k] = nums2[n-1]
n -= 1
k -= 1
# 当m!=0,n=0,说明nums2已经遍历完了,nums1还有剩余,因为剩余的元素本身就是最小的,所以不用挪动位置
# 当m=0,n!=0,说明nums1已经遍历完了,nums2还有剩余,并且nums2剩余的都比nums1最小的还小,所以直接放到最前面
nums1[:n] = nums2[:n]
return nums1
if __name__ == '__main__':
nums1 = [2,3,5,0,0]
m = 3
nums2 = [1,6]
n = 2
print(Solution().merge(nums1,m,nums2,n))