力扣刷题笔记:环形链表 ll(双指针法不是哈希)

这个题目出就让人很难受,如果不用哈希表的话有点难解,有点像小学的跑步相遇的数学题,虽然说题目将单链表的特性展现的非常好,但是这个题目做起来的过程相当让人感觉无语。

leetcode.142 环形链表 ll
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。
力扣刷题笔记:环形链表 ll(双指针法不是哈希)_第1张图片
其实让我们判断这个链表是不是一个环非常简单,我们设置步长不同的两个指针移动,如果是个环的话他们就一定会相遇,相当于两个人在操场上跑步,一个人速度快2m/s,一个人速度慢1m/s,保持匀速跑动,速度慢的一定会被速度快的套圈追上。
但是我一直没想到怎么找到最初的那个结点,评论和网上资料什么z+n(x+y)什么的看的人云里雾里,最后发现其实很简单就是小学数学题。
将两个指针看作两个在类似这个链表的跑道上跑步的人,一个人速度快2m/s,一个人速度慢1m/s,设第 t 秒后他们相遇了,此时跑的慢的人跑了 t 米,跑的快的人跑了2t 米,也就是说跑的快的人比跑的慢的人多跑的 t 米,因为他们在跑道上相遇,所以如果一个人在相遇点再跑 t 米就会回到这个点。
这个问题瞬间就简单了,相遇点绕一圈再到相遇点的距离是 t 米,起始点跑到相遇点的距离也是 t 米,那么我们只要保持速度都是1m/s,那么我们再次相遇的地方就是最初的结点。
力扣刷题笔记:环形链表 ll(双指针法不是哈希)_第2张图片
我图画完发现写的有点不对,我这里写的速度相等其实应该是都保持单位速度,也就是一个结点一个结点的移动,不然有可能会跳过O点。
代码附上:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *fast = head;
        ListNode *slow = head;
        if(head == NULL )
        { return head;}
        while(fast != NULL)
        {
            fast = fast->next != NULL?fast->next->next:fast->next;
            slow = slow->next;
            if(slow == fast)
            {
                slow = head;//找到相遇点后退出
                break;
            }
        }
        if(fast == NULL)//如果没有环,指针末尾会指向空处
        {return NULL;} 
        else
        {
            while(slow != fast)
            {
                slow = slow->next;
                fast = fast->next;
            }
            return fast;
        }       
    }
};

你可能感兴趣的:(leetcode,c++)