304、合并两个有序数组

这是一个关于合并两个非递减有序整数数组的问题,要求合并后数组依然保持非递减顺序,并且直接更新nums1数组。解决方案是使用逆向双指针策略,从后往前比较nums1和nums2的元素,依次将较小的元素放入结果数组中,直到其中一个数组为空。最后,如果nums2仍有剩余元素,则直接将其插入到nums1的剩余位置。该算法的时间复杂度为O(m+n),其中m和n分别是两个数组的元素数量。
摘要由CSDN通过智能技术生成

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

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

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

  

示例 1

输入: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 中的元素。

示例 2

输入:nums1 = [1], m = 1, nums2 = [], n = 0

输出:[1]

解释:需要合并 [1] 和 [] 。

合并结果是 [1] 。

示例 3

输入:nums1 = [0], m = 0, nums2 = [1], n = 1

输出:[1]

解释:需要合并的数组是 [] 和 [1] 。

合并结果是 [1] 。

注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

  

提示:

nums1.length == m + n

nums2.length == n

0 <= m, n <= 200

1 <= m + n <= 200

-109 <= nums1[i], nums2[j] <= 109

  

进阶:你可以设计实现一个时间复杂度为 O(m + n) 的算法解决此问题吗?

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/merge-sorted-array

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

package cn.fansunion.leecode.linkedlist;

/**

 * 88. 合并两个有序数组 <br/>给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

 *

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

 *

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

 *

 * 来源:力扣(LeetCode) 链接:力扣 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 *

 * @author wen.lei@brgroup.com

 *

 *         2022-2-23

 */

public class MergeSortedArray {

    /* 示例 1:

     

    输入: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 中的元素。

    示例 2:

     

    输入:nums1 = [1], m = 1, nums2 = [], n = 0

    输出:[1]

    解释:需要合并 [1] 和 [] 。

    合并结果是 [1] 。

    示例 3:

     

    输入:nums1 = [0], m = 0, nums2 = [1], n = 1

    输出:[1]

    解释:需要合并的数组是 [] 和 [1] 。

    合并结果是 [1] 。

    注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

     

    提示:

     

    nums1.length == m + n

    nums2.length == n

    0 <= m, n <= 200

    1 <= m + n <= 200

    -109 <= nums1[i], nums2[j] <= 109*/

    /**

     * 思路:目标是把nums2按照顺序插入到nums1,从后向前比较插入;双指针,效率高;<br/>

     * 如果nums2有剩余的没插入,需要单独再插入<br/>

     * 如果nums1有剩余的没插入,不需要处理,特征是处理nums2,nums2没处理的自然就有序的<br/>

     * 官方算法学名:“逆向双指针”。因为算法题经常都是各种“奇思妙想”,“诡计”,突然想到:就是从后向前容易点,逐步替换“0”的过程

     * 这道题的“合并数组”,又是有特定要求的;常见的合并数组:nums1+nums2,可以直接new一个nums3,正向遍历nums1和nums2

     *

     *

     * @param nums1

     * @param m

     * @param nums2

     * @param n

     */

    public void merge(int[] nums1, int m, int[] nums2, int n) {

        int nums1Index = m - 1;

        int nums2Index = n - 1;

        int curIndex = m + n - 1;

        while (nums1Index >= 0 && nums2Index >= 0) {

            if (nums1[nums1Index]<= nums2[nums2Index]) {

                nums1[curIndex] = nums2[nums2Index];

                nums2Index--;

                curIndex--;

            else {

                nums1[curIndex] = nums1[nums1Index];

                nums1Index--;

                curIndex--;

            }

        }

        // nums1提前往后挪了,nums2还有剩下的

        // 这种题目,边界值的情况经常有,一次性想不全,必须得构造很多测试用例额

        while (nums2Index >= 0) {

            nums1[nums2Index] = nums2[nums2Index];

            nums2Index--;

        }

    }

    /**

     * 合并两个有序数组(笨办法),结果还不对<br/>

     * [-1,0,0,3,3,3,0,0,0] 6,[1,2,2] 3;输出:[1,2,2,-1,0,0,3,3,3],预期:[-1,0,0,1,2,2,3,3,3]

     *

     * @param nums1

     *            nums1 = [1,2,3,0,0,0]

     * @param m

     *            3 nums2 = [2,5,6]

     * @param nums2

     *            3

     * @param n

     *            3 输出:[1,2,2,3,5,6] 解释:需要合并 [1,2,3] 和 [2,5,6] 。

     */

    public void mergeStupidAndError(int[] nums1, int m, int[] nums2, int n) {

        // 遍历需要插入的若干数字

        for (int nums2Index = 0; nums2Index < n; nums2Index++) {

            // 插入1个数字到目标数组里

            mergeIntoNums(nums2[nums2Index], nums1);

        }

    }

    // 插入1个数字到目标数组里

    private void mergeIntoNums(int newNum, int[] nums) {

        // 先找插入位置

        int insertIndex = 0;

        for (int i = 0; i < nums.length; i++) {

            if (nums[i] <= 0 || newNum < nums[i]) {

                insertIndex = i;

                break;

            }

            insertIndex++;

        }

        // 通过2个临时变量的辅助,插入,效果:后面的数字都往后移一位

        int cur = newNum;

        int next = 0;

        for (int index = insertIndex; index < nums.length; index++) {

            next = nums[index];

            nums[index] = cur;

            cur = next;

        }

    }

    /**

     * 另外一种形式的合并数组,允许构造新的merge数组并返回,稍微简单点

     *

     * @param nums1

     * @param nums2

     * @return

     */

    public int[] mergeWithReturn(int[] nums1, int[] nums2) {

        int[] nums = new int[nums1.length + nums2.length];

        int nums1Index = 0;

        int nums2Index = 0;

        int curIndex = 0;

        // 双指针

        while (nums1Index < nums1.length && nums2Index < nums2.length) {

            if (nums1[nums1Index] <= nums2[nums2Index]) {

                nums[curIndex] = nums1[nums1Index];

                nums1Index++;

            else {

                nums[curIndex] = nums2[nums2Index];

                nums2Index++;

            }

            curIndex++;

        }

        // num1有剩余的

        while (nums1Index < nums1.length) {

            nums[curIndex] = nums1[nums1Index];

            nums1Index++;

            curIndex++;

        }

        // nums2有剩余的

        while (nums2Index < nums2.length) {

            nums[curIndex] = nums2[nums2Index];

            nums2Index++;

            curIndex++;

        }

        return nums;

    }

}

package test.leecode.linkedlist;

import org.junit.Assert;

import org.junit.Test;

import cn.fansunion.leecode.linkedlist.MergeSortedArray;

/**

 * @author wen.lei@brgroup.com

 *

 *         2022-2-23

 */

public class MergeSortedArrayTest {

    @Test

    public void test() {

        MergeSortedArray test = new MergeSortedArray();

        // test2

        int[] nums3 = new int[] {23500000};

        int[] nums4 = new int[] {14569};

        test.merge(nums3, 3, nums4, 5);

        Assert.assertArrayEquals(new int[] {12345569}, nums3);

        // test1

        int[] nums1 = new int[] {123000};

        int[] nums2 = new int[] {256};

        test.merge(nums1, 3, nums2, 3);

        Assert.assertArrayEquals(new int[] {122356}, nums1);

        // test3

        int[] nums5 = new int[] {33330000};

        int[] nums6 = new int[] {1122};

        test.merge(nums5, 4, nums6, 4);

        Assert.assertArrayEquals(new int[] {11223333}, nums5);

        // test4

        int[] nums7 = new int[] {11230000};

        int[] nums8 = new int[] {4567};

        test.merge(nums7, 4, nums8, 4);

        Assert.assertArrayEquals(new int[] {11234567}, nums7);

    }

    @Test

    public void testMergeWithReturn() {

        MergeSortedArray test = new MergeSortedArray();

        // test2

        int[] nums3 = new int[] {235};

        int[] nums4 = new int[] {14569};

        int[] test2 = test.mergeWithReturn(nums3, nums4);

        Assert.assertArrayEquals(new int[] {12345569}, test2);

        // test1

        int[] nums1 = new int[] {123};

        int[] nums2 = new int[] {256};

        int[] test1 = test.mergeWithReturn(nums1, nums2);

        Assert.assertArrayEquals(new int[] {122356}, test1);

        // test3

        int[] nums5 = new int[] {3333};

        int[] nums6 = new int[] {1122};

        int[] test3 = test.mergeWithReturn(nums5, nums6);

        Assert.assertArrayEquals(new int[] {11223333}, test3);

        // test4

        int[] nums7 = new int[] {1123};

        int[] nums8 = new int[] {4567};

        int[] test4 = test.mergeWithReturn(nums7, nums8);

        Assert.assertArrayEquals(new int[] {11234567}, test4);

    }

    // mergeStupid

    public static void main(String[] args) {

        // test1

        int[] nums1 = new int[] {123000};

        int[] nums2 = new int[] {256};

        MergeSortedArray msa = new MergeSortedArray();

        msa.mergeStupidAndError(nums1, 3, nums2, 3);

        for (int num : nums1) {

            System.out.print(num);

        }

        System.out.println();

        // test2

        int[] nums3 = new int[] {23500000};

        int[] nums4 = new int[] {14569};

        MergeSortedArray msa2 = new MergeSortedArray();

        msa2.mergeStupidAndError(nums3, 3, nums4, 5);

        for (int num : nums3) {

            System.out.print(num);

        }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值