原题连接:Leetcode 88. Merge Sorted Array
You are given two integer arrays nums1
and nums2
, sorted in non-decreasing order, and two integers m
and n
, representing the number of elements in nums1
and nums2
respectively.
Merge nums1
and nums2
into a single array sorted in non-decreasing order.
The final sorted array should not be returned by the function, but instead be stored inside the array nums1
. To accommodate this, nums1
has a length of m
+ n
, where the first m elements denote the elements that should be merged, and the last n elements are set to 0 and should be ignored. nums2
has a length of n.
Example 1:
Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
Explanation: The arrays we are merging are [1,2,3] and [2,5,6].
The result of the merge is [1,2,2,3,5,6] with the underlined elements coming from nums1.
Example 2:
Input: nums1 = [1], m = 1, nums2 = [], n = 0
Output: [1]
Explanation: The arrays we are merging are [1] and [].
The result of the merge is [1].
Example 3:
Input: nums1 = [0], m = 0, nums2 = [1], n = 1
Output: [1]
Explanation: The arrays we are merging are [] and [1].
The result of the merge is [1].
Note that because m = 0, there are no elements in nums1. The 0 is only there to ensure the merge result can fit in nums1.
Constraints:
- nums1.length == m + n
- nums2.length == n
- 0 <= m, n <= 200
- 1 <= m + n <= 200
- -109 <= nums1[i], nums2[j] <= 109
Follow up: Can you come up with an algorithm that runs in O(m + n)
time?
方法一:合并 + 排序
思路:
合并成一个数组,sort()一下
c++代码:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
for(int i = 0; i < n; i++ ){
nums1[m + i] = nums2[i];
}
sort(nums1.begin(), nums1.end());
}
};
复杂度分析:
- 时间复杂度:O((m+n)log(m+n)),sort()的复杂度就是快排的复杂度
- 空间复杂度:O(log(m+n)),sort()的复杂度就是快排的复杂度
方法二:双指针
思路:
类似于归并排序的思想,将两个有序数组合并成一个有序数组。两个指针分别指向两个数组的开头,然后每次选择小的那个加入临时数组。
最后别忘了扫尾,当有一个数组没有遍历完时,要把它剩下的元素都加入临时数组。
最后将元素从临时数组拿回来
c++代码:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
vector<int> ans;
int i = 0, j = 0;
while(i <= m - 1 && j <= n - 1 ){
if(nums1[i] < nums2[j]) ans.emplace_back(nums1[i++]);
else ans.emplace_back(nums2[j++]);
}
// 扫尾
while(i <= m - 1) ans.emplace_back(nums1[i++]);
while(j <= n - 1) ans.emplace_back(nums2[j++]);
// 把ans的元素放回到nums1中
copy(ans.begin(), ans.end(), nums1.begin());
}
};
复杂度分析:
- 时间复杂度:O(m+n),需要遍历过每个元素
- 空间复杂度:O(m+n),临时数组的长度
方法三:逆向双指针
思路:
nums1的后半部分是空的,可以直接覆盖而不会影响结果。因此可以指针设置为从后向前遍历,每次取两者之中的较大者放进 nums 1的最后面。
这样还不需要一个临时数组
c++代码:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = m-1, j = n-1, k = m + n - 1;
while(i >= 0 && j >= 0){
if(nums1[i] > nums2[j]){
nums1[k--] = nums1[i--];
} else {
nums1[k--] = nums2[j--];
}
}
// 扫尾
while(i >= 0) nums1[k--] = nums1[i--];
while(j >= 0) nums1[k--] = nums2[j--];
}
};
复杂度分析:
- 时间复杂度:O(m+n),遍历两个数组
- 空间复杂度:O(1),数组原地修改