LeetCode刷题Java——88.合并两个有序数组(简单)

题目

给你两个按非递减顺序排列的整数数组nums1和nums2,另有两个整数m和n,分别表示nums1和nums2中的元素数目。

请你合并nums2到nums1中,使合并后的数组同样按非递减顺序排列。

注意:

最终,合并后数组不应由函数返回,而是存储在数组nums1中。为了应对这种情况,nums1的初始长度为m+n,其中前m个元素表示应合并的元素,后n个元素为0,应忽略。nums2的长度为n。

示例

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。

输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

解决方案

方案一:直接合并然后排序

直接将nums2中的元素加到nums1后面,然后使用排序算法进行排序。

这种方法没有使用nums1和nums2已经有序的特点,并且时间复杂度较大。

方案二:双指针法(正向)

指针p1遍历nums1,指针p2遍历nums2,将较小值放进新的数组然后移到下一个,这样会增加空间复杂度

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int[] sorteeNums = new int[m+n];
        int p1 = 0, p2 = 0;
        // nums1和nums2都没有遍历完
        while (p1 < m && p2 < n) {
            if(nums1[p1] < nums2[p2]) {
                sorteeNums[p1+p2] = nums1[p1];
                p1++;
            } else {
                sorteeNums[p1+p2] = nums2[p2];
                p2++;
            }
        }
        // nums1和nums2有一个遍历完了
        if(p1 == m) {
            while (p2 < n) {
                sorteeNums[p1+p2] = nums2[p2];
                p2++;
            }
        } else if(p2 == n) {
            while (p1 < m) {
                sorteeNums[p1+p2] = nums1[p1];
                p1++;
            }
        }

        for (int i = 0; i < sorteeNums.length; i++) {
            nums1[i] = sorteeNums[i];
        }
    }
}

也可以直接操作原数组nums1,如果nums2的元素要插入进来,就把nums1之后的元素往后移动,但是这样会增加时间复杂度

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p1 = 0, p2 = 0, index = 0;
        // nums1和nums2都没有遍历完
        while (p1 < m+n && p2 < n) {
            if(nums1[p1] > nums2[p2]) {
                for (int i = m+n-1; i > index; i--) {
                    nums1[i] = nums1[i-1];
                }
                nums1[index] = nums2[p2];
                p2++;
            }
            p1++;
            index++;
        }
        // 如果是nums1遍历完了,还需要把nums2拼上去
        // 如果是nums2遍历完了,nums1已经移动到后面去了不需要动
        if(p2 < n) {
            int diff = n-p2;
            for (int i = 0; i < diff; i++) {
                nums1[m+n-1-i] = nums2[n-1-i];
            }
        }
    }
}

方案三:双指针法(逆向)

方案二需要new一个长度为m+n的新数组,因为从头开始排序时直接操作nums1需要覆盖。

可以从nums1的第m个元素和nums2的第n个元素开始往前比,大的加到nums1尾部以后数据的前面,然后对应指针减一。这样不需要new新数组从而增加空间复杂度,也不需要移动元素增加时间复杂度。

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p1 = m-1, p2 = n-1, index = m+n-1;
        while (p1 >=0 && p2 >= 0) {
            if(nums1[p1] >= nums2[p2]) {
                nums1[index] = nums1[p1];
                p1--;
            } else {
                nums1[index] = nums2[p2];
                p2--;
            }
            index--;
        }
        while (p2 >= 0) {
            nums1[p2] = nums2[p2];
            p2--;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值