LeetCode [88]合并两个有序数组

LeetCode [88]合并两个有序数组

题目描述

给定两个有序整数数组 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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值