leetcode
leetcode 51 ~ 100
合并两个有序数组

合并两个有序数组

难度:

标签:

题目描述

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

请你 合并 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) 的算法解决此问题吗?

代码结果

运行时间: 36 ms, 内存: 15.1 MB


/**
 * 思路:
 * 1. 将nums1和nums2的有效部分合并后排序。
 * 2. 使用Java Stream处理。
 */
import java.util.Arrays;
 
public class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        System.arraycopy(nums2, 0, nums1, m, n); // 合并数组
        Arrays.sort(nums1); // 排序
    }
}

解释

方法:

该题解使用双指针法,从两个数组的末尾开始,比较两个指针所指元素的大小,将较大的元素放入 nums1 的末尾,同时将相应的指针向前移动。重复这个过程,直到其中一个数组的元素全部放入 nums1 中。最后,如果 nums2 中还有剩余元素,将其直接复制到 nums1 的前面。

时间复杂度:

O(m+n)

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中提到的双指针方法是否有特定的条件或假设,例如数组的长度或内容,才能确保正确运行?
双指针方法的正确执行基于几个关键假设:首先,nums1的大小至少为m+n,这是为了确保有足够的空间存放来自nums2的元素。其次,nums1和nums2必须是预先排序的。如果这些条件得到满足,该方法才能正确运行,否则结果将不正确或方法执行过程中会出现错误。
🦆
题解中提到如果nums2中还有剩余元素要复制到nums1的前面,为什么nums1中的元素不需要同样的处理?
在nums1和nums2都已经是排序好的数组的情况下,我们从后向前比较和填充nums1。当其中一个数组的元素全部处理完毕时,若nums1中的元素先被处理完,这意味着nums1的元素都已经在正确的位置上,因为它们已被比较和放置。而如果是nums2中的元素还有剩余,则表明这些元素是整个合并数组中最小的,需要被复制到nums1的前端。
🦆
题解说明了如果nums2的元素更大,则将其放入nums1的末尾。但是如果nums1的元素已经全部处理完,而nums2还有剩余怎么办?
如果nums1的元素已经全部处理完而nums2中还有剩余元素,这些剩余元素应直接复制到nums1的前面(即nums1数组的起始位置),因为在从后向前的合并过程中,这些剩余元素一定是所有元素中最小的,且位置已经由前面的排序过程保证其正确性。
🦆
这种从后向前填充的方法是否总是比从前向后填充更优?在什么情况下可能不是?
从后向前填充方法主要优势在于避免了额外的空间使用,因为它可以直接在原数组nums1上操作。当nums1有足够的空间存放两个数组合并后的所有元素时,这种方法是有效且优化的。然而,如果nums1没有预留足够空间,或者需要对原始数据的顺序保持不变,那么从前向后的填充(可能需要额外的空间来处理合并)可能更适合。

相关问题

合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

 

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1l2 均按 非递减顺序 排列

有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

 

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

 

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums 已按 非递减顺序 排序

 

进阶:

  • 请你设计时间复杂度为 O(n) 的算法解决本问题

区间列表的交集

给定两个由一些 闭区间 组成的列表,firstListsecondList ,其中 firstList[i] = [starti, endi] 而 secondList[j] = [startj, endj] 。每个区间列表都是成对 不相交 的,并且 已经排序

返回这 两个区间列表的交集

形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b

两个闭区间的 交集 是一组实数,要么为空集,要么为闭区间。例如,[1, 3][2, 4] 的交集为 [2, 3]

 

示例 1:

输入:firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]
输出:[[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]

示例 2:

输入:firstList = [[1,3],[5,9]], secondList = []
输出:[]

示例 3:

输入:firstList = [], secondList = [[4,8],[10,12]]
输出:[]

示例 4:

输入:firstList = [[1,7]], secondList = [[3,10]]
输出:[[3,7]]

 

提示:

  • 0 <= firstList.length, secondList.length <= 1000
  • firstList.length + secondList.length >= 1
  • 0 <= starti < endi <= 109
  • endi < starti+1
  • 0 <= startj < endj <= 109
  • endj < startj+1