力扣 88. 合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
方案一:临时数组计算保存结果,之后覆盖 nums1。
func merge(nums1 []int, m int, nums2 []int, n int) {
// 定义临时数组,将 nums1 和 nums2 的对比合并结果存入该临时数组
res := make([]int, m + n)
// i, j 分别指向 nums1 和 nums2 的数组开头,k 指向临时数组开头
for i, j, k := 0, 0, 0; k < m + n; k++ {
// 对比 i,j 指向的值,将较大者存入 k 指向的位置,同时更新 i,j 位置
if j >= n || i < m && nums1[i] < nums2[j] {
res[k] = nums1[i]
i++
} else {
res[k] = nums2[j]
j++
}
}
// 将临时数组的值覆写到 nums1
for i, num := range res {
nums1[i] = num
}
}
- 时间复杂度:O(m+n),因为需要遍历所有数组元素才能完成元素比较,合并数组,所以时间复杂度为 O(m+n)。
- 空间复杂度:O(m+n),因为使用了一个长度为 m+n 的临时数组保存合并结果,最后再将临时数组结果覆盖到原数组,所以空间复杂度为 O(m+n)。
方案二:逆向思维,反向计算。
func merge(nums1 []int, m int, nums2 []int, n int) {
// 因为 nums1 的下标从 m 开始后对应的值都为 0
// 将 nums1 和 nums2 从数组尾部进行对比
// 并将较大值写入 nums1 的尾部可以不对 nums1 前面的值造成干扰
// i, j 分别指向 nums1 和 nums2 的最大值,k 指向 nums1 的最大允许下标
for i, j, k := m - 1, n - 1, m + n - 1; k >= 0; k-- {
// 对比 nums1 和 nums2 的最大值,并将结果写入 k 指向的位置,从后到前完成遍历
if j < 0 || i >= 0 && nums1[i] > nums2[j] {
nums1[k] = nums1[i]
i--
} else {
nums1[k] = nums2[j]
j--
}
}
}
- 时间复杂度:O(m+n),因为需要遍历所有数组元素才能完成元素比较,合并数组,所以时间复杂度为 O(m+n)。
- 空间复杂度:O(1),因为所有的元素比较移动操作都在数组 nums1 中完成,没有借助额外的辅助空间,所以空间复杂度为 O(1)。