链表习题详解

LCR 026. 重排链表 - 力扣(LeetCode)

思路:把链表后半部分翻转,然后穿插构成新链表,这里注意一下如果是奇数,快慢指针返回slow,偶数返回slow->next。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* halfhead(struct ListNode* head)
{
    struct ListNode* fast=head;
    struct ListNode* slow=head;
    while(fast->next && fast->next->next)
    {
        fast=fast->next->next;
        slow=slow->next;
    }
    if(fast->next==NULL)
    return slow;
    else return slow->next;
}
struct ListNode* reverList(struct ListNode* head)
{
   struct ListNode* newhead=NULL;
   struct ListNode* ptake=head;
   struct ListNode* pbroke=head->next;
   while(1)
   {
       ptake->next=newhead;
       if(pbroke==NULL) return ptake;
       newhead=ptake;
       ptake=pbroke;
       pbroke=pbroke->next;
   }
}
void reorderList(struct ListNode* head){
struct ListNode* halfh=halfhead(head);
struct ListNode* head2=reverList(halfh);
int l=0;
struct ListNode* head3=head;
struct ListNode* tail=head;
head=head->next;
while(head2!=NULL && head!=NULL)
{
    if(l==0)
    {tail->next=head2;
    tail=tail->next;
    head2=head2->next;
    l=1;}
    else
    {
    tail->next=head;
    tail=tail->next;
    head=head->next;  
    l=0;
    }
}
while(head3)
{
    printf("%d ",head3->val);
    head3=head3->next;
}
}

160. 相交链表 - 力扣(LeetCode)

思路:链表分为两种情况,相交和不相交,我们用双指针来做,例如:

链表A不相交长度是a,链表B不相交长度是b,相交长度是c。所以分两种情况来看,

(1)如果a=b,而且不得null,两指针同时指向链表交点。

(2)如果a!=b,那么当指针pa走过路程a+b+c时,指针pb走过b+c+a时,两指针相遇,指向链表交点,这个过程就是pa走到表尾时指向B链表表头,然后等到pb走到表尾时指向A链表表头。

这两种情况是相交的时候,判断是否到焦点的条件是,pa=pb且pa!=NULL。

在不相交的时候:

(1)如果两链表长度相等,那么会同时指向NULL。

(2)如果两链表长度不相等时,pa走到表尾时指向B链表表头,然后等到pb走到表尾时指向A链表表头,她两走了相同的路程后都指向了NULL。

所以这两种情况的判断条件是:pa==pb 且pa==NULL

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL || headB==NULL)return NULL;
    struct ListNode *pa=headA;
    struct ListNode *pb=headB;
    while(pa!=pb)
    {   
        if(pa==pb && pa!=NULL)return pa;
        if(pa==pb && pa==NULL)return pa;
        if(pa==NULL) pa=headB;
        else pa=pa->next;
        if(pb==NULL) pb=headA;
        else pb=pb->next;
    }

    return pa;
}

LCR 022. 环形链表 II - 力扣(LeetCode)

如图所示

我们用快慢指针算法,链表中环外部分的长度为a,快慢指针在紫色点相遇,相遇时慢指针走了b长度,相遇时快指针已经走完了环的 n 圈,快指针走过的长度为 a+n(b+c)+b。慢指针走过的长度为a+b,由于快指针走过的距离为慢指针的二倍,所以2*(a+b)=a+n(b+c)+b。

由于我们要找到入环点,所以等式左面为a,推出a=c+(n-1)*(b+c),也就是说再设置一个指针p,当它走到入环点的时候慢指针从紫色节点走了(n-1)圈+c,慢指针和p同时到了入环点。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* slow=head;
    struct ListNode* fast=head;
    struct ListNode* p=head;
    while(fast!=NULL)
    {
        if(fast->next==NULL || fast->next->next==NULL)return NULL;
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)break;
    }
    while(p!=slow)
    {
        p=p->next;
        slow=slow->next;
    }
    return p;
}

138. 随机链表的复制 - 力扣(LeetCode)

先复制next指针指向,再复制random指针指向,再拆分。

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */

struct Node* copyRandomList(struct Node* head) {
    if(head==NULL)return NULL;
	for(struct Node* nodehead=head;nodehead!=NULL;nodehead=nodehead->next->next)
    {
        struct Node* newnode=(struct Node*)malloc(sizeof(struct Node));
        newnode->val=nodehead->val;
        newnode->next=nodehead->next;
        nodehead->next=newnode;
    }
    for(struct Node* nodehead=head;nodehead!=NULL;nodehead=nodehead->next->next)
    {
        nodehead->next->random=nodehead->random==NULL?NULL:nodehead->random->next;
    }
    struct Node* new=head->next;
    for(struct Node* nodehead=head;nodehead!=NULL;nodehead=nodehead->next)
    {
        struct Node* newhead=nodehead->next;
         nodehead->next=nodehead->next->next;
        newhead->next=(nodehead->next==NULL)?NULL:nodehead->next->next;
    }
    return new;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值