「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」
前言:
励志每日至少一题,并写下题解,死磕算法,加油
第一天我们讲了两数之和,是数组类型题目,今天我们接着讲数组类型的题目
题目
给你两个按 非递减顺序 排列的整数数组 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 中的元素。
题目地址:leetcode-cn.com/problems/me…
思路
首先我们应该从题目中提取关键词
- 1.非递减顺序,那意思就是有序喽
- 2.合并后数组不应由函数返回,而是存储在数组 nums1 中。那我们就是要操作nums1。
- 3.nums1后面有三个空位,这三个空位绝对不是空穴来风,绝对有用途,😝
联想
我们可以和生活中的例子做联想
我们两个架子上有从小到大排列的书籍,现在我们想把第二排的书籍放到第一排的架子上,怎么才能更省时省力呢
- 1.方法一:我们把第二排的书直接排到第一排的的后面,然后在一个个比较排列(合并后排序,这是最费力的) 那我们把第一排的书籍和第二排的一个一个作比较可以么?
- 2.方法二:我们把第一排和第二排的书籍从左边一个一个开始做比较,如果第二排第一个书籍比第一排第一个书籍小,那我们就把第一个位置给了第二排第一个书籍,把第一排第一个书籍放到第三排待用,或者把第一排的书籍都要往后挪,这是我们发现这个方法也不是很省力(双指针左侧对比)
- 3.方法三:我们把第一排和第二排的书籍从右边一个一个开始做比较,这时我们发现从题中提取关键词的时候发现 nums1后面有三个空位,这样我们对比的时候既不用开辟最新的空间,也不需要所有的书都要向后挪(遍历,切记数组的插入是o(n),时间复杂度是非常大的)(双指针右侧对比)
经过上卖弄的分析,我们发现方法三是最方便的
上面的这种对比方法就是双指针法
那么什么情况下我们可以思考用双指针来做呢?
- 1.双指针分为左右指针和快慢指针
- 2.只要我们碰到数组和字符串问题就可以往左右指针方面来想
- 3.只要数组
有序
,那就立马想到左右指针 - 4.碰到链表问题我们可以往快慢指针来想
题解
var merge = function (nums1, m, nums2, n) {
let length = m + n - 1;
let first = m - 1; // 第一排的指针
let second = n - 1; // 第二排的指针
// 为什么要 >-1, 如果一排的书对比完以后,指针会变成 - 1,那我们就不用在对比下去了,因为 - 1没有书籍了
// 为什么要first >-1 && second >-1而不是length>-1,我们一定要和实际联想起来,因为无论是first=-1还是second=-1的时候我们都没办法在进行对比了,所以不能使用length>-1
while (first > -1 && second > -1) {
if (nums1[first] > nums2[second]) {
nums1[length] = nums1[first]; // length这个位置的书籍就给第一排first这个位置的书籍
length--; // 然后坑位向前挪一下
first--; // first向前挪动一下
} else {
nums1[length] = nums2[second]; // length这个位置的书籍就给第二排second这个位置的书籍
length--; // 然后坑位向前挪一下
second--; // first向前挪动一下
}
}
// 如果上面的执行完,可能还会剩下一些书没有被对比,那我们直接把length最前面的位置给了他
// 如果是第一排的书籍没有被对比完,我们就不用对比了,因为那些书我们不用动位置,所以我们要考虑第二排的书籍有没有被对比完
while (second > -1) {
nums1[length] = nums[second];
second--;
length--;
}
}
-
时间复杂度:O(m+n)我们还是看执行量级最大的那段代码while (first > -1 && second > -1) ,first=m-1,second=n-1;所以这行代码的时间复杂度
最大
为O(m+n),而下面的while(second>-1)的时间复杂度最大为O(n),我们取最大的,O(m+n) -
空间复杂度:O(m+n)我们除了看定义的变量以外,还要看函数中的参数的变化,我们在梳理复杂度的时候,一定要一行一行的看,防止有遗漏,这段代码中,存储空间最大的就是nums1了,他的length为m+n-1,去掉常数,所以空间复杂度为O(m+n);