数组
双指针
排序
题目描述
给你两个按 非递减顺序 排列的整数数组 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)
的算法解决此问题吗?
解法
方法一:双指针
我们注意到数组的有序性,可以使用双指针的方法,从后向前遍历两个数组,每次取两个数组中较大的一个放进合并后的数组的最后面。
具体地,我们用两个指针 $i$ 和 $j$ 分别指向两个数组的末尾,用一个指针 $k$ 指向合并后的数组的末尾。每次比较两个数组的末尾元素,将较大的元素放在合并后的数组的末尾,然后将指针向前移动一位,重复这个过程,直到两个数组的指针都指向了数组的开头。
时间复杂度 $O(m + n)$,其中 $m$ 和 $n$ 分别是两个数组的长度。空间复杂度 $O(1)$。
Python3 Java C++ Go TypeScript Rust JavaScript PHP
1
2
3
4
5
6
7
8
9
10
11
12 class Solution :
def merge ( self , nums1 : List [ int ], m : int , nums2 : List [ int ], n : int ) -> None :
k = m + n - 1
i , j = m - 1 , n - 1
while j >= 0 :
if i >= 0 and nums1 [ i ] > nums2 [ j ]:
nums1 [ k ] = nums1 [ i ]
i -= 1
else :
nums1 [ k ] = nums2 [ j ]
j -= 1
k -= 1
class Solution {
public void merge ( int [] nums1 , int m , int [] nums2 , int n ) {
for ( int i = m - 1 , j = n - 1 , k = m + n - 1 ; j >= 0 ; -- k ) {
nums1 [ k ] = i >= 0 && nums1 [ i ] > nums2 [ j ] ? nums1 [ i --] : nums2 [ j --] ;
}
}
}
class Solution {
public :
void merge ( vector < int >& nums1 , int m , vector < int >& nums2 , int n ) {
for ( int i = m - 1 , j = n - 1 , k = m + n - 1 ; ~ j ; -- k ) {
nums1 [ k ] = i >= 0 && nums1 [ i ] > nums2 [ j ] ? nums1 [ i -- ] : nums2 [ j -- ];
}
}
};
func merge ( nums1 [] int , m int , nums2 [] int , n int ) {
for i , j , k := m - 1 , n - 1 , m + n - 1 ; j >= 0 ; k -- {
if i >= 0 && nums1 [ i ] > nums2 [ j ] {
nums1 [ k ] = nums1 [ i ]
i --
} else {
nums1 [ k ] = nums2 [ j ]
j --
}
}
}
/**
Do not return anything, modify nums1 in-place instead.
*/
function merge ( nums1 : number [], m : number , nums2 : number [], n : number ) : void {
for ( let i = m - 1 , j = n - 1 , k = m + n - 1 ; j >= 0 ; -- k ) {
nums1 [ k ] = i >= 0 && nums1 [ i ] > nums2 [ j ] ? nums1 [ i -- ] : nums2 [ j -- ];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 impl Solution {
pub fn merge ( nums1 : & mut Vec < i32 > , m : i32 , nums2 : & mut Vec < i32 > , n : i32 ) {
let mut k = ( m + n - 1 ) as usize ;
let mut i = ( m - 1 ) as isize ;
let mut j = ( n - 1 ) as isize ;
while j >= 0 {
if i >= 0 && nums1 [ i as usize ] > nums2 [ j as usize ] {
nums1 [ k ] = nums1 [ i as usize ];
i -= 1 ;
} else {
nums1 [ k ] = nums2 [ j as usize ];
j -= 1 ;
}
k -= 1 ;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12 /**
* @param {number[]} nums1
* @param {number} m
* @param {number[]} nums2
* @param {number} n
* @return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function ( nums1 , m , nums2 , n ) {
for ( let i = m - 1 , j = n - 1 , k = m + n - 1 ; j >= 0 ; -- k ) {
nums1 [ k ] = i >= 0 && nums1 [ i ] > nums2 [ j ] ? nums1 [ i -- ] : nums2 [ j -- ];
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 class Solution {
/**
* @param Integer[] $nums1
* @param Integer $m
* @param Integer[] $nums2
* @param Integer $n
* @return NULL
*/
function merge(&$nums1, $m, $nums2, $n) {
while (count($nums1) > $m) {
array_pop($nums1);
}
for ($i = 0; $i < $n; $i++) {
array_push($nums1, $nums2[$i]);
}
asort($nums1);
}
}