今天我来分享下算法中的双指针
概念:
双指针是一种常见的算法技巧,通常用于解决数组和链表相关的问题的。
它通过使用两个指针来遍历数据结构,从而在一次遍历中完成某些任务,提高了效率。
注意这里的指针,可不是C语言常说的那种指针,而是更多的用下标来表示
那么常见的双指针有两种形式:对撞指针,快慢指针
对撞指针:
一般用于顺序结构中,也称左右指针
1.对撞指针从两端向中间移动。一个指针从最左端开始,一个指针从最右端开始,然后逐渐往中间逼近
2.对撞指针的终止条件一般是两个指针相遇或者错开(也有可能在循环内部找到结果,就跳出循环直接返回了)
相遇:left==right
错开:left>right
注意这里的left 和 right指的是下标
快慢指针:
又称为龟兔赛跑指针,其基本思想就是使用两个移动速度不同的指针在数组或链表等序列结构上移动。
这种方法对于处理环形链表或数组非常有用。
当然,如若处理的问题也有像是出现循环往复的情况时,也是可以考虑快慢指针的思想
其中常见的实现方式:
在一次循环中,每次让慢的指针向后移动一位,而快的指针往后移动两位,实现一快一慢。
所以,总的来说,就是双指针就是可以在一些遍历过程的时候,优化遍历结构,从而提高代码运行效率。
下面用两道题来拓展下对撞指针和快慢指针吧。
对撞指针:
看到这道题,我们一般会想到枚举的方式,类似一种暴力破解的方法
类似于这样:
其实一般情况下是可以解决的,但是一旦数据量大了之后,就不好说了
所以在这道题中呢,用这种解法是超时的。
所以我们用这个对撞指针来解决下
代码:
public int[] twoSum(int[] price, int target) {//思路:使用双指针算法、暴力解法(超时)//首先,让right和left下标对应的值,相加,然后呢,如若小于这个target//那么left++;否则right--。等于返回数组这两个下标对应的值int left =0;int right=price.length-1;int [] arr=new int[2]; while(left < right){if(price[left]+price[right]<target){left++;}else if(price[left]+price[right] > target){right--;}else{arr[0]=price[left];arr[1]=price[right];break;}}return arr;}
注意,返回的类型是int [],所以我们返回值也得是对应的类型。
快慢指针:
这道题意思是:
所以可以看到这里是成环了,使用下快慢指针
我们首先要求出这个82怎么求
设置一个sumPow()方法来其对应的值
那么其实也是挺简单的,用一个sum+=数字位数上的平方值
比如19,有两位,那么先求个位平方,那么可以19%10=9
sum+=9*9
然后19/10=1
得到十位上的数字
那么再次sum+=1*1,这样就得出了82了
那么回到快慢指针上
先定义一个slow、fast指针
那么这个指针的值,即slow=sumPow()方法求出每一步的值,fast因为要走两步,所以fast=sumPow(sumPow())
我们可以先让slow一次走一步,fast一次走两步
最后,fast进入环,slow也在一个环中且相遇的时候,判断下fast/slow的值是否等于1即可
代码:
public int sumPow(int n){int sum=0;while(n!=0){int t=n%10;sum+=t*t;n/=10;}return sum;}public boolean isHappy(int n) {//思路,使用快慢指针法//在这个快乐数中,当按照题目的走法,即n=19,此时最后会走到1,//而1会一直循环,即成环了,而且环中都是1,如若n=2//那么走到后面也会成环,但环中不会出现1,所以这个是不符合题目要求的 //所以判断下成环的时候里面的值是否为1 int slow =n;//这里要fast多走一步,是因为要进入循环内,//如若一开始都是fast=slow,就不进入循环int fast=sumPow(n);while(slow!=fast){slow=sumPow(slow);fast=sumPow(sumPow(fast));}return fast==1;}
}
完!