题目:
移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
此题有暴力解法和双指针法。一个时间复杂度是O(N^2),一个是O(N)
双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。
双指针思想是有两个指针,一个是快指针,一个是慢指针,在外层for循环用快指针遍历整个数组,而慢指针的移动是受限的,在此题中,他受限于快指针,只有快指针指向的元素不是目标元素才能移动慢指针。会出现以下几种情况:
- 快慢指针指向同个元素,并同时一起移动。出现在共同指向的元素是非目标元素。若指向同个元素却只有快指针移动则说明共同指向的元素是目标元素
- 快指针移动,慢指针不移动。此时可能是慢指针指向的是目标或非目标元素,但快指针必定指向非目标元素。一起移动又指向不同元素则是相反情况。
总结下就是,慢指针相当于维护了一个没有目标值的数组,只有当快指针找到下一个非目标值,他才会进行扩展。
class Solution {
public int removeElement(int[] nums, int val) {
int slowIndex=0;
int fastIndex=0;
for(fastIndex=0; fastIndex<nums.length; fastIndex++){
if(nums[fastIndex] != val){
nums[slowIndex] = nums[fastIndex];
slowIndex++;
}
}
return slowIndex;
}
}
题目:
删除有序数组中的重复项(错题)
这题的跟第一题不太一样,由于判断重复项至少要两个以上才能判断出来,所以这题的快指针起点比慢指针多1个位置。慢指针移动条件是当前的慢指针与快指针不一样(慢指针必然是目前新数组最大的点),快慢指针的元素不一样代表着找到了下一个属于新数组的元素,慢指针的下一位就要赋值为这个新的值。
class Solution {
public int removeDuplicates(int[] nums) {
int fastIndex = 1;
int slowIndex = 0;
boolean flag = true;
for(; fastIndex<nums.length; fastIndex++){
if(nums[slowIndex] != nums[fastIndex]){
nums[++slowIndex] = nums[fastIndex];
}
}
return slowIndex+1;
}
}
题目:
比较含退格的字符串(不会做)
对于双字符串,双数组使用双指针法,一般是在两个数组上分别有一个指针,在此题中,倒序遍历是更好的方法,因为在前面的字符会被未知数量的后退符删除。当倒序遍历时,我们可以在大循环遍历,每次挑选出两个数组待比较的数进行比较,两个小循环找出待比较的数(去掉了回退符,被删除的数字)。
public boolean backspaceCompare(String s, String t) {
int t1 = s.length()-1;
int t2 = t.length()-1;
int num1 = 0;
int num2 = 0;
while(t1 >= 0 || t2 >= 0){
while(t1 >= 0){
if(s.charAt(t1) == '#'){
t1--;
num1++;
}else if(num1 > 0){
num1--;
t1--;
}else{
break;
}
}
while(t2 >= 0){
if(t.charAt(t2) == '#'){
t2--;
num2++;
}else if(num2 > 0){
num2--;
t2--;
}else{
break;
}
}
if (t1 >= 0 && t2 >= 0) {
if (s.charAt(t1) != t.charAt(t2)) {
return false;
}
} else {
if (t1 >= 0 || t2 >= 0) {
return false;
}
}
t1--;
t2--;
}
return true;
}