一.问题描述
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.
Note:
- The number of elements initialized in nums1 and nums2 are m and n respectively.
- You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2.
Example:
Input: nums1 = [1,2,3,0,0,0], m = 3 nums2 = [2,5,6], n = 3 Output: [1,2,2,3,5,6]
二.解题思路
题目本身不难,但是要求in_place操作,
如果要求常数内存O(1),就稍微复杂一点。
介绍俩O(1)内存方法。
方法一:
考虑如果我们可以新开内存怎么做?
我们新开一个数组(大小m+n),然后比较nums1第一个元素和nums2第一个元素谁小,谁更小就丢新开的数组里面,然后继续比较。
然而问题是不开新内存,注意题目说的nums1大小至少m+n,就会想是否可以这样用?
但是nums1本身的元素已经占在前面了,我们不能用,既然后面可以用,何不反其道而行?
对于上面假设不要求常数内存的例子,我们也可以比较nums1和nums2的最后一个元素,谁大就放在新开内存的最后面,慢慢迭代。
这样子我们就可以利用本题nums1的特性,把数丢后面,也不会影响nums1本身的数。
有人可能会问是否会影响nums1本身的数?
思考什么时候会影响nums1本身的数,假设nums1[i]被影响,影响是指nums1[i]这个数还没被拿去比较,就已经被nums2某个数占了,这说明nums2的大小至少得需要m+n-i+1(假设nums1[i]~nums[m+n-1]全被nums2的数占了,虽然可能有部分被nums1本身值占用,但是这部分不影响)。i最大是m,所以nums2的大小至少是m+n-m+1=n+1,然而nums2大小是n,因此不可能。
nums1[i]不可能会被nums1本身的数给影响。因为nums1的数被移动末尾,并不影响nums1的值在nums1所占的空间大小。
比如说nums1[10]被移动到nums1[100],虽然占用了第100个位置,但是释放了第10个位置。所以不会影响nums1的10之前数的数的处理。只有nums2的数加进nums1才可能就影响nums2本身的值,因为占用了新的空间。
时间复杂度O(m+n-1),空间复杂度O(1)
方法二:
死方法,从左开始处理。
比较两个数组的开头,nums2的数小,就插进nums1里面,然后将nums1之后的值全部右移1格。
小小的一个优化就是,不要出现一个nums2的值小于nums1的值就插入一次,判断nums2连续的几个值是不是都小于nums1的那个值,如果是的话就一次性插入nums2这几个小于的值进nums1,毕竟插入操作很花时间。
详细见代码。
时间复杂度O(m*m),空间复杂度O(1);
更多leetcode算法题解法: 专栏 leetcode算法从零到结束 或者 leetcode 解题目录 Python3 一步一步持续更新~
三.源码
方法一
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.
"""
# 18
total_len=m+n-1
for i in range(total_len,-1,-1):
if n<1:break
if m<1:
nums1[:n]=nums2[:n]
break
if nums1[m-1]>nums2[n-1]:
nums1[i]=nums1[m-1]
m-=1
else:
nums1[i]=nums2[n-1]
n-=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.
"""
# 18
i,j=0,0
len_nums1=len(nums1)
while i<m:
jstart=j
while j<n:
if nums2[j]<nums1[i]:j+=1
else: break
nums1[i+j-jstart:]=nums1[i:len_nums1-j+jstart]
nums1[i:i+j-jstart]=nums2[jstart:j]
m+=j-jstart
i+=1
nums1[m:m+n-j]=nums2[j:]