每日算法 合并有序数组

100 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情

一、题目

  • 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
  • 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
  • 注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

二、粗鲁解

  • 先来一点粗鲁的解法,直接先合并,再利用sort排序
  • 这里的合并不能直接用拓展运算符(...),因为它是需要在nums1本身进行变更
var merge = function(nums1, m, nums2, n) {
    nums1.splice(m, nums1.length - m);  //先给他切掉后面占位的0
    nums2.forEach(item=>{ 
        nums1.push(item)  //然后把nums2的元素接上去
    })
    nums1.sort((a, b)=> a-b);  //使用sort进行排序
};
  • 忘记了我们的splice也是可以进行添加元素的,罪过罪过,再加一下写法
  • 简化一下,两步搞定
var merge = function(nums1, m, nums2, n) {
    nums1.splice(m, nums1.length - m, ...nums2);
    nums1.sort((a, b)=> a-b);
};

三、双指针

  • 其实看到这道题我的第一想法就是类似链表的有序合并21. 合并两个有序链表 - 力扣(LeetCode),采用穿针引线的方法
  • 当然,在数组和链表的操作上还是有区别的
  • 所以我们也用双指针来试一下穿针引线,这个时候就需要再借助一个数组来存放有序的元素
var merge = function(nums1, m, nums2, n) {
    let p1 = 0 ,p2 = 0;  //p1指针负责管理nums1, p2负责管理nums2
    let cur ;  //负责管理有序数组元素
    let res = []; //辅助的有序数组
    while(p1 < m || p2 < n) {
        if(p1 == m) {  //说明nums1已经走完了,那么接下去就只管nums2
            cur = nums2[p2];
            p2++;
        }else if (p2 == n) {  //nums2已经走完了,接下去只管nums1
            cur = nums1[p1]; 
            p1++;
        } else if (nums1[p1] < nums2[p2]) {  //p1指向的元素比较小,要了
            cur = nums1[p1];
            p1++;
        } else {
            cur = nums2[p2] ;  //要p2指向的
            p2++; 
        }
        res.push(cur);  //收入囊中
    }
    //最后再赋值给nums1 
    for(let i = 0 ;i < m+n ;i++) {
        nums1[i] = res[i]
    }
};

四、后前向填补

  • 其实在写的时候就能感觉到上面的步骤比较繁琐,进行了四个状态的判断
  • 那么我们已知的nums1后面的0都是没有用的,那么我们不如考虑从后向前填补
var merge = function(nums1, m, nums2, n) {
    let last = m+n-1;  //指向nums1的最后一个元素
    m--;  //指向nums1最后的元素
    n--;  //指向nums2最后的元素
    while(n>=0) {  //只要nums2还有就继续填补到完
        if(nums1[m] > nums2[n]) { 
            [nums1[m], nums1[last]] = [nums1[last], nums1[m]];
            m--;
        }else {
            nums1[last] = nums2[n];
            n--;
        }
        last--;  //确定完一个就向前走
    }
};

以上均通过力扣用例