题目:tada:
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/
示例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
- -109 <= nums1[i], nums2[j] <= 109
解题
1. 先替换,后排序
思路
TIP先用nums2中的元素替换nums1中的 0,然后进行排序即可
代码
/**
* @param {number[]} nums1
* @param {number} m
* @param {number[]} nums2
* @param {number} n
* @return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function(nums1, m, nums2, n) {
//用nums2替换nums1中的0
nums1.splice(m,n,...nums2)
//升序排序
nums1.sort((a,b)=> a-b)
};
WARNING思路是好的,不过直接这样写,面试官大概会让你滚出去了…
但令人激动的是,这是目前为数不多,自己写的和官方题解几乎一样
2. 双指针
思路
TIP这题和之前做过的一道 合并有序链表 很像,所以很快就想到了双指针的解法
将两个数组看作队列,每次都从两个数组头部,取出比较小的数放进结果中
代码
/**
* @param {number[]} nums1
* @param {number} m
* @param {number[]} nums2
* @param {number} n
* @return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function(nums1, m, nums2, n) {
//定义两个指针
let p1 = 0, p2 = 0;
//创建长度为 m+n的数组res,并用0初始化
const res = new Array(m + n).fill(0);
var cur;
//如果两个指针都到底了,说明已经遍历完成
while (p1 < m || p2 < n) {
//若P1==m(p2==n),则说明nums1(nums2)已经遍历完成,则只需要将nums2(nums1)加到后面即可
if (p1 === m) {
cur = nums2[p2++];
} else if (p2 === n) {
cur = nums1[p1++];
} else if (nums1[p1] < nums2[p2]) {
cur = nums1[p1++];
} else {
cur = nums2[p2++];
}
res[p1 + p2 - 1] = cur;
}
//将结果复制到nums1中(题目要求直接在nums1上修改)
for (let i = 0; i != m + n; ++i) {
nums1[i] = res[i];
}
};
3. 逆向双指针
思路
TIP在上一个方法(正向双指针)中,之所以用一个临时变量cur,是为了避免nums1中的元素在取出来之前就被覆盖了
但根据题意,nums1的后半部分是空(0),直接覆盖不会影响结果,所以可以让指针从后往前遍历,每次取两者中的最大值放入nums1后半部分
代码
/**
* @param {number[]} nums1
* @param {number} m
* @param {number[]} nums2
* @param {number} n
* @return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function(nums1, m, nums2, n) {
//用来遍历的两个指针(从后往前)
let p1 = m - 1, p2 = n - 1;
//指向当前要插入的位置
let tail = m + n - 1;
var cur;
while (p1 >= 0 || p2 >= 0) {
if (p1 === -1) {
cur = nums2[p2--];
} else if (p2 === -1) {
cur = nums1[p1--];
} else if (nums1[p1] > nums2[p2]) {
cur = nums1[p1--];
} else {
cur = nums2[p2--];
}
nums1[tail--] = cur;
}
};