一.問題描述
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:]