DS:经典单链表题目-判断相交与带环,环入口节点,环长度问题详解

本文深入探讨链表相交节点的查找,环形链表的判断及环入口节点的定位,提供高效算法实现,助您掌握链表核心操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

判断链表相交

编写一个程序,找到两个单链表相交的起始节点。

如下面的链表:

在这里插入图片描述
在节点 c1 开始相交。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
对,这里单链表是不存在"X"型相交的因为单链表的节点只能指向一个地址,所以只有"Y"型和"V"型
所以可以先分别求出两个链表的长度,然后求出它们的长度差将长的那个链表进行访问,直到剩余长度与短链表一样时,开始同时访问并判断各自节点的地址是否相同,第一个地址相同的节点就是我们要找的交点,如果直到NULL都没有找到,说明这两个链表并不相交:
具体实现:

int getlongth(struct ListNode *target){
    int count =0;
    while(target!=NULL){
        count++;
        target = target->next;
    }
    return count;
}
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode* LongHead;
    struct ListNode* shortHead;
    int lenA = getlongth(headA);
    int lenB = getlongth(headB);
    int cha = 0;
    if(lenA>=lenB){
        cha = lenA-lenB;
        LongHead = headA;
        shortHead = headB;
    }
    else{
        cha = lenB-lenA;
        LongHead = headB;
        shortHead = headA;
    }
    for(int i = 0;i<cha;i++){
        LongHead = LongHead->next;
    }
    while(LongHead!=shortHead){
        shortHead = shortHead->next;
        LongHead = LongHead->next;
        if(!LongHead){
            return NULL;
        }
    }
    return LongHead;
}

判断链表是否带环(要求时间复杂度为O(1))

示例 :
在这里插入图片描述
链表中有一个环,其尾部连接到第二个节点。
这里我们要明白,带环链表是没有尽头的,它会一直死循环下去,我们假设它是一条奇怪的格子赛道,将两个指针比作运动员A和运动员B,A的脚程一次一格,B的是一次两格,当比赛开始,B一马当先,按理说他应该会先到达终点,但这个赛道是没有尽头的,他将在环里一直跑下去,过了一会,A也来了,他们将在环里相遇,据此我们可以设置快慢两个指针,当开始后快的那一个不是先等于NULL而是和慢指针的地址相同时,就可以确定是环形列表了
具体实现:

bool hasCycle(struct ListNode *head) {
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    if (!head){
        return false;
    }
    while(1){
        fast = fast->next;
        if(fast==NULL){
            return false;
        }
        slow = slow->next;
        fast = fast->next;
        if(fast==NULL){
            return false;
        }
        if(fast==slow){
            return true;
        }
    }
}

这里你可能会奇怪,fast比slow走的快就行了,可以是其他的步数吗?当然可以,但注意,某些组合在特殊场景下是它们之永远无法相遇的:假设快指针一次三格,慢指针一次一格,当这个环形赛道只有两格时,他们将永远不在一格上


求链表带环时环的入口节点

不可以修改链表
按照上面的算法,我们似乎只能找到快慢两指针相遇的位置,这个位置当然不会一定在入口处,那麽我们该如何确定呢?
在这里插入图片描述
我们假设链表从头节点到入口的距离是x,从入口到相遇点的距离是y,而链表的长度是d,当快慢指针相遇时:

慢指针快指针
路程x+y+n*d2(x+y+n*d)
也就是>x+y+(k*d)

我们将快指针的两个式子等立得到:x=h*d-y;(h=k-2n)从头结点到环入口的距离等于从相遇点到环入口再加上h-1倍的环长度;所以我们可以说当两个指针分别从从相遇点和头节点出发,那么它们必然会在入口点相遇:
具体实现:

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    if (!head){
        return NULL;
    }
    while(1){
        fast = fast->next;
        if(fast==NULL){
            return NULL;
        }
        slow = slow->next;
        fast = fast->next;
        if(fast==NULL){
            return NULL;
        }
        if(fast==slow){
            break;
        }
    }
    struct ListNode *n1 = head;
    struct ListNode *n2 = slow;
    while(n1!=n2){
        n1 = n1->next;
        n2 = n2->next;
    }
    return n2;
}

求环长度

有了前面的基础,这里实现起来非常简单,我们可以任意选择环入口节点或相遇节点,用一个指针记录当前位置,再使用另一个指针进行遍历同时记录步数,这两个指针相等时,步数就是环的长度:
具体实现

int GetCyclLongth(struct ListNode *pow)
{
   int count = 1;
   for(struct ListNode*go = pow;go->next!=pow;go =go->next,count++)
   {;}
   return count;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值