leetcode-88.合并两个有序数组

171 阅读3分钟

合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 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] 

思考

看完题呢,脑子里第一个想法就是暴力 ,将他们合并 然后nums.sort((a,b)=>a-b)(a-b为升序)就解决了。但是很明显 不是题目所要考察的

T u T 啊,孩子真的没救了吗?

既然不用sort,那我们想想其他的办法吧

image.png 首先呢 可以建立两个索引 index1,index2分别指向num1和num2的第一个数

既然要把num2加入num1,那么就从num2[index2]开始比较num1[index1],如果遇见比num2[index2]大的数,那么就可以将num2[index2]插入num1[index1]前面,同时呢,num1往后面挤掉一个0。同时呢,如果num1最后一个非0数都比num2第一个数小,那么直接将num2全部加入到num1.

function merge(nums1, m, nums2, n) {
    // 从 nums2 中逐一取出元素
    for (let i = 0; i < n; i++) {
        // 当前需要插入的元素
        let current = nums2[i];

        // 在 nums1 的前 m+i 个元素中找到插入位置
        let j = 0;
        while (j < m + i && nums1[j] <= current) {
            j++;
        }

        // 插入元素并更新 nums1 的长度
        nums1.splice(j, 0, current);
        nums1.pop(); // 移除最后一个 0 以保持数组长度
    }
}
let nums1 = [1, 2, 3, 0, 0, 0];
let m = 3;
let nums2 = [2, 5, 6];
let n = 3;
merge(nums1, m, nums2, n);
console.log(nums1);  // 输出应为 [1, 2, 2, 3, 5, 6]

用了数组的内置方法还这么费劲,再想想吧…… 那么前面这么费劲,后面呢,我们不妨从后面来。 两个索引都指向数组的末尾有效值,我们比较他们的大小,谁大,就去num1的最后,如此循环 好像也可以?!!

var merge = function(nums1, m, nums2, n){ 
            let p1 = m - 1, p2 = n - 1, p = m + n - 1;
            while (p2 >= 0) { // nums2 还有要合并的元素 
            // 如果 p1 < 0,那么走 else 分支,把 nums2 合并到 nums1 中 
            if (p1 >= 0 && nums1[p1] > nums2[p2]) {
            nums1[p--] = nums1[p1--]; 
            // 填入 
            nums1[p1] 
            } else {
                nums1[p--] = nums2[p2--]; 
                // 填入
                nums2[p1]
                } 
              }
            }
           

事实证明也是可以的。

任务完成