「这是我参与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);
};
解法二
三指针。
思路
- 定义一个指针right指向A数组末尾,用于指定插入元素的位置。
- 定义一个rightA指向A数组的最后一个元素。
- 定义一个rightB指向B数组的最后一个元素。
- 遍历数组A,从从rightA位置开始遍历
- 比较A[rightA] 和 B[rightB] 的大小
- 如果A[rightA]大,则将A[rightA]赋值给A[right]
- 然后将rightA往前移动一格,将right也往前移动一格
- 如果B[rightB]更大或两者相等,则将B[rightB]赋值给A[right]
- 然后将rightB往前移动一格,将right也往前移动一格
- 遍历的结束条件是,rightA和rightB都不小于0,两者任意一个小于0都停止
- 然后再看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),不需要申请额外的空间存放数据。