前言
作为一个刚刚开始接触算法的小白,在刚刚开始的leetcode之路上,选择了方法较为多的数组作为起点。在经过不少题目的摧残之后,发现很多题目都用到了一种相同的方法--双指针,因此这篇文章诞生的目的就是总结一下近期认识到的双指针用法,加以巩固。
双指针是什么
在我的理解里,双指针就是下标,索引的概念,而不是指在数据结构中的指针概念,双指针就是在遍历的过程中使用两个指针进行动态的扫描。
双指针的用法
双指针就是定义两个指针进行遍历,因此我们可以根据不同的题目需求去设置两个指针的起始位置、运动速度、方向等。双指针也多用于数组,链表等链式结构。
两层循环
如leetcode的第一题两数之和,在一个数组中找到两个数的和为目标值。
在这个题目中,就可以使用到双指针最常用的方法双指针遍历,
定义:外层循环指针 i, 内层循环指针 j,需要得到的值target,得到的数组arr
i的初始值设置为0,j的初始值设置为 i + 1,
如何进行循环,判断是否存在 arr[i] + arr[j] == target
存在就输出 [i, j], 否则就不存在。
for(let i=0;i<nums.length;i++){
for(let j=i+1;j<nums.length;j++){
if(nums[i] + nums[j] == target){
return [i,j]
}
}
}
return []
};
对撞指针
对撞指针就是使双指针中指针的初始化位置,一个指针在数组的头部,一个指针在数组的尾部。让它们不断的向中间靠拢,直到碰撞到一起(下标相同),多用于有序数组
var numRescueBoats = function(people, limit) {
people.sort((a, b) => (a - b));
var num = 0
let left = 0
let right = people.length - 1
while (left <= right) {
if ((people[left] + people[right]) <= limit) {
left++
}
right--
num++
}
return num
};
快慢指针
快慢指针就是设置指针的移动速度,让一个指针缓慢移动,一个指针快速移动,比如快指针一次走两步,慢指针一次走一步。快慢指针在针对成环问题很有效果,如果一个链表成环,那么两个指针终有一天会重合。
如leetcode141环形链表,给定一个头节点,判断在链表中是否有环。
这道题目就很适合使用快慢指针的方法,设置快指针一次走两步,慢指针一次走一步,这样如果链表中存在环,那么快指针一定会有先进入环内,并且在环内不断绕圈,等待着慢指针的到来,与其相遇。如果不存在环,慢指针就永远追不上快指针,它们也不会相遇,因此判断两个指针是否相遇就能判断是否成环。
if(head == null || head.next == null){
return false;
}
let fast = head.next;
let slow = head;
while(fast != slow){
if(fast == null || fast.next == null){
return false;
}
fast = fast.next.next;
slow = slow.next;
}
return true;
};
总结
关于双指针的方法还有很多,应该针对不同的问题去设置指针的各个属性。碰到有序数组时应该优先考虑双指针,以减少时间复杂度和空间复杂度。