当前位置 博文首页 > Inmaturity_7的博客:408计算机考研--数据结构--快慢指针学习(C

    Inmaturity_7的博客:408计算机考研--数据结构--快慢指针学习(C

    作者:[db:作者] 时间:2021-07-16 21:46

    快慢指针学习(C语言指针)

    一、判断环形链表

    1.1、题目描述

    给定一个链表,判断链表中是否有环。

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

    进阶:
    你能用 O(1)(即,常量)内存解决此问题吗?
    

    示例 1:

    在这里插入图片描述

    输入:head = [3,2,0,-4], pos = 1
    输出:true
    解释:链表中有一个环,其尾部连接到第二个节点。
    

    示例 2:
    在这里插入图片描述

    输入:head = [1,2], pos = 0
    输出:true
    解释:链表中有一个环,其尾部连接到第一个节点。
    

    示例 3:
    在这里插入图片描述

    输入:head = [1], pos = -1
    输出:false
    解释:链表中没有环。
    
    提示:
    链表中节点的数目范围是 [0, 104]
    -105 <= Node.val <= 105
    pos 为 -1 或者链表中的一个 有效索引 。
    
    1.2、解决方法–快慢指针(若链表有环必相遇)
    bool hasCycle(struct ListNode* head) {
        if (head == NULL || head->next == NULL) {//排除不可能的情况
            return false;
        }
        struct ListNode* slow = head;//慢指针:每次走一步
        struct ListNode* fast = head->next;//快指针:每次走两步
        while (slow != fast) {//当两个指针不相遇说明不成环
            if (fast == NULL || fast->next == NULL) {//如果到链表尾直接跳出
                return false;
            }
            slow = slow->next;
            fast = fast->next->next;
        }
        return true;
    }
    

    二、扩展

    题目描述:设计一个算法完成以下功能:判断一个链表是否有环,如果有,找出环的入口点并返回,否则返回NULL。
    算法的基本思想:设置快慢两个指针分别为fast和slow,初始时都指向链表头head。slow每次走一步,即slow=slow->next;fast每次走两步,即fast=fast->next->next。由于fast比slow走得快,如果有环,那么fast一定会先进入环,而slow后进入环。当两个指针都进入环后,经过若干操作后两个指针定能在环上相遇。这样就可以判断一个链表是否有环。假设链表未成环的长度为a,快慢指针相遇在环中的地方离环的入口长度为x,且此时慢指针是第一次进入,而快指针已经在环中转了n圈(环长为r),于是由快慢指针两倍速度的关系有:2(a+x)=a+nr-x;于是推出a=n*r-x。那么如果我们同时让两个指针分别从头结点和快慢指针相遇的结点出发,则这两个指针会在环入口相遇。
    代码实现

    LNode*FindLoopStart(LNode *head){
    	LNode *fast=head,*slow=head;//设置两个快慢指针
    	while(slow!=NULL&&fast->next!=NULL){
    		slow=slow->next;//每次走一步
    		fast=fast->next->next;//每次走两步
    		if(slow==fast) break;
    	}
    	if(slow==NULL||fast->next==NULL)
    		return NULL;//没有环,返回NULL
    	LNode  *p1=head,*p2=slow;//分别指向开始点,相遇点
    	while(p1!=p2){
    		p1=p1->next;
    		p2=p2->next;
    	}
    	return p1;//返回入口点
    }
    
    cs