题目描述
给你两个按 非递减顺序 排列的整数数组 nums1
和 nums2
,另有两个整数 m
和 n
,分别表示 nums1
和 nums2
中的元素数目。
请你 合并 nums2
到 nums1
中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1
中。为了应对这种情况,nums1
的初始长度为 m + n
,其中前 m
个元素表示应合并的元素,后 n
个元素为 0
,应忽略。nums2
的长度为 n
。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 输出:[1,2,2,3,5,6] 解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0 输出:[1] 解释:需要合并 [1] 和 [] 。 合并结果是 [1] 。
示例 3:
输入:nums1 = [0], m = 0, nums2 = [1], n = 1 输出:[1] 解释:需要合并的数组是 [] 和 [1] 。 合并结果是 [1] 。 注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。
提示:
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-10^9 <= nums1[i], nums2[j] <= 10^9
NOTE:按 非递减顺序 排列的整数数组, 合并nums2
到 nums1
中,使合并后的数组同样按 非递减顺序 排列
解题思路:从后往前遍历两个数组,统一合并到nums1中
-
在
nums1
中,M
是有效元素的最后一个索引,初始化为m-1
;在nums2
中,N
是有效元素的最后一个索引,初始化为n-1
。同时,cur
是nums1
数组中待填充位置的最后一个索引,初始化为m+n-1
。 -
使用一个
while
循环,当M
和N
都大于或等于0时,即nums1
和nums2
都还有元素待合并时,比较两个数组当前位置的元素。 -
如果
nums1[M]
大于或等于nums2[N]
,那么将nums1[M]
复制到nums1[cur]
的位置,并将M
和cur
都递减。 -
如果
nums1[M]
小于nums2[N]
,那么将nums2[N]
复制到nums1[cur]
的位置,并将N
和cur
都递减。 -
如果
nums1
的元素都已经被检查过(M
小于0),但nums2
中还有元素(N
大于等于0),则继续一个while
循环,将nums2
的剩余元素复制到nums1
中,直到nums2
也没有元素为止。
完整代码:
#include <vector>
using namespace std;
class Solution {
public:
// 合并两个有序数组的函数
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
// M和N分别指向nums1和nums2数组中最后一个有效元素的索引
int M = m-1;
int N = n-1;
// cur指向合并后nums1数组的最后一个位置的索引
int cur = m+n -1;
// 当nums1和nums2都还有元素时,从后向前进行合并
while(M >= 0 && N >= 0) {
// 如果nums1当前元素大于等于nums2当前元素
if(nums1[M] >= nums2[N]) {
// 把nums1的当前元素复制到合并后数组的当前位置
nums1[cur--] = nums1[M--];
}
// 否则,如果nums1当前元素小于nums2当前元素
else if (nums1[M] < nums2[N]) {
// 把nums2的当前元素复制到合并后数组的当前位置
nums1[cur--] = nums2[N--];
}
}
// 如果nums2中还有剩余元素,直接复制到nums1的前面
// 这是必要的,因为当nums1的元素先被复制完时,可能会有nums2中的元素还没被复制
while (N >= 0) {
nums1[cur--] = nums2[N--];
}
// 注意:如果nums1中有剩余的元素,它们已经在合适的位置,无需额外操作
}
};
为什么后面要加上while(N>=0)
- 如果
nums2
中的所有值都大于nums1
中的值,那么nums1
中的值会首先放入其末尾,然后nums2
的值紧随其后。例如:
nums1 = [1, 2, 3, 0, 0, 0] nums2 = [4, 5, 6]
合并后:
nums1 = [1, 2, 3, 4, 5, 6]
这种情况下,nums1
中的值先移动,nums2
的值之后移动,不会有剩余。
nums1
中有较大的值在末尾,而nums2
有较小的值
nums1 = [4, 6, 8, 0, 0, 0] nums2 = [1, 2, 3]
合并后:
nums1 = [1, 2, 3, 4, 6, 8]
这种情况下,nums2
的值会被首先复制到nums1
的前三个位置。nums1
和nums2
都没有剩余的值。
nums1
的有效部分全部大于nums2
的值:
nums1 = [7, 8, 9, 0, 0, 0] nums2 = [1, 2, 3]
开始合并:
Step 1: nums1 = [7, 8, 9, 0, 0, 9]
Step 2: nums1 = [7, 8, 9, 0, 8, 9]
Step 3: nums1 = [7, 8, 9, 7, 8, 9]
现在nums1
中的有效值已经全部移动到了正确位置,nums2
中的值尚未移动:
Step 4: nums1 = [1, 8, 9, 7, 8, 9]
Step 5: nums1 = [1, 2, 9, 7, 8, 9]
Step 6: nums1 = [1, 2, 3, 7, 8, 9]
在这种情况下,nums1
中的值移动完成后,nums2
中的所有值会依次复制到nums1
的前端,因为它们比nums1
的有效部分的任何值都小。
因此,只有在nums1
的有效部分的值全部大于nums2
时,nums2
的值才可能剩余。
在这种情况下,算法保证了nums1
数组的前端空间足以容纳nums2
的所有值。