说到数据结构中的单链表,我们可以想到很多关于此结构的问题,这篇文章主要总结了几个关于用同一种方式——快慢指针来解决的问题~
一、第一题——返回链表的中间结点
题目要求:
解题思路:
& 利用快慢指针,快指针每次走两步,慢指针每次走一步
& 最后返回慢指针
& 注意,循环条件时,fast != NULL && fast->next != NULL,因为存在结点数目是奇数还是偶数的情况
代码实现:
ListNode* middleNode(ListNode* head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
二、第二题——返回链表中的倒数第k个结点
输入一个链表,输出该链表中倒数第k个结点
解题思路:
& 和上一题的思想还是一样利用快慢指针来求解
& 特殊情况考虑:当结点为空或者k<0的时候,都应该返回空
& 首先让快指针先走k-1步
& 然后同步走
& 最后返回满指正的值
代码实现:
ListNode*
FindKthToTail(ListNode* pListHead, unsigned int k) {
if(pListHead == 0 || k<=0)
return NULL;
ListNode* fast = pListHead;
ListNode* slow = pListHead;
for(int i = 0;i<k-1;i++)
{
if(fast->next != NULL)
{
fast = fast->next;
}
else return NULL;
}
while(fast -> next != NULL)
{
fast = fast ->next;
slow = slow->next;
}
return slow;
}
三、第三题——判断是否为回文结构
解题思路:
& 利用快慢指针,第一步设置一个快指针和慢指针
& 快指针一次走两步,慢指针一次走一步,当快指针下一步为null的时候说明慢指针已经走了一半,这样就可以找到中间结点
& 再反转中间链表后面的指针
& 再从头到尾向中间扫描,对比每个元素是否相等,如果都相等就是回文数,否则不是回文数
代码实现:
bool
chkPalindrome(ListNode* A) {
if(A == NULL)
return false;
else if(A->next == NULL)
return true;
//快慢指针找出中间结点
ListNode* fast = A;
ListNode* slow = A;
while(fast != NULL && fast->next!= NULL)
{
fast = fast->next->next;
slow = slow->next;
}
//反转
ListNode* p = slow->next;
ListNode* p1 = p->next;
while(p != NULL)
{
p->next = slow;
slow = p;
p = p1;
p1 = p1->next;
}
//比较
while(A != slow)
{
if((A->val) != (slow->val))
{
return false;
}
else
{
if(A->next == slow)
{
return true;
}
A = A->next;
slow = slow->next;
}
}
return true;
}
四、第四题——判断链表中是否有环
解题思路:
& 采用快慢指针的方式,想象成两个运动员,如果相遇了则表示有环存在
代码实现:
bool hasCycle(ListNode *head) {
if(head == NULL)
return NULL;
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
return true;
}
return false;
}
五、第五题——返回链表入环的第一个结点
解题思路:
& 注意!上一题我们的求解过程中,环的相遇点不一定是环的起点
& 根据规律,我们可以用数学公式推导出来,非环部分的长度+环起点到相遇点之间的长度就是环的整数倍。这意味着两个指针从相遇点再走x距离就刚刚走了很多圈,也就意味着如果从相遇点再走x就到了环的起点
& 怎么才能走x步呢?——让一个指针从头开始走,另一个指针从相遇点开始走,等两个指针相遇那就走了x步,此时就是环的起点
代码实现:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
{
fast = head;
while(fast != slow)
{
fast = fast->next;
slow = slow->next;
}
return fast;
}
}
return NULL;
}