【LeetCode】—— 链表套路之快慢指针

快慢指针

  • 快慢指针中的快慢指的是移动的步长,即每次向前移动速度的快慢。例如可以让快指针每次沿链表向前移动2,慢指针每次向前移动1次。

快慢指针在链表中的应用

一、环形链表(LeetCode141题)

解题思路
  • 如果链表存在环,就好像操场的跑道是一个环形一样。此时让快慢指针都从链表头开始遍历,快指针每次向前移动两个位置,慢指针每次向前移动一个位置;如果快指针到达NULL,说明链表以NULL为结尾,没有环。如果快指针追上慢指针,则表示有环。
代码实现:
bool hasCycle(struct ListNode *head) {
    if(head == NULL || head->next == NULL)
        return false;
    
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    
    while(fast != NULL && fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
        
        if(fast == slow)
            return true;
    }
    return false;
    
}

二、链表中间节点(LeetCode876题)

解题思路
  • 定义两个指针,一个快指针fast,一个慢指针slow,快指针一次走两步,慢指针一次走一步,当快指针走到最后,慢指针正好走在中间的位置,此时返回慢指针所在位置即可,注意当链表为空时直接返回头结点即可。
代码实现
struct ListNode* middleNode(struct ListNode* head) {
    if(head == NULL || head->next == NULL)
        return head;
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    while(fast != NULL && fast->next !=NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;  
}

三、删除链表倒数第N个节点(LeetCode19题)

解题思路
  • 定义两个指针,一个快指针fast,一个慢指针slow,让快指针先走n步,再让快慢指针一起走,当快指针走到链表最后,慢指针正好走在链表的倒数第n-1个位置,此时删除slow指针的后一个值,即删除了链表第n个位置的值,再考虑一些特殊情况,比如链表只有一个值时,可让slow->next = slow->next->next,删除之后,这时链表为空。
代码实现
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
     int i=0;
    struct ListNode* slow,* fast = head;
    slow = (struct ListNode*)malloc(sizeof(struct ListNode));
    slow->next = head;
    while(i < n)
    {
        fast = fast -> next;
        i++;
    }
    while(fast != NULL)
    {
        fast = fast -> next;
        slow = slow -> next;
    }
    if(slow -> next == head)
        return head -> next;
    else
        slow->next = slow->next ->next;
        return head;
}

四、环形链表II(LeetCode142题)

解题思路
  • 有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环。
  • 如何判断一个链表是否存在环?设定两个指针slow,fast,均从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
  • 如果链表存在环,如果找到环的入口点?当fast若与slow相遇时,slow肯定没有走遍历完链表或者恰好遍历一圈。于是我们从链表头与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。

环形链表

代码实现
 class Solution {
    public:
        ListNode * hasCycle(ListNode *head) {
            ListNode* fast = head;
            ListNode* slow = head;
            
            while(fast && fast->next)
            {
                fast = fast->next->next;
                slow = slow->next;
                
                if(slow == fast)
                {
                    return fast;
                }
            }
            
            return NULL;
        }
        ListNode *detectCycle(ListNode *head) {
            
            ListNode* meet = hasCycle(head);
            //如果meet为空,说明不存在环
            if(meet == NULL)
            {
                return NULL;
            }
            else
            {
                while(1)
                {
                    //meet从slow和fast相遇的点开始走,head从头开始走
                    //如果二者相遇则返回这个相遇的交点
                    if(meet == head)
                        return meet;
                    else
                    {
                        meet = meet->next;
                        head = head->next;
                    }
                }
            }
        }
    };

五、相交链表(LeetCode160题)

可参考博主博文:有详细的解析

LeetCode相交链表解析

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值