Leetcode刷题日记-No88合并两个有序数组

本文详细解析LeetCode第88题,介绍如何合并两个已排序的数组,通过比较元素并原地操作,达到空间复杂度优化。讨论了不同解法的时间和空间复杂度,并强调算法优化的重要性。
摘要由CSDN通过智能技术生成

题目地址:https://leetcode.cn/problems/merge-sorted-array/

        如果对归并排序有印象,其实能直接看出来这个算法就是归并排序“并”的部分(已经限定了数组是非递减排序的)。由于两个数组已经是排序好的,那么可以维护两个指针i和j,分别代表两个数组的索引值,且初始值都为0。依次比较nums1[i]和nums2[j]的大小,小的保存,指针后移并继续比较,直到一个数组遍历完成,将另一个数组的剩余元素“平移”即可。代码如下:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i=0;
        int j=0;
        int k=0;
        int[] result = new int[m+n];
        while(i<m && j<n) {
            if(nums1[i] <= nums2[j]) {
                result[k++] = nums1[i++];
            }else{
                result[k++] = nums2[j++];
            }
        }
        //合并剩余数组中的元素
        if(i == m) {
            while(j<n) {
                result[k++] = nums2[j++];
            }
        }
        if(j == n) {
            while(i<m) {
                result[k++] = nums1[i++];
            }
        }
        for (int i1 = 0; i1 < nums1.length; i1++) {
            nums1[i1] = result[i1];
        }
    }
}

        时间复杂度分析:上面代码涉及到4个非嵌套循环,因此总的时间复杂度线性的,精确一点就是O(m+n)。

        空间复杂度分析:由于引入了一个长度为m+n的临时数组,因此空间复杂度也为O(m+n)

        注:上述while循环的写法可以改造为更精简的for循环写法,代码如下:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int[] result = new int[m+n];
        for (int i = 0, i1=0, i2=0; i < m+n; i++) {
            //如果num1已经取完,直接取nums2
            if(i1==m) {
                result[i] = nums2[i2++];
            }else if(i2==n) {
                result[i] = nums1[i1++];
            }else if(nums1[i1]<=nums2[i2]) {
                result[i] = nums1[i1++];
            }else{
                result[i] = nums2[i2++];
            }
        }
        for(int i=0;i<m+n;i++) {
            nums1[i] = result[i];
        }
    }
}

        紧接着,考虑是否能够原地排序,不引入额外的空间复杂度。观察nums1数组,后面有n个保留给nums元素的位置,如果换一个思路,从后往前遍历,就可以在不引入额外存储的情况下实现。代码如下:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int k = m+n;
        for (int i=k-1, i1=m-1, i2=n-1; i >= 0; i--) {
            if(i1 < 0) {
                nums1[i] = nums2[i2--];
            }else if(i2 < 0) {
                nums1[i] = nums1[i1--];
            }else if(nums1[i1]<=nums2[i2]) {
                nums1[i] = nums2[i2--];
            }else{
                nums1[i] = nums1[i1--];
            }
        }
    }
}

        反思:基础的方法很容易都能想到,但是算法就是拼的特定条件下的时间复杂度和空间复杂度最优,要有不满足的精神,将代码优化到极致。另外,本题目从尾到头遍历省去一个额外数组的解法也提醒我,当觉得问题无解的时候,多跳出固化思维,从另外一个视角去看,或许就是“山重水复疑无路,柳暗花明又一村”了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值