单链表进阶OJ题精析

目录

一、回文链表

1.1 题目

1.2 题解

1.3 分析

二、带环链表I

2.1 题目

2.2 题解

2.3 分析

2.3.1为什么该思路可行?

2.3.2为什么只能快指针走两步?

三、带环链表II

3.1 题目

3.2 题解

3.3 分析

四、相交链表

4.1 题目

4.2 题解

4.3 分析

4.3.1如何判断是相交链表

4.3.2如何返回相交节点

4.4第三题的相交链表新思路

五、面试题—链表的深度拷贝

5.1 题目

5.2 题解

5.3 分析


一、回文链表

1.1 题目

牛客网原题链接:链表的回文结构_牛客题霸_牛客网

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

1.2 题解

class PalindromeList {
  public:
    //寻找中间节点
    struct ListNode* middleNode(struct ListNode* head) {
        struct ListNode* slow = head;
        struct ListNode* fast = head;
        while (fast != NULL && fast->next != NULL) {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
    //逆置链表
    struct ListNode* reverseList(struct ListNode* head) {
        if (head == NULL) {
            return head;
        }
        struct ListNode* a = NULL;
        struct ListNode* b = head;
        struct ListNode* c = head->next;

        while (b) {
            b->next = a;
            a = b;
            b = c;
            if (c) {
                c = c->next;
            }
        }
        return a;
    }
    //
    bool chkPalindrome(ListNode* A) {
        struct ListNode* mid = middleNode(A);
        struct ListNode* rmid = reverseList(mid);

        while(rmid&&A)
        {
            if(rmid->val!=A->val)
            {
                return false;
            }

            rmid=rmid->next;
            A = A->next;
        }

        return true;
    }
};

1.3 分析

找到中间节点,将中间节点往后的节点进行逆置,然后从中间节点开始遍历之后的节点与头节点进行比较。

寻找中间节点使用快慢指针法,逆置链表用三指针法。具体讲解详见博主的另一篇博客:http://t.csdnimg.cn/1mZ1x

二、带环链表I

2.1 题目

LeetCode原题链接:. - 力扣(LeetCode)

给你一个链表的头节点 head ,判断链表中是否有环。如果链表中存在环 ,则返回 true 。 否则,返回 false 。

2.2 题解

bool hasCycle(struct ListNode *head) {
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;

        if(slow==fast)
        {
            return true;
        }
    }
    return false;
}

2.3 分析

2.3.1为什么该思路可行?

2.3.2为什么只能快指针走两步?

三、带环链表II

3.1 题目

LeetCode原题链接:. - 力扣(LeetCode)

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

3.2 题解

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;

        if(slow==fast)
        {
            struct ListNode* meet = slow;
            while(meet!=head)
            {
                meet=meet->next;
                head=head->next;
            }
            return meet;
        }
    }
    return false;
}

3.3 分析

四、相交链表

4.1 题目

LeetCode原题链接:. - 力扣(LeetCode)

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

4.2 题解

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode* curA=headA,*curB=headB;
    struct ListNode* plong=headA,*pshort=headB;
    int kA=0;
    int kB = 0;
    while(curA->next)
    {
        curA=curA->next;
        kA++;
    }
    while(curB->next)
    {
        curB=curB->next;
        kB++;
    }
    if(curA!=curB)
    {
        return NULL;
    }
    int cha = abs(kA-kB);
   
    if(kA<kB)
    {
        plong = headB;
        pshort=headA;
    }
    while(cha--)
    {
        plong=plong->next;
    }
    while(plong!=pshort)
    {
        plong=plong->next;
        pshort=pshort->next;
    }
    return plong;
}

4.3 分析

4.3.1如何判断是相交链表

两个链表的尾指针指向的是同一个节点

4.3.2如何返回相交节点

难点:相交前的两个链表长度可能不同,不能从头开始一一比较

解决方案:将长链表的指针率先走,走到长度与短链表的指针相同为止。

采用快慢指针法。详见博主的另一篇博客:http://t.csdnimg.cn/1mZ1x

4.4第三题的相交链表新思路

五、面试题—链表的深度拷贝

5.1 题目

LeetCode原题链接:. - 力扣(LeetCode)

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

5.2 题解

struct Node* copyRandomList(struct Node* head) {
	struct Node* cur = head;
    //创建复制节点
    while(cur)
    {
        struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        //尾插到原节点之后
        copy->next = cur->next;
        cur->next=copy;

        cur=copy->next;
    }
    cur = head;
    //复制随机指针
    while(cur)
    {
        struct Node* copy = cur->next;
        if(cur->random==NULL)
        {
            copy->random=NULL;
        }
        else
        {
            copy->random = cur->random->next;
        }

        cur=copy->next;
    }
    cur = head;
    //构建新链表并返回
    struct Node* copyhead=NULL;
    struct Node* copytail=NULL;
    while(cur)
    {
        struct Node* copy = cur->next;

        
        if(copyhead==NULL)
        {
            copyhead=copytail=copy;
        }
        else
        {
            copytail->next=copy;
            copytail=copytail->next;
        }
        

        cur=copy->next;
    }
    return copyhead;
}

5.3 分析

难点:随机指针的指向问题

解决方案:  

     1. 复制一个全新链表,根据原链表的相对位置,确定随机指针的指向,时间复杂度为O(N^2)

     2.将每个新节点全部尾插到原节点的后面,这样只需将random指向原节点的next的指针即可

  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值