今天复习专题写的是双指针的
26.删除排序数组中的重复项
和27.移除元素
。
26 删除排序数组中的重复项 Remove Duplicates From Sorted Array
-
难度:简单
-
想写这个主要是因为这是我在LeetCode上做的第一个题(还真不是Two Sum= =),当时其实做的有点懵,不过后来就好很多啦。
-
题目:给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组 并在使用 O ( 1 ) \mathcal{O}(1) O(1) 额外空间的条件下完成。
-
这里要求的是在原地修改数组,所以就不可以复制一个之后再做。
-
总体的思路就是维护两个指针,一个快指针遍历数组查看是否有重复,另一个慢指针负责修改数组。
-
这个题实际上比27题多了一些弯将在下面讲述:
-
1.首先,
for
循环是需要从i=1
(右指针)开始遍历的,因为nums[0]
总是要保留的。 -
2.然后就是
j
(左指针)当然是从0
开始遍历的,因为至少要和第一个元素做对比。只有当nums[i] != nums[j]
的时候才会移动。注意这里是先移动再赋值。所以是++j
。 -
3.最后,返回值是
j+1
,因为如果是j
则实际上最后一个并没有被包含进去。之前的保证的是最后一个元素没有重复,但是如果只是j
则不包含这个最后一个元素,而这个元素就在nums[j+1]
的地方。 -
这个题虽然简单,但是很多细节的地方也要注意。
class Solution {
public int removeDuplicates(int[] nums) {
int j=0;
for(int i=1;i<nums.length;i++){ //i=1是因为第一个总是要保留的
if(nums[i]!=nums[j]){
nums[++j] = nums[i];//++j也是因为第一个要保留,所以先加再换
}
}
return j+1;//注意一下,不然最后一个进不来
}
}
- 时间复杂度:使用
for
循环遍历了一遍,所以时间复杂度是 O ( n ) \mathcal{O}(n) O(n)。 - 空间复杂度:原地算法,没有开辟新的空间,空间复杂度是个常数 O ( 1 ) \mathcal{O}(1) O(1)。
27. 移除元素 Remove Element
- 难度:简单
- 这个题在
26
之后,但是显然需要绕的弯没有26
题多,于是做完26
再做27
,就不会觉得有过多的障碍。 - 题目:给你一个数组
nums
和一个值val
,你需要 原地 移除所有数值等于val
的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O ( 1 ) \mathcal{O}(1) O(1) 额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 - 注意点:
- 1.这个题的
j
同样是从0
开始遍历的。不过这一题的i
是也是要从0
开始遍历,因为第一个元素同样有可能满足nums[0] == val
,这种情况下是要移除的。 - 2.这里为什么是
j++
呢,主要是发现了一个不等于val
的值,需要先直接修改其值再移动。一般来说j++
比++j
的出现次数多,所以想前者比较自然,后者需要多思考一会。
class Solution {
public int removeElement(int[] nums, int val) {
int j = 0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=val){
nums[j++] = nums[i];
}
}
return j;
}
}
- 时间复杂度:同
26
题,使用for
循环遍历了一遍,所以时间复杂度是 O ( n ) \mathcal{O}(n) O(n)。 - 空间复杂度:原地算法,也没有开辟新的空间,空间复杂度是个常数 O ( 1 ) \mathcal{O}(1) O(1)。
- 这一期的总结:
- 1.去重之类的题可以用快慢指针遍历解决;
- 2.细节要非常注意!26题要注意从何处开始比较,以及最后一个元素在循环中实际上是没有包含的,所以要加一个返回。边界条件比较烦,很容易做错。