合并两个有序数组

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。

示例

  • 示例 1:
    输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
    输出:[1,2,2,3,5,6]
  • 示例 2:
    输入:nums1 = [1], m = 1, nums2 = [], n = 0
    输出:[1]

解答

方法一:直接合并后排序
/**
 * @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) {
    nums1.splice(m, nums1.length - m, ...nums2);
    nums1.sort((a, b) => a - b);
};
复杂度分析
  • 时间复杂度:O((m+n)log(m+n))。
    排序序列长度为 m+n,套用快速排序的时间复杂度即可,平均情况为 O((m+n)log(m+n))。

  • 空间复杂度:O(log(m+n))。
    排序序列长度为 m+n,套用快速排序的空间复杂度即可,平均情况为 O(log(m+n))。

方法二:双指针

利用数组 nums 1与nums 2 已经被排序的性质,将两个数组看作队列,每次从两个数组头部取出比较小的数字放到结果中。

/**
 * @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 newArr=[];
    let p1=0,p2=0;
    for(i=0;i<m+n;i++){
        if(p2 == n){//nums2结束,把nums1后面的直接链接到数组后面
            newArr = newArr.concat(nums1.slice(p1,m));
            break;
        }else if(p1 == m){//nums1结束,把nums2后面的直接链接到数组后面
            newArr = newArr.concat(nums2.slice(p2,n));
            break;
        }else{
            newArr[i] = nums1[p1]<=nums2[p2]?nums1[p1++]:nums2[p2++];
        }
    }
    nums1 = newArr;
};
复杂度分析
  • 时间复杂度:O(m+n)。
    指针移动单调递增,最多移动m+n 次,因此时间复杂度为 O(m+n)

  • 空间复杂度:O(m+n)。
    需要建立长度为 m+n 的中间数组 sorted。

方法三:逆向双指针

由于已知nums1数组的长度是等于合并后的长度,后半部分是空的,可以直接覆盖而不会影响结果。因此可以指针设置为从后向前遍历,每次取两者之中的较大者放进nums 1的最后面。

/**
 * @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 newArr=[];
    let p1=m-1,p2=n-1;
    for(i=m+n-1;i>=0;i--){
        if(p2 == -1){//nums2排序结束可以直接退出
            break;
        }else if(p1 == -1){//nums1排序结束后,继续从nums2中取值
            nums1[i] = nums2[p2--]
        }else{
            nums1[i] = nums1[p1]<= nums2[p2]? nums2[p2--]:nums1[p1--];
        }
    }
};
复杂度分析
  • 时间复杂度:O(m+n)。
    指针移动单调递减,最多移动 m+n 次,因此时间复杂度为 O(m+n)。

  • 空间复杂度:O(1)O(1)。
    直接对数组nums 1原地修改,不需要额外空间。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容