leetcode系列:合并两个有序数组

描述

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

说明:

初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

示例:

输入:

nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3

输出:

[1,2,2,3,5,6]

思路

解一

由于nums1已经是排序了的,我们能参考插入排序的思想,将nums2中的元素,逐个与nums1末尾的元素进行比较,直到找到合适的位置插入为止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
assert nums1 != null && nums2 != null;
for (int i = 0; i < n && m < nums1.length; i++, m++) {
nums1[m] = nums2[i];
for (int j = m; j > 0; j--) {
if (nums1[j] >= nums1[j - 1]) {
break;
} else {
swapArr(nums1, j, j - 1);
}
}
}
}

private static void swapArr(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}

该算法的时间复杂度不理想,时间复杂度为 O(N*M)

解二

双指针思想

p为nums1的末尾,q为新插入的位置。

从后面开始遍历数组nums2,逐个比较nums[i] 与 nums1[p] 的值

如果 nums1[p] > nums2[i] ,交换p,q指标的值,一直循环到nums1[p] <= nums2[i],将大的值nums2[i]放置q位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MergeArr {

public void merge(int[] nums1, int m, int[] nums2, int n) {
assert nums1 != null && nums2 != null;
// 为nums1的末尾指针
int p = m - 1;
// 找到比较后应该插入的位置,起初为m + n - 1
int q = m + n - 1;

// 从后面开始遍历数组nums2
for (int i = n - 1; i >= 0; i--) {
// 如果nums1[p] > nums2[i]
while (p >= 0 && nums1[p] > nums2[i]) {
// 交换这两个值,交换后p,q往前移一位
swapArr(nums1, p--, q--);
}
// 否则,将大的值放置q位置,q往前移一位
nums1[q--] = nums2[i];
}
}

private static void swapArr(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}

时间复杂度为O(N+M),空间复杂度为O(1)

参考

参一

直接使用jdk源码数组拷贝

1
2
3
4
5
6
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
System.arraycopy(nums2, 0, nums1, m, n);
Arrays.sort(nums1);
}
}

参二

逐个比较,比较大的放置后面,只是末尾需要额外的复制,最坏情况下,时间复杂度为O((n+m)log(n+m))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
// two get pointers for nums1 and nums2
int p1 = m - 1;
int p2 = n - 1;
// set pointer for nums1
int p = m + n - 1;

// while there are still elements to compare
while ((p1 >= 0) && (p2 >= 0))
// compare two elements from nums1 and nums2
// and add the largest one in nums1
nums1[p--] = (nums1[p1] < nums2[p2]) ? nums2[p2--] : nums1[p1--];

// add missing elements from nums2
System.arraycopy(nums2, 0, nums1, 0, p2 + 1);
}
}

最好时间复杂度O(N+M)

github

代码链接见上面👆