Leetcode题库 ----合并两个有序数组(java语言版)

题目描述:

     

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

 本题主要有三种思路,推荐是使用第三种思路,时间复杂度低,效率高,代码量少。

          第一种思路:也就是大多数人的思路,就是排序,重点就在于排序,将第二个数组直接添加到第一个数组后边然后遍历即可。(这道题本人用的排序方法是内设置函数Array.sort,在前面博客中,我分别用了冒泡排序,选择排序,有兴趣可以看我前面的博客),这种思路不是重点,所以不必深究。

         第二种思路:就是定义一个额外的数组来保存nums1与nums2比较后的结果,这个数组的长度等于nums1+nums2.当nums1的元素小于nums2的元素时,将nums1的元素保存到新建的数组中,同时让nums1和新建的数组同时向后移动(++),此时注意nums2的下标没有变化,再次比较,要是nums2的元素小于nums移动后的元素,则将nums2的元素保存到新建数组中,然后让nums2与新建数组下标向后移动,nums1下标不变。(也就是nums1,nums2中小的那个元素赋值给新建数组,然后移动这个小元素对应的下标,再判断大小,在移动)

         第三种思路: 第二中思路就是前插法,也很明确,但是开辟了新的空间,那我们可以像前一篇博客一样,将nums1看作两个数组,一个数组用来比较,一个数组用来保存。然后发现,还用前插法的话,得不到我们想要的结果,因为影响了原数组中未处理的值,因为nums1除了已有的元素还有额外空间,那我们就用尾插法,这样不会影响原数组未作处理的值。还能很快的得到我们想要的结果。比较方式和第二种方法一样,不过是比较最大值(从尾部插入,因为是排序好的数组,尾部是最大值),将两者中的最大值插入到“新数组的末尾”,逐个比较。

         具体看代码:

第一种思路:

//          第一种方法,将第二个数组元素添加到第一个数组元素中,然后排序,重点在排序这个地方,(我用的内置排序方法,其他,归并快速,冒泡选择都行)
          int m=3;
          int n=3;
          int nums1[] = new int[]{1,2,3,0,0,0};
          int nums2[] = new int[]{2,5,6};
//          将排序数组nums2赋值到nums1,m个元素后面,然后排序就行,冒泡。选择,快速,我用的是内置函数。
          int j=0;
          for (int i=m;i<m+n;i++){
              nums1[i]=nums2[j];
              j++;
          }
          Arrays.sort ( nums1 );
          for (int num:nums1){
              System.out.print(num+" ");
          }

执行结果:

执行用时:

 第二种思路:  

  

 //第二种方法,定义三个数组,一个空数组,空数组的大小等于另外两个数组大小的和(能放下两个数组的合并结果)。用来存放另外两个数组(排序后的数组)比较的结果。
//          当第一个数组中的元素小于第二个数组中的元素时(谁小证明谁是当前最小的元素),将第一个数组中对应元素赋值给空数组,然后让第一个数组和空数组加一,向后移动,当第一个数组大于于第二个数组时,将第二个数组中的对应元素赋值给空数组,然后让第二个数组和空数组增一,向后移动。
          int nums[] = new int[]{0,0,0,0,0,0,0,0};
          int nums1[] = new int[]{1,2,5,7,8,9};
          int nums2[] = new int[]{3,5,6};
//            代表操作第一个数组的指针
          int j=0;
//          代表操作第二个数组的指针
          int k=0;
          for (int i=0;i<nums.length;i++){
//              这句话防止数组越界
             if (j<nums1.length&&k<nums2.length) {
//                 当第一个数组小于等于第二个数组元素时,将第一个数组赋值给空数组,并向后移动。
                 if (nums1[j] <=nums2[k] ) {
                     nums[i]=nums1[j];
                     j++;
//  当第一个数组大于于等于第二个数组元素时,将第二个数组赋值给空数组,并向后移动。
                 }else if (nums1[j]>nums2[k]){
                     nums[i]=nums2[k];
                     k++;
                 }
             }
//             如果某一个数组比较完了,也就是k,j>数组长度时,直接将将另外一个数组中的元素(未比较完)赋值给空数组中剩与的位置。
             else if(j>=nums1.length){
                 nums[i]=nums2[k];
                 k++;
                 j++;
             }else{
                 nums[i]=nums1[j];
                 j++;
                 k++;
              }
          }
         for (int num:nums){
              System.out.print(num+" ");
         }

执行结果:

执行用时:

 第三种思路:

 //第三种方法,(尾插法)不另外开辟空间,将第一个数组看作两个数组,然后进行操作
          int nums1[]=new int[]{1,2,5,6,7,0,0,0};
          int nums2[]=new int[]{3,8,9};
//          n1代表数组1中元素(存在元素,0不算)末尾的下标。
          int n1=nums1.length-nums2.length-1;
//          n2代表数组二中末尾的下标
          int n2=nums2.length-1;
//          尾插法,i从“新数组”(将nums1看成两个数组)的末尾下标,然后比较将元素从末尾插入到新数组中
          for (int i=nums1.length - 1; i >=0; i--) {
//              n1+1代表nums1中元素的个数,当nums1中的元素的个数为0时,就将nums2中的元素从末尾依次插入新数组(nums1额外空间)中
               if ((n1+1)==0){
                   nums1[i]=nums2[n2];
                   n2--;
               }
//               n2+1代表nums2的元素个数,为0时跳出,然后剩与元素就为nums1中的元素
               else if ((n2+1) == 0) {
                   break;
               }
//               判断,当nums1末尾元素大于nums2末尾元素时,则将nums1添加到新数组(新数组的空间等于nums1+nums2)的末尾;否则将nums2添加到新数组的末尾,然后逐个递减进行判断。
               else if (nums1[n1] >nums2[n2]) {
                        nums1[i]=nums1[n1];
                        n1--;
               }
               else {
                        nums1[i]=nums2[n2];
                        n2--;
              }
          }
          for (int num : nums1) {
              System.out.print ( num + " " );
          }
      }

执行结果:

执行用时:

      总结:本题表面看起来没有多难,但是其中包含的很多东西值得慢慢体会。尾插法是一个很重要的方法,当前插法会改变原数组元素(将一个数组看成两个)时,尾插法就体现了很大的作用。我还差的远,还得慢慢来。

      2019-3-4

发布了43 篇原创文章 · 获赞 6 · 访问量 6675

猜你喜欢

转载自blog.csdn.net/weixin_37850160/article/details/88134148