题目描述
给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
初始化 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中。一开始我的思路是用三个循环,外层是将nums2遍历,内层两个是将nums1遍历。首先取nums2中的数,遍历nums1直到nums1[i]<=nums2[j]<nums[i+1] ,那么复制给nums[i+1]=nums[j] 将nums1[i+2]=nums[i+1]向后移动。但是可以看出来这个时间复杂度将会到达O(n^3)实在太高了怎么办。
我下面意识到,既然这样又麻烦又复杂,那我为什么不先把nums2接到nums1后面,然后再排序,由于又是有序的,不可能到达排序的worst case,这样既没有额外空间,也不会时间复杂度那么高。下面的代码我也是这么做的,但是我偷了个懒用了内置函数,因为笔试是允许内置函数的,不会让你浪费很多的时间去写一个简单的排序。
源码
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];
//由于已经知道大小了,直接把nums2拷贝到nums1后面
}
Arrays.sort(nums1);
//直接内置的归并算法给数组排序
}
}
改进
可以看到上面的源码很简洁真正的就三步搞定,但是复杂度还是高了,因为下面的归并算法的复杂度会达到O(nlog(n))。那么有没有什么办法降低复杂度到O(n)并且空间复杂度还是为O(1)呢。那么下面就可以模仿归并排序了,由于是有序的,那么我们可以从后向前比较,将最大的数放在数组的末尾。这样既不会影响nums1的遍历,也不会产生额外的空间,最后也就遍历了一遍nums1就好了。
改进代码
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int r=m--+n-- -1;
//这句表达式就是先将r=m+n-1,然后m--,n--,这样后面的数组就都会从m-1和n-1开始了
while(m>=0&&n>=0){
nums1[r--]=nums1[m]>nums2[n]?nums1[m--]:nums2[n--];
}
while(n>=0){
nums1[r--]=nums2[n--];
//为什么这边和归并排序比起来少了一个while(m>=0)呢,因为值本来就再nums1中,没有用到额外空间,否则是还要再加一个循环的。
}
}
}
分析
第一个时间复杂度为O(nlog(n))
第二个就是O(n)
空间复杂度都为O(1)
难点
这是一道简单题,难点就是要想最优解,把时间的复杂度降到最低
[1]https://leetcode-cn.com/problems/merge-sorted-array/submissions/