题目描述
若存在两个按非递减顺序排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示其元素数目
要求合并 nums2 到 nums1 中,并且使合并后的数组同样按非递减顺序排列
相信肯定有一部分人不太理解此处的非递减顺序!!!
其实简单来说,就是递增顺序,但是又不是严格递增,如
然后可能也不太理解两个数组是如何合并的!!!
如数组 nums1 和 nums2 的长度都为 3,那么提前将 nums1 开辟 3+3=6 的内存空间,前三个位置存储原本的元素,后三个位置存储 0
C 语言具体代码实现
先看看作者本人的想法!!!(哈哈哈,显然是最差劲的一种方法)
先将 nums2 的元素插入到 nums1 的空余位置,然后使用 qsort 函数对 nums1 排序
时间复杂度:
空间复杂度:
#include <stdio.h>
#include <stdlib.h>
int cmp(const void* _a, const void* _b){ // 参数格式固定
int *a = (int*)_a; // 强制类型转换
int *b = (int*)_b; // 强制类型转换
return *a - *b; // 升序
}
void merge(int *nums1, int nums1Size, int m, int *nums2, int nums2Size, int n){
// 将 nums2的元素插入到 nums1的空余位置
for(int i = m, j = 0; i < nums1Size; i++, j++){
nums1[i] = nums2[j];
}
// 对 nums1排序
qsort(nums1, nums1Size, sizeof(int), cmp);
}
int main(void){
int nums_1[] = {1, 2, 3, 0, 0, 0};
int nums_2[] = {2, 5, 6};
merge(nums_1, 6, 3, nums_2, 3, 3);
// 格式化输出列表
printf("[");
for(int i = 0; i < 6; i++){
if(i != 5){
printf("%d,", nums_1[i]);
}else{
printf("%d", nums_1[i]);
}
}
printf("]");
// [1,2,2,3,5,6]
return 0;
}
再看另一种方法:双指针!!!
利用两数组已经被排序好的性质,使用双指针的方法,将两个数组看作队列,每次从两个数组头部取出比较小的数字放到结果中
时间复杂度:
空间复杂度:
#include <stdio.h>
#include <stdlib.h>
void merge(int *nums1, int nums1Size, int m, int *nums2, int nums2Size, int n){
int p1 = 0, p2 = 0; // 两个指针
int sorted[nums1Size]; // 临时数组
int cur; // 临时值
while(p1 < m || p2 < n){ // 两个数组中有任何一个没有遍历完
if(p1 == m){
cur = nums2[p2++];
}else if(p2 == n){
cur = nums1[p1++];
}else if(nums1[p1] < nums2[p2]){
cur = nums1[p1++];
}else{
cur = nums2[p2++];
}
sorted[p1+p2-1] = cur;
}
for(int i = 0; i < nums1Size; i++){
nums1[i] = sorted[i];
}
}
int main(void){
int nums_1[] = {1, 2, 3, 0, 0, 0};
int nums_2[] = {2, 5, 6};
merge(nums_1, 6, 3, nums_2, 3, 3);
// 格式化输出列表
printf("[");
for(int i = 0; i < 6; i++){
if(i != 5){
printf("%d,", nums_1[i]);
}else{
printf("%d", nums_1[i]);
}
}
printf("]");
// [1,2,2,3,5,6]
return 0;
}
还有最后一种,也是最优的方法:逆向双指针!!!
此方法是双指针的拓展,区别在于这种方法不需要创建一个临时数组且多增加了一个指针值,用于指向 nums1中逆向的索引;相同的两个指针作用只有小小的变化,就是分别从数组的非 0 项开始比较,将较大的元素保存在 nums1 中逆向的索引对应的空间中
时间复杂度:
空间复杂度:
#include <stdio.h>
#include <stdlib.h>
void merge(int *nums1, int nums1Size, int m, int *nums2, int nums2Size, int n){
int p1 = m - 1, p2 = n - 1; // 分别指向两数组最后一项(非0)元素
int tail = m + n - 1; // 指向 nums1数组最后一项(0)元素
int cur; // 临时值
while(p1 >= 0 || p2 >= 0){
if(p1 == -1){
cur = nums2[p2--];
}else if(p2 == -1){
cur = nums1[p1--];
}else if(nums1[p1] > nums2[p2]){
cur = nums1[p1--];
}else{
cur = nums2[p2--];
}
nums1[tail--] = cur; // 直接修改 nums1数组
}
}
int main(void){
int nums_1[] = {1, 2, 3, 0, 0, 0};
int nums_2[] = {2, 5, 6};
merge(nums_1, 6, 3, nums_2, 3, 3);
// 格式化输出列表
printf("[");
for(int i = 0; i < 6; i++){
if(i != 5){
printf("%d,", nums_1[i]);
}else{
printf("%d", nums_1[i]);
}
}
printf("]");
// [1,2,2,3,5,6]
return 0;
}