renchord / SEU_MIMO_LeetCode

This project records the solutions and chats about the Top/Hot LeetCode issues by MIMO h/w teams of SEU
4 stars 0 forks source link

[LC-88][chapter3][Two Pointer Algorithm] Merge Sorted Array #12

Open luna5210 opened 2 years ago

luna5210 commented 2 years ago

Tag : 双指针 中文链接:https://leetcode-cn.com/problems/merge-sorted-array/

题目描述: 给你两个按 非递减顺序 排列的整数数组 nums1nums2,另有两个整数 mn ,分别表示 nums1nums2 中的元素数目。 请你合并 nums2nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 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 -10^9 <= nums1[i], nums2[j] <= 10^9   进阶:你可以设计实现一个时间复杂度为 O(m + n) 的算法解决此问题吗?

题目解答: 给定两个有序数组nums1、nums2,将两个数组合并到nums1,使其保证非递减顺序排序,nums1设计成m+n长度,不需要开拓新的空间。为了保证非递减排序,我们需要遍历数组,而指针正是用于遍历数组的,由于数组本身是有序的,所以从最后的大数来更新所需的步骤最少;那么这题两个数组各需要一个指针,nums1作为最后的返回数组,还需要一个指针pos(指向数组末尾m+n-1);另外两个指针分别指向nums1的m-1、nums2的n-1。 具体步骤:

  1. 通过比较两个数组将大数复制到nums1的尾部,每次比较后依次递减向前遍历;
  2. 如果nums2先结束,nums1是排好序的,则任务完成;
  3. 如果nums1先结束,nums2要再依次复制到数组中,任务完成。

注意:这里使用了++和--的小技巧,a++和++a都是将a加1,a++返回值为a,++a返回值为a+1。如果只是希望增加a的值而不是返回a的值,即本题中的移动指针,推荐使用++a,运行速度略快一些。 之前的一些for循环也是只需要增加a的值,但是有时需要注意for循环的结束条件。

代码:

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int pos = m-- + n-- -1;
        while( m >= 0 && n >= 0){
            nums1[pos--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--];
        }
        while( n >= 0){
            nums1[pos--] = nums2[n--];
        }
    }
};

复杂度分析: 时间复杂度:O(m + n),需要遍历两个数组一次; 空间复杂度:O(1), 不需要额外使用空间。