链表OJ练习二(精选OJ题-相交链表和环形链表)

前言

我们将练习一做完,下来就开始有难度的了,只有过完这关,我们的知识才有更深的理解,大家加油。

OJ练习

(1)相交链表

在这里插入图片描述

思路:如果相交,那么最后一个结点肯定相同,那么我们直接看最后一个结点相不相同,就能够判断他是否相交,然后我们再利用他们之间差的距离,我们让他们从同一起跑线出发,然后找到相交点。

代码如下

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode* curA=headA;
    struct ListNode* curB=headB;
    int lenA=0;
    int lenB=0;
    //看A有多少个结点
    while(curA->next)
    {
        lenA++;
        curA=curA->next;
    }
    //看B有多少个结点
    while(curB->next)
    {
        lenB++;
        curB=curB->next;
    }
    //判断最后一个结点是不是相同的
    //就能判断是不是相交。
    if(curA!=curB)
    {
        return NULL;
    }
    int gas=abs(lenA-lenB);
    struct ListNode* shoutList=headA;
    struct ListNode* LongList=headB;
    if(lenA>lenB)
    {
        shoutList=headB;
        LongList=headA;
    }
    while(gas--)
    {
        LongList=LongList->next;
    }
    while(LongList!=shoutList)
    {
        LongList=LongList->next;
        shoutList=shoutList->next;
    }
    return shoutList;
}

(2)环形链表<判断是否环>

在这里插入图片描述

思路:我们这道题考验的是逻辑结构,并不是我们写代码的能力,我们的数学思维,他是一个环,就是相当于一个循环链表,如果这时候我们利用速度指针,一个快指针和一个慢指针,快指针的速度是慢指针的二倍,我们等到了环中,快指针迟到会追上慢指针,所以等快指针等于慢指针的时候我们就认定这是个环。

现在思考一个问题(为什们速度是二倍,能不能是三倍或者是四倍?)
我们假设当fast进入环的时候,快慢指针之间的距离是N,所以当slow走一步的时候,fast走两步,所以他们之间的距离差一,那么他们迟早会追上。
但是当速度是三倍的时候,当fast进入环的时候,他们的距离差N,每走一步,距离就差N-2,所以如果在进入环后,差的距离是奇数,那么就永远追不上了。
bool hasCycle(struct ListNode *head) {
    struct ListNode * slow=head;
    struct ListNode * fast=head;
    struct ListNode * cur=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(fast==slow)
        {
            return true;
        }
    }
    return false;
}

(3)环形链表(判断环点的位置)

在这里插入图片描述

思路在这里插入图片描述

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

思路二:利用相交链表求解

思路,在快慢指针相遇,将其链表的下一个结点设为空指针,然后就变成了相交链表 ,下面画图解释。
在这里插入图片描述

 struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode* curA=headA;
    struct ListNode* curB=headB;
    int lenA=0;
    int lenB=0;
    //看A有多少个结点
    while(curA->next)
    {
        lenA++;
        curA=curA->next;
    }
    //看B有多少个结点
    while(curB->next)
    {
        lenB++;
        curB=curB->next;
    }
    //判断最后一个结点是不是相同的
    //就能判断是不是相交。
    if(curA!=curB)
    {
        return NULL;
    }
    int gas=abs(lenA-lenB);
    struct ListNode* shoutList=headA;
    struct ListNode* LongList=headB;
    if(lenA>lenB)
    {
        shoutList=headB;
        LongList=headA;
    }
    while(gas--)
    {
        LongList=LongList->next;
    }
    while(LongList!=shoutList)
    {
        LongList=LongList->next;
        shoutList=shoutList->next;
    }
    return shoutList;
}
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode * slow=head;
    struct ListNode * fast=head;
    struct ListNode * cur=NULL;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            //相交链表
            cur=slow->next;
            slow->next=NULL;
            struct ListNode *ret =getIntersectionNode(head,cur);

            return ret;
        }
  
    }
    return NULL;
}

(4)复杂带随机指针的链表

在这里插入图片描述

思路:对于这个问题,思路还是很简单的,难的是我们代码的实现,就要考虑我们的基本功,

做法
1.拷贝链接结点在上面每个结点中间
2.设置链接结点的随机结点,并且它的随机结点于前一个结点的随机结点相同
3.最后将随机结点剪下来,然后再链接起来。

代码实现

struct Node* copyRandomList(struct Node* head) {
	struct Node* cur=head;
	
    //1.拷贝链接结点在上面每个结点中间
    while(cur)
    {
        struct Node* next=cur->next;
        struct Node* newnode=(struct Node*)malloc(sizeof(struct Node));
        newnode->val=cur->val;

        cur->next=newnode;
        newnode->next=next;
        cur=next;
    }
    cur=head;
 
    while(cur)
    {
        struct Node* next=cur->next;
        if(cur->random==NULL)
        {
            next->random=NULL;
        }
        else
        {
            next->random=cur->random->next;
        }
        cur=next->next;
    }
    //3.最后将随机结点剪下来,然后再链接起来。
    cur=head;
    struct Node* newhead=NULL;
    struct Node* newcur=NULL;
    while(cur)
    {
        struct Node* next=cur->next;
        if(newhead==NULL)
        {
            newhead=newcur=next;
            cur=next->next;
            if(cur!=NULL)
                next=cur->next;
        }
        else
        {
            newcur->next=next;
            newcur=newcur->next;
            cur=next->next;
            if(cur!=NULL)
                next=cur->next;
        }
    }
    return newhead;
}

总结

还是要多练习,孰能生巧,一起加油

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

桐桐超努力

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

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

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

打赏作者

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

抵扣说明:

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

余额充值