1、题目说明
给 2 个按 非递减顺序 排的整数数组 nums1、nums2,及 2 个整数 m 、n ,分别表示 nums1 和 nums2 中的元素数目。
(1)基本要求
合并 nums2 到 nums1 ,使合并后的数组nums1同样按 非递减 排序。nums1初始长为 m + n,其中前 m 个元素表示应合并的元素,若后 n 个元素为 0 ,则忽略。nums2 的长度为 n 。
(2)进阶要求
设计实现一个时间复杂度为 O(m + n) 的算法解决此问题
力扣官网上标注为88题,属简单类
2、题目分析
- 初始元素局部有序 ( 排除快速排序 )
- 原地排序 —— 考虑最优,使其空间复杂度为O(1), 选择、直插、冒泡、希尔、堆排 均可,其他的不行
- 由示例知,要求算法稳定 —— 直插、冒泡、2路归并、基数排序 均可,其他的不行
- 时间复杂度为nums1数组长,即 m+n (插入排序在最好情况下可做到)
- 2个数组均为非递减排列,若用原地排,可考虑从后向前,由大到小搞到nums1里头
3.解题思路
从后向前遍历,每次取两者中的较大者放进 nums1最后面。有点像直接插入法
4.代码(逻辑类似,重在复习不同语法)
C版
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
m--;
n--; // 变成数组尾元素下标
// tail是nums1的尾元素下标,从后向前
int tail = nums1Size - 1;
while (m>=0 && n>=0) {
// 比较尾巴
if (nums2[n] >= nums1[m]) {
nums1[tail--] = nums2[n--]; //用完再减
} else { // nums2<nums1 => 大的放至nums1尾部该放的位置
nums1[tail--] = nums1[m--];
}
}
while(n>=0){ //nums1的m个插完了,nums2的还没插完
nums1[tail--] = nums2[n--];
}
} //时间O(m+n); 空间 O(1)
Java版
public void merge(int[] nums1, int m, int[] nums2, int n) {
m--;
n--;
int len = nums1.length-1;
while(m>=0 && n>=0){
if(nums2[n] >= nums1[m])
nums1[len--] = nums2[n--];
else
nums1[len--] = nums1[m--];
}
while(n>=0)
nums1[len--] = nums2[n--];
}
Python版
def merge(nums1: list[int], m: int, nums2: list[int], n: int) -> None:
p1, p2, p = m - 1, n - 1, m + n - 1
while p2 >= 0: # nums2没插完
if p1 >= 0 and nums1[p1] > nums2[p2]:
nums1[p] = nums1[p1] # 填入 nums1[p1]
p1 -= 1
else:
nums1[p] = nums2[p2] # 填入 nums2[p2]
p2 -= 1
p -= 1
Go版
func merge(nums1 []int, m int, nums2 []int, n int) {
p1, p2, p := m-1, n-1, m+n-1
for p2 >= 0 { // nums2没插完
// nums1前m个未插完,且比nums2的大
if p1 >= 0 && nums1[p1] > nums2[p2] {
nums1[p] = nums1[p1]
p1--
} else {
nums1[p] = nums2[p2]
p2--
}
p--
}
fmt.Println(nums1)
}