双指针 排序 数组
题目描述 给你两个按 非递减顺序 排列的整数数组 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 );
}
}