例题
-
给你一个数组
nums
和一个值val
,你需要原地移除所有数值等于val
的元素,并返回移除后数组的新长度。 -
不要使用额外的数组空间,你必须仅使用
O(1)
额外空间并原地修改输入数组。 -
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
双指针法
通过快慢指针在一个for
循环下完成两个for
循环的工作。
- 快指针:查找符合要求的新数组的元素,也就是需要保留的元素。
- 慢指针:指向更新后的数组下标,慢指针最后指向的下标就是新数组的大小。
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowindex = 0; // 慢指针
for(int fastindex = 0; fastindex < nums.size(); fastindex++){
if(val != nums[fastindex]){
nums[slowindex++] = nums[fastindex]; // 把快指针所在元素赋值给慢指针所在元素,慢指针后移
}
}
return slowindex; // 慢指针下标即为新数组大小
}
};
刷题
26. 删除有序数组中的重复项
将升序数组中重复出现的元素原地删除,保持元素相对顺序不变。
- 快慢指针都应该从
1
开始,因为第0
个元素无论如何都不应该被删除。 - 判断条件是快指针指向元素与其左侧那个元素不相等。
283. 移动零
将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
- 在数组中“删去”全部的
0
,即将非零元素依次移到数组开头。 - 另外写一个
for
循环,将慢指针后面的元素赋值为0
。
844. 比较含退格的字符串(难)
给定 s
和 t
两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true
。#
代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空。
- 方法一:双指针法依次比较
- 对两个字符串各用一个指针,从后向前依次遍历,把能跳过的字符跳过,然后两字符串进行比较:若不同,直接为假。
- 如此循环,直到两者中至少有一个循环到头。
- 如果两个指针同时指到
-1
,则为真,反之为假。 - 注意:这里不能直接计数有多少个
#
,就向前移动多少个字符。而要一个一个字符地判断。- 反例:
bxo#j##t
退格完成后应该是bt
,但如果从后往前遍历的过程中,计数到t
之前有2
个#
,就直接向前移到o
,则错过了j
左边的#
,而实际上它也能起到退格的作用。
- 反例:
- 方法二:双指针法模拟
- 采用模拟的手段写一个函数,返回原字符串完成退格后的字符串,然后比较
s
和t
经过处理的字符串即可。 - 与例题类似,快慢指针从前向后依次遍历,快指针找到非
#
元素就将其赋值给慢指针。 - 与例题不同的是,快指针找到
#
元素后,若慢指针大于0
,应该将慢指针回退,从而完成退格。
- 采用模拟的手段写一个函数,返回原字符串完成退格后的字符串,然后比较
977. 有序数组的平方
说明:此题是数组的第四部分,由于可以采用双指针法,就一并放到了本文。
给你一个按非递减顺序排序的整数数组 nums
,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。
- 数组
nums
是按非递减顺序排列的,所以如果所有数都是非负数,那直接按顺序平方即可,当然此题也就没有了意义,所以关键是要处理好负数。 - 这个数组类似于数轴,也就是只会在数组左右两端取得平方后的最大值,我们其实是要按照元素绝对值大小进行排序。
- 于是考虑定义左右两指针
i
j
,分别比较两边的平方值,平方值大的取出来,从后向前赋值给result
数组,然后对指针i
j
执行自增或自减操作。 - 如此循环,直到
i>j
,注意这里i==j
时仍要进入循环,否则中间剩下的这个元素就会被丢弃。