双指针:可以将其分成快慢指针和左右指针,两者有不一样的应用场景。
快慢指针:主要是用于一些判断链表问题的,比如说判断当前的链表是否包含有环存在,这些题目往往使用单个指针是很难解决的。
//判断当前的链表是否有环
struct ListNode{
struct ListNode *next;
int val
};
bool hasCycle(ListNode* head)
{
ListNode fast, slow;
fast = slow = head;
while(fast != NULL && fast -> next != NULL) {
fast = fast -> next -> next;
slow = slow -> next;
if(fast == slow) return true;
}
return false;
}
假如需要找到当前链表环的入口节点的话,我们只需要在第一次快慢指针相遇的时候记录下来,然后让其中的一个指针指向head指针,再次循环到两个指针再次相遇即可!原理如下:
因为快指针每次移动的速度是慢指针的两倍,那么在第一次相遇的时候,假设慢指针走了k步,那么快指针就走了2k步,对应的快指针比慢指针多走的步数即为环的长度,也就是不管快慢指针在环的什么地方相遇,第一次相遇的时候都是多出来的刚好是对应的环的长度,现在假设相遇的点离环的入口的长度为m,那么慢指针举例head的距离则为 k - m的长度,然而环的长度为k,满指针距离当前点的距离也仍然是k-m的长度值,所以只需要将其中的任何一个指针再次指向初始的节点,另外一个指针的位置不改变,然后直接一步一步的向下走,下一次相遇的位置就是环的入口!
//求解当前环的入口指针
bool detectCycle(ListNode* head)
{
ListNode fast, slow;
fast = slow = head;
while(fast != NULL && fast -> next != NULL) {
fast = fast -> next -> next;
slow = slow -> next;
if(fast == slow) break;
}
slow = head;
while(slow != fast) {
slow = slow -> next;
fast = fast -> next;
}
return slow ;
}
3.求解链表的中点:
ListNode slow, fast;
slow = fast = head;
while(fast != NULL && fast -> next != NULL) {
fast = fast -> next -> next ;
slow = slow -> next ;
}
return slow;
//就是让其中的快指针先走两步,满指针走一步,当其中的快指针到达末端的时候,慢指针刚好在中间节点处。
4.寻找链表中的倒数第k个元素:
一样的是使用对应的快慢指针的方法,让其中的快指针先走k步,然后同时遍历其中的快慢指针,当其中的快指针到达对应的末端的时候慢指针就达到对应的中间节点处。代码实现很简单!
左右指针的常见算法:
待续…