合并两个有序数组

给你两个有序整数数组 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]
    ##解答

    方法一:直接合并后排序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * @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 已经被排序的性质,将两个数组看作队列,每次从两个数组头部取出比较小的数字放到结果中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /**
    * @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的最后面。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /**
    * @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原地修改,不需要额外空间。