双指针
什么是双指针(对撞指针、快慢指针)
双指针,指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。
换言之,双指针法充分使用了数组有序这一特征,从而在某些情况下能够简化一些运算。
双指针比较灵活,可以大大降低时间复杂度,可用在数组,单链表等数据结构中。
对撞指针(首尾指针,左右指针)
对撞指针是指在有序数组中,将指向最左侧的索引定义为左指针(left),最右侧的定义为右指针(right),然后从两头向中间进行数组遍历。
对撞数组适用于有序数组,也就是说当你遇到题目给定有序数组时,应该第一时间想到用对撞指针解题。
快慢指针
快慢指针也是双指针,但是两个指针从同一侧开始遍历数组,将这两个指针分别定义为快指针(fast)和慢指针(slow),两个指针以不同的策略移动,直到两个指针的值相等(或其他特殊条件)为止,如fast每次增长两个,slow每次增长一个。
删除有序数组中的重复项
这是第一次碰到双指针,原地删除让我思考了很久要怎么做到不用新的数组又能判断重复
后面看题目 数组升序排列 那么如果num[i+1]-num[i]=0则说明数字重复 当然 可能有N个相同的数字
即 对于[a,b]中如果num[a]=num[b] 则中间的数都是相等的
所以这时候双指针出场了
我们用快指针表示遍历到的数组下标位置,而慢指针左边是处理好的数组,它的下一个位置则是要插入新数据的位置
当快指针的位置上的数字与慢指针上的数据不相等时则将快指针上的数据插入,并移动两个指针
class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
int fast =1,slow=0;
while(fast<n){
if(nums[fast]!=nums[slow]){//如果两个指针指向的数据不相等则将新数据插入
if(fast - slow > 1){
nums[slow+1] = nums[fast];
}
slow++;
}
fast++;
}
return slow+1;
}
}
移除元素
和上一题一样,换汤不换药
当快指针扫到的下标位置上的值不等于val时插入慢指针下一个位置
class Solution {
public int removeElement(int[] nums, int val) {
int slow=0;
int fast=0;
int length=nums.length;
while(fast<length){
if(nums[fast]!=val ){
nums[slow]=nums[fast];
slow++;
}
fast++;
}
return slow; }
}
汇总区间
用慢指针指向区间起始位置 快指针扫描,当快指针指向的下一个位置不满足+1时说面区间结束,记录区间,慢指针移到下一个区间起始位置。
class Solution {
public List<String> summaryRanges(int[] nums) {
List<String> listAns = new ArrayList<String>();
int left=0,right=0;
for(int i=1;i<nums.length;i++){
if((nums[i]-nums[i-1])==1 && (i)<nums.length){
right++;
continue;
}
if(left==right){
listAns.add(String.valueOf(nums[left]));
left++;
right++;
}else{
listAns.add(nums[left]+"->"+nums[right]);
right++;
left=right;
}
}
return listAns;
}
}
移动零
不复制数组、原地对数组操作 并且也要保持非零元素的相对顺序
慢指针的左边记录处理好的非零元素 慢指针指向零元素 当快指针扫描秒到一个非零元素时就与当前的慢指针所指零元素交换位置 慢指针再指向下一个零元素
class Solution {
public void moveZeroes(int[] nums) {
int left=0;
int right = 0;
while(right<nums.length){
if(nums[right]!=0 ){
int t =nums[right];
nums[right] =0;
nums[left]=t;
left++;
}
right++;
}
}
}
对撞指针
对撞指针是指在有序数组中,将指向最左侧的索引定义为左指针(left),最右侧的定义为右指针(right),然后从两头向中间进行数组遍历。
搜索插入位置
二分典中典
从头尾找到中间位置的数,如果目标值大于中间的数则头指针指向中间位置,小于则尾指针指向中间位置并再次找到中间位置判断
直到找到目标值或尾指针小于头指针返回其索引或插入位置
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0;
int right=nums.length-1;
int center=0;
while(right>=left){
center=(right+left)/2;
if(nums[center]>target){
right=center-1;
}
if(nums[center]<target){
left=center+1;
}
if(nums[center]==target){
return center;
}
}
return right+1;
}
}
总结
什么时候可以考虑用双指针
-
有序数组
-
要求不使用额外空间原地处理数据
[center]==target){
return center;
}
}
return right+1;
}
}
### 总结
什么时候可以考虑用双指针
1. 有序数组
2. 要求不使用额外空间原地处理数据
##