[路飞]_leetcode刷题_面试题 10.01. 合并排序的数组

445 阅读2分钟

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战

题目

给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。

初始化 A 和 B 的元素数量分别为 m 和 n。

示例:

输入:
A = [1,2,3,0,0,0], m = 3
B = [2,5,6],       n = 3

输出: [1,2,2,3,5,6]

解法一

暴力解法。

思路

直接将B的所有元素放入A中,然后再进行排序。

那只是为了表达该思想,我们就直接用数组插入的方法splice和js数组自带的排序方法sort即可。

代码

/**
 * @param {number[]} A
 * @param {number} m
 * @param {number[]} B
 * @param {number} n
 * @return {void} Do not return anything, modify A in-place instead.
 */
var merge = function(A, m, B, n) {
    A.splice(m, A.length - m, ...B);
    A.sort((a, b) => a - b);
};

解法二

三指针。

思路

  1. 定义一个指针right指向A数组末尾,用于指定插入元素的位置。
  2. 定义一个rightA指向A数组的最后一个元素。
  3. 定义一个rightB指向B数组的最后一个元素。
  4. 遍历数组A,从从rightA位置开始遍历
    • 比较A[rightA] 和 B[rightB] 的大小
    • 如果A[rightA]大,则将A[rightA]赋值给A[right]
      • 然后将rightA往前移动一格,将right也往前移动一格
    • 如果B[rightB]更大或两者相等,则将B[rightB]赋值给A[right]
      • 然后将rightB往前移动一格,将right也往前移动一格
  5. 遍历的结束条件是,rightA和rightB都不小于0,两者任意一个小于0都停止
  6. 然后再看B数组是否有值,即rightB是否小于0,若不小于0,将遍历,将B内剩下的值都方法A的前面

整体思路其实是借鉴了归并排序的合并的思想,只是我们这里是从后往前合并,而且是原数组上操作。

两个有序数组比较,从后往前比,谁的数更大,就取谁。

代码如下

/**
 * @param {number[]} A
 * @param {number} m
 * @param {number[]} B
 * @param {number} n
 * @return {void} Do not return anything, modify A in-place instead.
 */
var merge = function(A, m, B, n) {
    let right = m+n-1;
    let rightA = m-1;
    let rightB = n-1;

    while(rightA>=0&&rightB>=0){
        if(A[rightA] > B[rightB]){
            A[right] = A[rightA];
            right--;
            rightA--;
        }else{
            A[right] = B[rightB];
            right--;
            rightB--;
        }
    }
    if(rightB>=0){
        while(right>=0){
            A[right] = B[rightB];
            right--;
            rightB--
        }
    }
    return A
};

复杂度分析

时间复杂度:O(m+n),需要将A和B的所有元素都遍历到,总共是m+n

空间复杂度:O(1),不需要申请额外的空间存放数据。