【专题】链表中的双指针问题

一、什么是双指针?

在链表中,通常设置两个指针,这两个指针每次走的长度不同,会对链表的交点等问题提供一个便捷的解决方案。
这两个指针分别称为快指针(pFast)和慢指针(pSlow)。

二、应用场景

2.1 寻找链表的中间节点

题目链接 给你单链表的头结点 head,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

(1) 解决思路

定义两个指针pFastpSlow,pFast一次走两步,pFast一次走一步。当pFast走完整个链表时,pSlow恰好走至中间节点的位置。
在这里插入图片描述

(2) 解决代码

struct ListNode* middleNode(struct ListNode* head) 
{
    struct ListNode* slow = head, *fast = head;

    while((fast != NULL) && (fast->next != NULL))
    {
        slow = slow->next;
        fast = fast->next->next;
    }   
    return slow;
}

2.2 判断两个链表是否有相交节点

题目链接 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

(1) 解决思路

分别求出两个链表的长度,记为L1L2。让长的链表走差距步(即|L1 - L2|步),随后再一起走,第一个相同的地址点就是两个链表的交点。

(2) 解决代码

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode* tailA = headA;
    struct ListNode* tailB = headB;
    int lenA = 1, lenB = 1;
    while(tailA->next)
    {
        tailA = tailA->next;
        ++lenA;
    }
    while(tailB->next)
    {
        tailB = tailB->next;
        ++lenB;
    }   

    if(tailA != tailB)
    {
        return NULL;
    }

    int gap = abs(lenA-lenB);
    struct ListNode* longList = headA;
    struct ListNode* shortList = headB;
    if(lenA < lenB)
    {
        longList = headB;
        shortList = headA;
    }

    while(gap--)
    {
        longList = longList->next;
    }

    while(longList != shortList)
    {
        longList = longList->next;
        shortList = shortList->next;
    }

    return longList;
}

2.3 判断链表是否有环。

题目链接 给你一个链表的头节点 head ,判断链表中是否有环。

  • 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意pos不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环,则返回true;否则,返回false。

(1) 解决思路

采用快慢指针来解决此问题。慢指针一次走一步,快指针一次走两步,两个指针均从链表的起始位置开始。如果链表有环,则两个指针一定会相遇;否者快指针会先走到链表的尾部。
在这里插入图片描述

(2) 解决代码

bool hasCycle(struct ListNode *head) 
{
    struct ListNode *slow = head, *fast = head;

    while((fast != NULL) && (fast->next != NULL))
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
        {
            return true;
        }
    }
    return false;
}

(3) 扩展问题

(3-1) 快慢两个指针一定会相遇?

  • 一定会。快指针会先进环,慢指针会后进环。假设慢指针进环时,慢指针和快指针之间的距离为N,慢指针进环以后快指针开始追击;慢指针每走一步,快指针走两步,它们之间的距离便会缩小1。距离变换的形式为N ->(N-1) -> (N-2) -> … -> 2 -> 1 ->0(相遇)

(3-2) 快指针每次走2、3、4……步还可以相遇吗?

  • 不一定。若快指针一次走偶数步,一定会相遇;若一次走奇数步,则不会相遇。

在这里插入图片描述

2.4 寻找链表的第一个入环节点

添加链接描述 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

  • 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。

(1) 解决思路

首先判断链表是否有环,采用上题的方式进行判断。若有环,记录快慢指针相遇的节点。让一个指针从链表起始位置开始走,另一个指针从相遇位置开始走,每次只走一步。两指针的相遇点便是链表入环的第一个节点。
在这里插入图片描述

(2) 解决代码

struct ListNode *detectCycle(struct ListNode *head) 
{
    struct ListNode* slow = head, *fast = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = slow->next->next;

        if(slow == fast)
        {
            struct ListNode* meet = slow;
            while(head != meet)
            {
                head = head->next;
                meet = meet->next;
            }
            return meet;
        }
    }
    return NULL;
}

—— writing by Pan Qifan(潘琦藩) ——

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向懒羊羊学习的大猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值