链表刷题篇

一.

 题目链接:链表 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台 (leetcode-cn.com)

思路:

原链表如图

链表刷题篇_第1张图片

 1.定义一个新head头指针,标记为new,将它初始为NULL,并非指向NULL,最后我们选择返回这个new指针作为新链表的头指针。

链表刷题篇_第2张图片

 2.定义一个结点node

3.进行循环遍历链表各个结点,判定head指针是否为空,如果不为空,说明还没有到达尾部。如果程序第一次运行就没有进入循环,说明传入了一个空链表,此时返回new新链表的头指针,也可直接返回NULL。
4.以下开始逆序链表:在当前指针不为NULL时,先对原链表做头删操作,再对新链表做头插操作。即使用循环进行操作:
让node指针指向传入函数链表的头指针head,两指针指向保持相同。

链表刷题篇_第3张图片

 然后让head指针指向next结点

链表刷题篇_第4张图片

 然后让node->next指向新头指针new,然后更新new=node,以准备下次循环,new作为指向新链表的头指针

链表刷题篇_第5张图片

 

. 最终head指针指向了原链表的结尾,即为NULL,退出循环,此时新链表已经反转完毕,情况如图:

链表刷题篇_第6张图片

 

struct ListNode* reverseList(struct ListNode* head){
    struct ListNode*new=NULL;
    struct ListNode*node;
    while(head!=NULL)
    {
        node=head;
        head=head->next;
        node->next=new;
        new=node;
    }
    return new;
}

链表刷题篇_第7张图片

题目链接:链表 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台 (leetcode-cn.com) 

法一:

使用p,q两个指针,p总往前走,但q每次都从头开始走,对于每个节点,看p与q的步数是否一样,若步数不等,则有环

举个例子如图:

链表刷题篇_第8张图片

p从-4走到2,需要4步,而q从head出发只需一步

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode*cur1=head;
    int pos1=0;
    while(cur1)
    {
        struct ListNode*cur2=head;
        int pos2=0;
        while(cur2)
        {
            if(cur2==cur1)
            {
                if(pos1==pos2)
                break;
                else
                {
                    return cur1;
                }
            }
            cur2=cur2->next;
            pos2++;
        }
        cur1=cur1->next;
        pos1++;
    }
    return NULL;
    
   
}

 法二:快慢指针

算法流程:

fast,slow指向链表头部,fast走两步,slow走一步

但fast==slow时,两指针在环中第一次相遇,下面分析此时fast与slow走过步数关系

(1)设链表a+b个节点,其中链表头部到链表入口有a个节点(不计链表环入口节点),链表环有b个节点,设两指针分别走了x,y步(x为快指针步数,y为慢指针步数)

我们知道fast的步数是slow的两倍,故有x==2y

(2)fast比slow多走了n个环的长度,所以x=y+nb(解析:双指针都走过a步,然后在环内绕圈直到重合时,重合时fast比slow多走环的整数倍)

以上两式相减得y=nb,x=2nb

(3)如果让指针从链表头部一直向前走并统计步数k,那么所有走到链表入口节点的步数:

k=a+nb;(先走a步到入口节点,然后每绕一圈都会回到入口节点)

(4)目前slow走过的步数为nb步,因此,我们只需让slow与fast第一 次相遇后,再种a步就能到环路口

链表刷题篇_第9张图片

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

 三

题目链接:160. 相交链表 - 力扣(LeetCode) (leetcode-cn.com) 

法一:

先遍历headA和headB然后统计两个链表的长度len1和len2,用p指向headA,用q指向headB

如果len1和len2相等,则p走一步,q走一步,当p==q就是相交节点

如果len1>len2则让p先走,p每走一步,len1就减一-,等到len1和len2相等就p和q一起走

当p==q就是相交节点

如果len1

链表刷题篇_第10张图片

 

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
   int lenth1=0;
   int lenth2=0;
   struct ListNode*p=headA;
   struct ListNode*q=headB;
   if(headB==NULL||headA==NULL)
   return NULL;
   while(p!=NULL)
   {
       p=p->next;
       lenth1++;
   }
    while(q!=NULL)
    {
        q=q->next;
        lenth2++;
    }
    while(lenth1!=lenth2)
    {
        if(lenth1>lenth2)
        {
            headA=headA->next;
            lenth1--;
        }
        else
        {
            headB=headB->next;
            lenth2--;
        }
    }
    while(headA!=headB)
    {
        headA=headA->next;
        headB=headB->next;
    }
    return headA;
}

法二

当链表 headA 和headB 都不为空时,创建两个指针pA 和pB,初始时分别指向两个链表的头节点 headA 和 headB,然后将两个指针依次遍历两个链表的每个节点。具体做法如下:

每步操作需要同时更新指针pA 和pB。

如果指针pA 不为空,则将指针 pA 移到下一个节点;如果指针pB 不为空,则将指针 pB 移到下一个节点。

如果指针 pA 为空,则将指针 \textit{pA}pA 移到链表 headB 的头节点;如果指针pB 为空,则将指针 pB 移到链表 \headA 的头节点。

当指针 pA 和pB 指向同一个节点或者都为空时,返回它们指向的节点或者 null。

链表刷题篇_第11张图片

 

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if (headA == NULL || headB == NULL) {
        return NULL;
    }
    struct ListNode *pA = headA, *pB = headB;
    while (pA != pB) {
        pA = pA == NULL ? headB : pA->next;
        pB = pB == NULL ? headA : pB->next;
    }
    return pA;
}

 题目链接:链表 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台 (leetcode-cn.com)

法一:

先遍历一次链表,统计链表长度len,再用p=len-n,然后让链表从头走到第p,则p为要删除的节点

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    if(head==NULL)
    return NULL;
    int length=0;
    struct ListNode*p=head;
    while(p)
    {
        p=p->next;
        length++;
    }
    p=head;
    if(n==length)
    {
        head=head->next;
        return head;
    }
    int i=length-n;
    for(int j=1;jnext;
    }
    p->next=p->next->next;
    return head;
}

法二:

创一个头节点temp,然后让temp->next=head

然后用p,q两个指针指向temp,让p先走n步,然后q再出发,当p走到最后一个节点,此时,q走到要删除的节点的前一个

链表刷题篇_第12张图片

 

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    struct ListNode*temp=malloc(sizeof(struct ListNode));
    temp->val=0;
    temp->next=head;
     struct ListNode* fast = head;
    struct ListNode* slow = temp;
    for(int i=0;inext;
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;
    }
    slow->next=slow->next->next;
    return temp->next;
}

链表刷题篇_第13张图片

题目链接:链表 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台 (leetcode-cn.com) 

法一:直接在链表操作

struct ListNode* oddEvenList(struct ListNode* head){
     if(head==NULL)
    return NULL;
    
    struct ListNode*p=head;
    
    int len=0;
    while(p->next!=NULL)
    {
        p=p->next;
        len++;
    }
    len+=1;
    struct ListNode*q=head;
    if(len==2)
    return head;
    while(len>0)
    {
       if(len-1>0)
       {
            struct ListNode*tmp=q->next;
            q->next=tmp->next;
            p->next=tmp;
            tmp->next=NULL;
            p=tmp;
            len-=2;
            q=q->next;
       } 
       else
       {
           q=q->next;
           len-=2;
       }
    }
    return head;
}

法二:

分离节点后合并

将奇数节点和偶数节点分离然后合并

struct ListNode* oddEvenList(struct ListNode* head) {
    if (head == NULL) {
        return head;
    }
    struct ListNode* evenHead = head->next;
    struct ListNode* odd = head;
    struct ListNode* even = evenHead;
    while (even != NULL && even->next != NULL) {
        odd->next = even->next;
        odd = odd->next;
        even->next = odd->next;
        even = even->next;
    }
    odd->next = evenHead;
    return head;
}

你可能感兴趣的:(力扣)