《LeetCode系列》---合并两个有序数组

💥今天的这道leetcode题,将通过逆向双指针来进行解决。

 

涉及知识:

        数组相关知识的基础;


目录

一、题目描述

二、思路分析

1、题目思路

2、代码分析

 三、代码提交


一、题目描述

题目名称合并两个有序数组(编号88)

难度简单💥

 🎄简单来说,该题就是给了两个有序的数组nums1和nums2,然后将两个数组合并后存储在nums1里。


二、思路分析

1、题目思路

通过该题描述,合并后的数组是有序的。

这时有些聪明的人,也许就会想到把两个数组合并后再直接用库方法sort()来排序。

虽然可以直接解出该题,但不建议这么做。

这么做的话,这道题就没有意思了呀。

💥(1)该题中给的参数不止有两个数组,还有对应两个数组的长度(m和n)。那么我们可以通过该长度来获取数组的下标。

💥(2)定义两个数组的最后一个元素的下标位置,然后通过遍历,从每一个数组的最后一个下标位置开始进行比较。(从后面开始确定)

💥(3)由于两个数组合并后要存储在第一个数组nums1里面,那么我们何不将比较好后较大的一个元素,直接存储在nums1的最后一个下标位置(nums1的长度得进行扩容)。

💥(4)那么我们就需要有三个位置的指针,分别是第一个数组nums1的m-1位置,第二数组nums2的n-1位置和要增添进第一个数组nums1末尾的m+n-1位置。

  • 为什么都要减1?

因为数组是从下标0位置开始,m和n,m+n都是作为数组的长度,需要减1才能获取最后一个下标位置。

  • m+n是代表什么?

因为要合并两个数组,并存储进第一个数组里面,那么存储后的第一个数组nums1,其长度不得变成两个数组长度之和(m+n)。


2、代码分析

代码示例:

public class TestDemo1 {
    public static void merge(int[] nums1, int m, int[] nums2, int n){
        int i=m-1;       //nums1数组的末位置
        int j=n-1;       //nums2数组的末位置
        int k=m+n-1;     //合并后nums1数组的末尾置
        while(i>=0&&j>=0){
            //从末尾开始比较,直到其中一个数组下标位置为0
            if(nums1[i]>=nums2[j]){
            //如果数组1的i位置元素大于或等于数组2的j位置元素,就将大的一方存储在k的位置
                nums1[k]=nums1[i];
                i--;        //之后要将i和k向左移动
                k--;
            } else{
            //如果数组2的j位置元素大于或等于数组1的i位置元素,就将大的一方存储在k的位置
                nums1[k]=nums2[j];
                j--;        //之后要将j和k向左移动
                k--;
            }
        }
        //当然有可能存在其中一个数组的长度小于另外一个
        //这时就会出现其中一个数组已经遍历完,但另外一个数组却没有
        //那么我们就要将还没遍历完的数组直接存储在k的下一个位置里,直到这个数组也遍历完
        while(i>=0){
            nums1[k]=nums1[i];
            i--;
            k--;
        }
        while(j>=0){
            nums1[k]=nums2[j];
            j--;
            k--;
        }
        //一切遍历完后,就完成了合并的过程
    }
    public static void main(String[] args) {
    //假设两个数组的长度都是3
        int []arr1={1,2,3,0,0,0};
        int []arr2={4,5,6};
        int m=3,n=3;
        merge(arr1,m,arr2,n);    //调用合并方法
        System.out.println(Arrays.toString(arr1));    //将数组转换成字符串再打印出来
    }
}

(1)这道题利用逆向双指针来解决,那么此处我们得定义三个位置的指针。

(2)为了对这两个数组中的每一个元素进行比较 ,因为是从末位置开始往前循环比较,那么当定义的数组长度i或j小于0时,即说明这个数组已经都存储进nums1里了。 


 

以下面这个图为例,比较完后,j小于0,nums2里的4、5、6都存进绿色方框位置,此时合并有序数组就完成了。

(3)

💥可有一种情况是,如果其中一个数组的长度小于另外一个数组长度,那么就会出现长度小的数组已经存进去了,但大的数组还没进行排序存进去。   

💥还有一种情况是nums2的数组元素都小于nums1的数组元素,那么当nums1遍历完后循环结束,nums2的元素还没存进nums1里去.     

因此我们得对这两种情况进行处理。

对两个数组进行一次遍历判断。

如果下标位置还是大于或等于0,说明还没有完全存储进数组1,那么只需继续存进对应nums1的k位置,再更新k和对应数组的下标i或j即可。 

 

【注意】:

        这种方法只能应用于两个“有序”数组 ,前提条件是有序,如果是两个非有序数组,是不可以用以上这种方法进行合并的.

 三、代码提交

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
可以使用二分查找算法来解决这个问题。 首先,我们可以将两个数组合并成一个有序数组,然后求出中位数。但是,这个方法的时间复杂度为 $O(m + n)$,不符合题目要求。因此,我们需要寻找一种更快的方法。 我们可以使用二分查找算法在两个数组中分别找到一个位置,使得这个位置将两个数组分成的左右两部分的元素个数之和相等,或者两部分的元素个数之差不超过 1。这个位置就是中位数所在的位置。 具体来说,我们分别在两个数组中二分查找,假设现在在第一个数组中找到了一个位置 $i$,那么在第二个数组中对应的位置就是 $(m + n + 1) / 2 - i$。如果 $i$ 左边的元素个数加上 $(m + n + 1) / 2 - i$ 左边的元素个数等于 $m$ 个,或者 $i$ 左边的元素个数加上 $(m + n + 1) / 2 - i$ 左边的元素个数等于 $m + 1$ 个,则这个位置就是中位数所在的位置。 具体的实现可以参考以下 Java 代码: ```java public double findMedianSortedArrays(int[] nums1, int[] nums2) { int m = nums1.length, n = nums2.length; if (m > n) { // 保证第一个数组不大于第二个数组 int[] tmp = nums1; nums1 = nums2; nums2 = tmp; int t = m; m = n; n = t; } int imin = 0, imax = m, halfLen = (m + n + 1) / 2; while (imin <= imax) { int i = (imin + imax) / 2; int j = halfLen - i; if (i < imax && nums2[j - 1] > nums1[i]) { imin = i + 1; // i 太小了,增大 i } else if (i > imin && nums1[i - 1] > nums2[j]) { imax = i - 1; // i 太大了,减小 i } else { // i 是合适的位置 int maxLeft = 0; if (i == 0) { // nums1 的左边没有元素 maxLeft = nums2[j - 1]; } else if (j == 0) { // nums2 的左边没有元素 maxLeft = nums1[i - 1]; } else { maxLeft = Math.max(nums1[i - 1], nums2[j - 1]); } if ((m + n) % 2 == 1) { // 总元素个数是奇数 return maxLeft; } int minRight = 0; if (i == m) { // nums1 的右边没有元素 minRight = nums2[j]; } else if (j == n) { // nums2 的右边没有元素 minRight = nums1[i]; } else { minRight = Math.min(nums1[i], nums2[j]); } return (maxLeft + minRight) / 2.0; } } return 0.0; } ``` 时间复杂度为 $O(\log\min(m, n))$。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星河栀染

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值