您的位置:首页 > 其它

链表中的一些问题——快慢指针

2016-11-03 13:44 232 查看
如果需要判断一个链表是否循环,或者是否带环,或是单向的链表求中位数、倒数第n个数,可以用到快慢指针以达到最简单的方法。

判断链表是否带环

可以用两个指针p1,p2均指向头结点,p1每移动一次,p2遍历整个链表,查找是否有与p1地址相等的位置。

//链表定义
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};


bool doesExistLoop(ListNode *pHead)
{
ListNode *p1, *p2;
p1 = p2 = pHead;
while (p1->next)
{
while (p2->next)
{
p2 = p2->next;
if (p2 == p1) return true;
}
p1 = p1->next;
}
return false;
}


此种方法时间复杂度为O(n^2),效率比较低。下面介绍一种经典的、效率高一些的方法——快慢指针。

快慢指针的思路很简单,就好像两个人在赛跑,一个跑得快一个跑得慢。如果跑的是环形跑道,时间足够长的话,跑得慢的总会被套圈,即他俩的位置总有一个时间是冲个的;反之如果跑道是一条直线的话,俩人位置是永远不会重合的。

应用到这个问题中,可以设置两个指针p1,p2,p1每次向后走一步,p2每次向后走两步,若两个指针能够重合,就说明链表是带环的。

bool doesExistLoop(ListNode *pHead)
{
ListNode *fast, *slow;
fast = slow = pHead;
while (fast)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}
return false;
}


这种方法时间复杂度是O(n),效率会比第一种方法高不少。

如果链表带环,如何找环的入口

思路如下:先利用上边寻找环的方法,当快慢指针相遇的时候,一个指针从头开始,另一个从相遇的地方开始,两个同步走,下一次相遇的地方一定是入口(不知道什么原理,但是亲自试了几个后发现真是……)

ListNode* findLoopPort(ListNode *pHead)
{
ListNode *fast, *slow;
fast = slow = pHead;
while (fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow) break;
}
if (fast == NULL&&fast->next == NULL) return NULL;
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return fast;
}


在有序链表中寻找中位数

若不借助计数器变量实现查找中位数的功能,快慢指针也是最好的选择。让快指针的速度保持为慢指针的两倍,这样当快指针达到链表最后的时候,慢指针正好到达链表的中间。注意判断链表有奇数个节点还是偶数个节点,若奇数个节点,则慢指针的值就是所求;若偶数个节点,则慢指针和慢指针下一个的值的平均数就是所求。

int findMiddle(ListNode *pHead)
{
ListNode *fast, *slow;
fast = slow = pHead;
while (fast)
{
if (fast->next == NULL) return slow->val;
else if (fast->next == NULL&&fast->next->next == NULL) return (slow->val + slow->next->val) / 2;
else
{
fast = fast->next->next;
slow = slow->next;
}
}
}


返回链表中倒数第n个数

保持快指针的速度比慢指针快n即可。

ListNode* lastButOne(ListNode *pHead)
{
ListNode *fast, *slow;
if (!pHead || !pHead->next || !pHead->next->next) return NULL;
fast = pHead->next->next;
slow = pHead;
while (!fast->next)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: