主要考察归并排序得思想,本题方法很多
我自己写的非最优版本
public void merge(int[] nums1, int m, int[] nums2, int n) {
if (n == 0) {
return;
}
if (m == 0) {
for (int i = 0; i < n; i++) {
nums1[i] = nums2[i];
}
return;
}
/**
* nums1 = [1,2,2,0,0,0], m = 3,
* nums2 = [3,5,6], n = 3
* 输出:[1,2,2,3,5,6]
*/
/**
* [1,2,3,0,0,0]
* 3
* [4,5,6]
* 3
*/
/**
* [1,0,0,0,0,0]
* 1
* [2,3,4,5,6]
* 5
*/
int first = 0;
int second = 0;
for (; first < m; ) {
if (nums1[first] > nums2[second]) {
swap(nums1, first, nums2, second);
sortArrays(nums2);
}
first++;
}
for (second = 0; second < n; second++, first++) {
nums1[first] = nums2[second];
}
}
/**
* * [2,3,4]
*/
private void sortArrays(int[] nums2) {
if (nums2.length < 2) {
return;
}
for (int i = 0; i < nums2.length; i++) {
if (i == nums2.length - 1) {
return;
}
if (nums2[i] <= nums2[i + 1]) {
break;
}
int temp = nums2[i];
nums2[i] = nums2[i + 1];
nums2[i + 1] = temp;
}
}
public void swap(int[] nums1, int i, int[] nums2, int j) {
int temp = nums1[i];
nums1[i] = nums2[j];
nums2[j] = temp;
}
方法一:直接合并后排序
利用库函数中的快排
平均时间复杂度,O((m+n)log(m+n))
平均时间空间复杂度,O(log(m+n))
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
for (int i = 0; i != n; ++i) {
nums1[m + i] = nums2[i];
}
Arrays.sort(nums1);
}
}
方法二:双指针
空间复杂度:O(m+n)
时间复杂度:O(m+n)
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int p1 = 0, p2 = 0;
int[] sorted = new int[m + n];
int cur;
while (p1 < m || p2 < n) {
if (p1 == m) {
//m走完后,下一个值应该是另外一个数组了
cur = nums2[p2++];
} else if (p2 == n) {
//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 != m + n; ++i) {
nums1[i] = sorted[i];
}
}
}
方法三:逆向双指针,最优
时间复杂度:O(m+n)
空间复杂度:O(1)
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int p1 = m - 1, p2 = n - 1;
int tail = m + n - 1;
int cur;
//只要两个数组任意一个没走完,就要继续向左走
while (p1 >= 0 || p2 >= 0) {
if (p1 == -1) {
//p1 == -1表示nums1已经走完了,这个时候nums2还没走完,需要继续向左移动一个
cur = nums2[p2--];
} else if (p2 == -1) {
//p2 == -1表示nums2已经走完了,这个时候nums1还没走完,需要继续向左移动一个
cur = nums1[p1--];
} else if (nums1[p1] > nums2[p2]) {
cur = nums1[p1--];
} else {
cur = nums2[p2--];
}
nums1[tail--] = cur;
}
}
}
思考总结
- 主要考察归并排序的思想
- 归并排序从左往右,或从右往左两种策略
- 归并排序需要开辟新空间,原地排序两种思路