前言
相比前面两天的题目稍微难一点,我将在本文中梳理我的思考过程 审题 画图 每一步转换 找特殊情况 打代码
一、题目再解读
原题题干
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
O(1):不随n的增加而增加即可 可以有1、2、C个固定的变量 不单单只是一个
核心规则(抓重点)
原地修改:不能新建数组,只能在原数组上改,空间复杂度O(1)
返回值:返回移除后的数组长度k,原数组前k个元素为有效元素
顺序有关:有效元素顺序不可以打乱。
无需处理k之后的元素,系统不会校验 示例演示
示例 1:
输入: nums = [1,1,1,2,2,3]
输出: 5, nums = [1,1,2,2,3]
解释: 函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3。 不需要考虑数组中超出新长度后面的元素。
示例 2:
输入: nums = [0,0,1,1,1,1,2,3,3]
输出: 7, nums = [0,0,1,1,2,3,3]
解释: 函数应返回新长度 length = 7, 并且原数组的前七个元素被修改为 0, 0, 1, 1, 2, 3, 3。不需要考虑数组中超出新长度后面的元素。
二、新手探索实录(我的思考复盘)
第一次写这道题时,我想用快慢双指针思路,但总觉得缺一个变量stock (判断一个数字是否已经出现两次了),但我稍微卡住了,靠想想不出来。
然后我在纸上画出 第一个实例 的变化状态
S是我们的慢指针 F是我们的快指针 sea也是一个指针 它像东海龙王一样 坐落与最新见到的数字的第一个位置
每次F都会往前一格,它就像警察一样审核它指向的犯人
我的循环默认情况是nums[F]和nums[S]相同,所以F自动增一,其他都是特殊情况
而我的特殊情况就是在以下状态转换图里找的了
ex: 状态1 nums[F]===nums[S] 但是 F-sea==1(数组[1,1]符合条件 ):
slow多走一步
F++
状态2 nums[F]===nums[S] 但是 F-sea==2(数组[1,1,1]不符合条件 ):
slow不走了 让fast警察自己去抓小偷 所以这个可以归为默认情况
F++
状态3 遇见新数字了:
先让sea改变位置先
再让S走一步
这个时候就可以就行赋值了 nums[S]=nums[F]
状态4 nums[F]===nums[S] 但是 F-sea==1(数组[1,1,2,2]符合条件 ):
slow多走一步
状态5 又遇见新数字了:
先让sea改变位置先
再让S走一步
这个时候就可以就行赋值了 nums[S]=nums[F]
以下是我的代码
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function (nums) {
let len = nums.length;
if (len === 0) {
return 0;
}
//创建三个变量-->用他们之间的距离来查即可
let slow = 0;
let sea = 0;
for (let fast = 1; fast < len; fast++) {
//判断遇到新的数字再改变sea(第一旧重复数字的位置)
if (nums[sea] != nums[fast]) {
sea=fast;
}
if ((nums[fast] === nums[slow]) && (fast - sea == 1)) {
slow++;
nums[slow]=nums[fast];
} else if (nums[fast] != nums[slow]) {
slow++;
nums[slow]=nums[fast];
}
}
return slow + 1;
};
其中还有一些巧妙的地方我不知道怎么的,突然在脑子里蹦出来的,不知道怎么说,还请见谅
三、最优解法:同向快慢指针(O (n) 时间 + O (1) 空间)
解法思路
数组是有序的 → 重复数字一定挨在一起!
两个指针
- fast 快指针:往前遍历,一个个检查元素
- slow 慢指针:记录新数组位置,存放合法的元素
var removeDuplicates = function(nums) {
let slow = 2;
for (let fast = 2; fast < nums.length; fast++) {
if (nums[fast] !== nums[slow - 2]) { nums[slow++] = nums[fast];
}
}
return Math.min(slow, nums.length);
};
四、复杂度分析
时间复杂度:O(n),数组仅遍历一次,双指针移动总次数不超过n
空间复杂度:O(1),仅用了两个指针变量,无额外数组空间开销,完全符合题目要求
结语
还得继续学习,解法不够优秀,思考太久,写博客也写了很久,以后写快点 加油加油