算法通关村 —— 双指针的妙用
本文针对数组删除的元素的场景,提供一些解决的方法
- 原地删除数值等于val的值
- 删除有序数组中的重复项
原地删除数值等于val的值
问题描述:提供一个数组array和一个值val,将数组中的val值移除并最后返回数组长度(不使用O(1)的额外空间,数组的顺序可以改变)
解决思路:
1、快慢指针
在数组头部设置俩指针,快指针每次+1,慢指针在array[slow] != val时+1,当array[fast] != val时,array[fast] 和 array[slow]对调;
/**
* 快慢指针,快指针每次加1,慢指针在array[fast] != val时加1
* 当array[fast] != val时,array[slow] = array[fast]
*/
public static int slowFastPoint(int[] array, int val) {
int slow = 0;
for (int fast = 0; fast < array.length; fast++) {
if (array[fast] != val) {
array[slow] = array[fast];
slow++;
}
}
return slow;
}
2、对撞指针
设置两指针left、right分别向中间靠拢(移动一步),当array[right] != val、array[slow] = val
时,双方互换,依次类推;
/**
* 对撞指针,快指针从最后出发,慢指针从头开始
* 快指针遇到非val时停下,当slow遇到val时,与fast交换,以此类推
*/
public static int collisionPoint(int[] array, int val) {
int left = 0;
int right = array.length - 1;
while (left <= right) {
if (array[right] != val && array[left] == val) {
array[left] = array[right];
array[right] = val;
}
if (array[right] == val) right--;
if (array[left] != val) left++;
}
return left;
}
3、对撞指针+覆盖
该思路也是设置left、right两指针同时靠拢,当array[left] = val 时直接与array[right]对换,此时left先不+1,而是判断交换过来的val是否等于val,再重复上步骤;
/**
* 双碰撞指针,array[left] == val时,直接array[left] = array[right],但赋值后还是从当前开始
*/
public static int cover(int[] array, int val) {
int left = 0;
int right = array.length - 1;
while (left <= right){
if (array[left] == val){
array[left] = array[right];
right--;
}else {
left++;
}
}
return right + 1;
}
删除有序数组中的重复项
问题描述:提供一个有序数组array,删除数组中重复的元素,返回最终的数组长度;(仅能用O(1)的额外空间)
解决思路:
还是使用双指针的来解决问题,slow和fast依次加1,当array[slow] = array[fast]时,slow停下,直到array[fast] != array[slow],两值互换,然后各移一步,继续上述操作;
/**
* 删除有序数组中的重复项
* */
public static int removeDuplicate(int[] array){
int slow = 1;
for (int fast = 0; fast < array.length; fast++) {
if (array[fast] != array[slow - 1]){
array[slow] = array[fast];
slow++;
}
}
return slow;
}