这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战
本文题目均来自LeetCode,每道题都会有多种解法,因为我们主要是为了练习双指针,所以只考虑用双指针解题
什么是双指针
双指针
:指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。- 双指针法充分使用了数组有序这一特征,从而在某些情况下能够简化一些运算。
- 换言之,只要我们看到有序数组,那么就可以考虑使用双指针解法。
题目一
- 给你一个
有序
数组 nums ,请你原地
删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
要求: 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
测试用例
[1,1,2]
解析
读题,划重点
。也就是找出题目中的关键词。本题中我们可以看到,源数组是有序的
,最终的结果是要返回一个没有重复元素的数组的长度
,同时解题要求是,必须在原地(即必须在原数组上操作),不能利用另外的数组。- 理解题目要求之后,开始思考解题思路:
- 首先,数组存在为空的情况,此时没有任何重复元素,满足题目条件,那么我们直接返回0即可。
- 在数组不为空的情况下:(我们利用快慢指针)
- 创建一个变量i指向数组的第一位;
- 然后从数组第二位开始迭代数组,在此过程中,如果 nums[i] 不等于 nums[j]时,我们先将 i++,接着将nums[i]的值替换为nums[j],以此类推
- 最后返回 i+1
看代码:
let removeDuplicates = function(nums) {
let len = nums.length;
if (len === 0) {
return 0
}
let i = 0
for (let j=1; j < len; j++) {
if (nums[j] !== nums[i]) {
i++;
nums[i] = nums[j]
}
}
return i + 1;
}
迭代步骤
- 源数组
[1, 1, 2, 3, 4]
初始化的i = 0; j = 1
- 第一次迭代:
nums[0] === nums[1]
,不进入我们的处理逻辑; - 第二次迭代:
i = 0; j = 2; nums[i]为1,nums[j]为2
,进入处理逻辑,将 i 赋值为 1,nums[1] 赋值为 2; - 第三次迭代:
i = 1; j = 3; nums[i]为2,nums[j]为3
,进入处理逻辑,将 i 赋值为 2,nums[2] 赋值为 3; - 第四次迭代:
i = 2; j = 4; nums[i]为3,nums[j]为4
,进入处理逻辑,将 i 赋值为 3,nums[3] 赋值为 4; - 第五次迭代,
j = 5
,不满足循环的前置条件,所以循环结束。此时数组为[1, 2, 3, 4]
,i的值为3
- 因为我们一开始没有去更改nums[0]的值,所以返回的是 i + 1
练习题
- 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
要求:
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。