前端算法(55)

41 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

题目解析

我们先用参数 m 和 n,分别保存两个数组当前遍历到索引位置,因为是数组长度,所以遍历前先减一,在进行遍历数组,每次遍历都能确定一个数的位置,最多遍历 nums1.length === m + n 次,如果 nums1 数组已经遍历了 m 次,表示 nums1 数组中的非零整数的位置都已经确定了则 nums1 和 nums2 两个数组遍历中交错取值,而 nums1 数组中的元素位置确定,表明 nums2 数组中剩余未遍历的元素都比 nums1 数组中最后一次遍历的元素要小,在直接将 nums2 数组中剩余未遍历的元素,从 nums1 数组开头位置按顺序添加,并删除 nums2 数组中原来的元素,直接终止遍历即可, 如果 nums2 数组已经遍历了 n 次,表示 nums2 数组中的元素位置都已经确定了则nums1 和 nums2 数组都是有序整数数组,nums2 数组中的元素位置确定,而且是从后往前修改 nums1 数组,表明 nums1 数组中剩余未遍历的元素,是有序且无需遍历,即 nums1 数组已经是组合完成并有序的了,直接终止遍历即可,否则就倒序遍历,从大小到确定两个数组中的元素,将比较后更大的一方,从末尾开始保存在 nums1 数组中,每遍历一次确定一个数的位置,且更新 nums2 数组下一个待检查元素的索引位置

/**
 * @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) {
  m--;
  n--;
  for (var i = nums1.length - 1; i >= 0; i--) {
    if (m < 0) {
      nums1.splice(0, n + 1, ...nums2.slice(0, n + 1));
      break;
    }
    if (n < 0) {
      break;
    }
    if (nums2[n] > nums1[m]) {
      nums1[i] = nums2[n];
      n--;
    } else {
      nums1[i] = nums1[m];
      m--;
    }
  }
};