这是我参与更文挑战的第3天,活动详情查看: 更文挑战
题干:
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。
示例:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
思路1:头部双指针
这一想法实际上就是分别在在nums1和nums2的头部插入指针,然后再使用一个新的数组,两个指针分别比较,将比较结果的较小值插入新数组中,指针后移,当我们nums1和num2某一个数组的指针到达目标点后就不不用再往后走,然后将第二个数组的值依次插入即可(因为我们两个数组都是有序的,一个数组的指针走完后,说明第二个数组的剩余值就可以直接接在本数组的尾部)。但是最后还需要我们将得到的新数组赋值给nums1,这种方式效率较差(不推荐)。
执行用时:104 ms, 在所有 JavaScript 提交中击败了9.54%的用户
内存消耗:37.9 MB, 在所有 JavaScript 提交中击败了68.03%的用户
function merge3(nums1, m, nums2, n) {
let newarr = [];
let begin1 = 0;
let begin2 = 0;
var tt = 0
while (begin1 < m || begin2 < n) {
if (begin1 == m) {
newarr.push(nums2[begin2++])
} else if (begin2 == n) {
newarr.push(nums1[begin1++])
} else if (nums1[begin1] > nums2[begin2]) {
newarr.push(nums2[begin2++])
} else {
newarr.push(nums1[begin1++])
}
}
for (let index = 0; index < newarr.length; index++) {
nums1[index] = newarr[index]
}
return nums1
}
思路二:尾部双指针(推荐)
为什么要在尾部进行指针操作呢?因为我们的数组是有序的,上一个操作我们直接new了一个新的数组,这违背了题意。我们如何利用nums1给我们留给nums2的坑位呢?
我认为我们需要设置三个指针,分别是begin1,begin2,addend,含义分别是nums1,nums2的实际数组的尾部值,addend值是nums1实际数组的尾部。
因此我们向前开始遍历:这里说明当我们的begin2游标值<0时就说明了我们已经结束了
-
如果num2的第一个值大于num1的第二个值,则将num2的值放入addend当前的位置,接着哪个值变动了,就移动哪个值的指针,所以我们移送num2的指针
-
依次类推...
-
当我们的begin1的值发现<0了,这是其实并没有结束,因为begin2的值还可能不为0,此时我们只需要将begin2相对应的值全部放入addend的值即可
执行用时:80 ms, 在所有 JavaScript 提交中击败了84.78%的用户
内存消耗:37.8 MB, 在所有 JavaScript 提交中击败了90.47%的用户
var merge2 = function (nums1, m, nums2, n) {
let end1 = m - 1;//num1的尾指针
let end2 = n - 1;//num2的尾指针
let addend = m + n - 1;
while (end2 >= 0) {
if (end1 < 0) {
nums1[addend] = nums2[end2];
end2 -= 1
} else if (nums1[end1] > nums2[end2]) {
nums1[addend] = nums1[end1]
end1 -= 1
} else {
nums1[addend] = nums2[end2];
end2 -= 1;
}
addend -= 1
}
return nums1
};
画了以下大概流程(因为没带鼠标就再本子上画了):