链表的相关OJ题解析

这篇具有很好参考价值的文章主要介绍了链表的相关OJ题解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

⭐一、移除链表元素 

⭐二、反转链表

⭐三、求链表中间节点

⭐四、求链表倒数第k个节点

⭐ 五、合并两个有序链表

⭐六、链表的回文结构

⭐ 七、相交链表

⭐八、环形链表

⭐九、链表入环的第一个节点



⭐一、移除链表元素 

链表的相关OJ题解析

链接: 移除链表元素

思路一:前后指针法

1.定义两个指针cur、prev

cur用来遍历,prev用来指向cur的前一个节点,方便删除时连接链表

2.直接遍历链表,如果该节点的val值与要删除的val值相等,那么就free掉该节点

时间复杂度O(n),空间复杂度O(1)

链表的相关OJ题解析

 ⭐代码实现:

struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode*cur=head,*prev=NULL;
while(cur)
{if(cur->val!=val)
{
 prev=cur;//让prev指向cur节点的前一个节点
 cur=cur->next;
}
else 
{
    if(prev==NULL)//判断删除的是否为头节点
    {
        head=cur->next;//为头节点的话,指向头节点的指针后移
        free(cur);
        cur=head;
    }
    else 
    {
        prev->next=cur->next;//删除节点的前一个节点连上删除节点的后一个节点
        free(cur);
        cur=prev->next;//更新一下cur指向的节点
    }
}


}
return head;
}

注意点:如果删除的节点为头节点时,需要更新一下head头节点。

思路二:

将不等于val的节点尾插到一个新的链表中,等于val的节点直接删除(free掉)

时间复杂度O(n),空间复杂度O(1)

链表的相关OJ题解析

 链表的相关OJ题解析

链表的相关OJ题解析

 ⭐代码实现:

struct ListNode*  removeElements(struct ListNode* head, int val) {
    //创建一个什么都不存的头节点(哨兵位节点)
    struct ListNode* newhead = (struct ListNode*) malloc(sizeof(struct ListNode));
    struct ListNode*tail=newhead,*cur = head;
   //tail指向新链表的尾,cur用来遍历新链表
        while(cur!=NULL)
        {
            if(cur->val == val)
            {
                struct ListNode *tmp = cur->next;
                   free(cur);
                   cur=tmp;
            }
            else
            {
                tail->next=cur;
                tail=cur;
                cur=cur->next;
            }
        }

        tail->next=NULL;//注意要把新链表的尾置空
      head=newhead->next;//把新链表赋给head
      free(newhead);
      return head;

    }

1.该方法不需要判断删除的节点是否为头节点,

但需要注意的是

2.得把新链表头节点的下一个节点赋给head,而不是把新链表的头节点赋给head

3.如果最后一个节点是被删除的节点,那么需要把新链表的尾节点置空,不然新链表的尾节点的next将变为野指针

⭐二、反转链表

链表的相关OJ题解析

链接: 反转链表

思路

将原链表中的节点依次取下来头插到新链表中

图解:

链表的相关OJ题解析

⭐ 代码实现:

struct ListNode* reverseList(struct ListNode* head){

 struct ListNode*newhead=NULL;//新链表的头节点
 struct ListNode*cur=head,*tmp=NULL;
 while(cur)
 {
     tmp=cur;
     cur=cur->next;
     tmp->next=newhead;//头插
     newhead=tmp;
 }   
 return newhead;
}

 时间复杂度O(n),空间复杂度O(1)

⭐三、求链表中间节点

链表的相关OJ题解析

链接:链表的中间节点

 思路:快慢指针法

设置一个快指针fast和一个慢指针slow同时指向头结点,让fast指针一次走两个结点,而slow指针一次走一个结点,如果链表结点个数为奇数,则fast->next为空时,slow就是中间节点,如果链表结点为偶数,则fast为空时,slow就是中间节点,循环结束后,返回slow即可

链表节点为奇数个:

链表的相关OJ题解析

 链表节点为偶数个:

链表的相关OJ题解析

⭐ 代码实现:

struct ListNode* middleNode(struct ListNode* head){

struct ListNode*fast=head,*slow=head;
while(fast&&fast->next)
{
    fast=fast->next->next;//一次走两步
    slow=slow->next;//一次走一步
}

return slow;

}

⭐四、求链表倒数第k个节点

链表的相关OJ题解析

链接:求链表倒数第k个节点

 思路:快慢指针法

先设置两个指针fast 和 slow ,先让fast走k步,并判断如果k值过大,当fast已经为空时,说明k值不合法,返回空。如果K的值合法,那么接着让fast和slow一起走,当fast为空时,slow的位置就是倒数第K个结点

图解:

链表的相关OJ题解析

⭐ 代码实现:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
   struct ListNode*fast=pListHead, *slow=pListHead;
     if(!pListHead||k<=0)return NULL;
   while(k--)
   {
    if(fast)
     { 
        fast=fast->next;//fast不为空就走
     }
   else
    {
       return NULL;//fast为空说明不合法,返回NULL
    }
   }
   while(fast)
   {
    fast=fast->next;//fast,slow一起走
    slow=slow->next;
   }
   
   return slow;
}

这里需要注意的是,如果k<=0的时候,说明不合法,K过大时也不合法。

⭐ 五、合并两个有序链表

链表的相关OJ题解析

链接:合并两个有序链表

思路:哨兵位解法

创建一个新节点(哨兵位节点,不存放值的节点)作为新链表,比较两个原链表中的val值,取小的尾插至新链表中,省去了判断两个链表是否为空的情况,但返回前需要free掉该空间,时间复杂度O(n),空间复杂度O(1)

⭐ 代码实现:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode*phead=NULL,*tail=NULL;
struct ListNode*tmp=NULL;
phead=tail=(struct ListNode*)malloc(sizeof(struct ListNode));
if(list1==NULL)
{
    return list2;
}
if(list2==NULL)
{
    return list1;
}
while(list1&&list2)
{
    if(list1->val<=list2->val)
    {
        tail->next=list1;
        list1=list1->next;
        tail=tail->next;
        tail->next=NULL;
    }
    else{
        tail->next=list2;
        list2=list2->next;
        tail=tail->next;
        tail->next=NULL;
    }
}
if(list1==NULL)
{
      tail->next=list2;
}
else{
    tail->next=list1;
}
  struct ListNode* head=phead->next;
   free(phead);//释放申请的空间,防止内存泄漏
return head;
}

⭐六、链表的回文结构

链表的相关OJ题解析

链接:链表的回文结构

思路:

先找到该链表的中间节点,然后从中间节点开始,将后面的节点依次头插到一个新链表中(反转链表),然后再通过比较这两个链表,如果都相等那么是回文结构,如果有一个节点不相等那么不为回文结构

通过上面的求链表的中间节点反转链表我们可以很轻松的解决这个问题

⭐代码实现:

class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        // write code here
        ListNode*fast=A;
        ListNode*slow=A;
        ListNode*phead=NULL;
        while(fast&&fast->next)//为了求出中间节点
        {
            fast=fast->next->next;
            slow=slow->next;
        }
        while(slow)//将链表反转
        {
            ListNode*tmp=slow;
            slow=slow->next;
            tmp->next=phead;
            phead=tmp;
        }
        while(phead)
        {
            if(phead->val!=A->val)
            {
                return false;//不相等就返回false
            }
            else {
            phead=phead->next;
            A=A->next;
            }
        }
        return true;
    }
};

⭐ 七、相交链表

链表的相关OJ题解析

链接:相交链表

思路:

先将这两个链表各自遍历一遍,遍历的同时求出它们的长度,并在它们最后一个节点处结束遍历(为了比较它们是否相交,因为相交的话,最后一个节点必相同),然后比较它们最后一个节点是否相等,如果不相等返回空,如果相等,接着比较它们的长度,让长的链表先走它们的长度差步,然后一起走,它们第一个相遇的节点就是它们相交的第一个节点了

⭐代码实现:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode*pre=headA,*cur=headB;
    struct ListNode*longlist=headA,*shortlist=headB;
    int cnt1=1,cnt2=1;
    while(pre->next)//遍历链表
    {
        cnt1++;//求长度
        pre=pre->next;
    }
    while(cur->next)//遍历链表
    {
        cnt2++;//求长度
        cur=cur->next;
    }
    if(pre!=cur)//比较最后一个节点
    {
         return NULL;//不相等返回空
    }
    if(cnt1<cnt2)
    {
       longlist=headB;//为了让长的先走
       shortlist=headA;
    }
    int a=abs(cnt1-cnt2);//算长度差
    while(a--)
    {
      longlist=longlist->next;//让长的先走它们的长度差步
    }
    while(longlist!=shortlist)//相遇的节点就为第一个相交的节点
    {
       longlist=longlist->next;
       shortlist=shortlist->next;
    }
    return longlist;


}

⭐八、环形链表

链表的相关OJ题解析

链接:环形链表

思路:快慢指针法

让fast和slow指针同时走,不过fast一次走两步,slow指针一次走一步,如果该链表不带环,那么fast和slow将不会相遇,fast走到空时就返回false,如果带环那么它们将相遇。

⭐代码实现:

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

为什么快指针每次走两步,慢指针走一步可以它们可以相遇呢?

原因:
假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。

最好情况:当慢指针刚进环时,可能就和快指针相遇了,

最差情况:两个指针之间的距离刚好就是环的长度。此时,两个指针每移动
一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在慢指针走到一圈之前,
快指针肯定是可以追上慢指针的,此时它们就相遇了。

让我们假设一下,当慢指针进环时,快指针和慢指针之间的距离为N,快指针一次走两步,慢指针一次走一步,每走一步,他们的距离就减1,从N到N-1,到N-2…3,2,1,最后到0,此时两者就相遇了


那么可不可以让快指针一次走多步(三步或三步以上)呢?
快指针一次走3步,走4步,…n步行吗?
这种情况有时是可以的,比如一些特殊情况。

慢指针进环时他们的距离为N,随后到N-2,N-4…,如果N为奇数,那么N-2*n(n为步数)永远不等于0,毕竟指针不能走半步;而如果N为偶数,则N-2 *n就总会有等于0的时候,由此可以知道,快指针一次走3步,可能快慢指针可以相遇,可能不可以。这需要看它们相遇的时机了。

⭐九、链表入环的第一个节点

链表的相关OJ题解析

链接:环形链表||

思路:

先使用上一题的方法:让fast和slow指针同时走,不过fast一次走两步,slow指针一次走一步,如果该链表不带环,那么fast和slow将不会相遇,fast走到空时就返回false,如果带环那么它们将相遇。

然后保存它们相遇的点,接着让慢指针从起始点开始走,快指针从相遇点开始走,它们都是一次走一步,此时它们相遇的点就是链表入环的第一个节点。

⭐代码实现:

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

它们会在环形入口相遇的原因:

H为链表的起始点,E为环入口点,M与判环时候相遇点设:
环的长度为R,H到E的距离为LE到M的距离为X则:M到E的距离为R-X
在判环时,快慢指针相遇时所走的路径长度:
fast: L +X+nR      slow: L+x
注意:
1.当慢指针进入环时,快指针可能已经在环中绕了n圈了,n至少为1
因为:快指针先进环走到M的位置,最后又在M的位置与慢指针相遇
2.慢指针进环之后,快指针肯定会在慢指针走一圈之内追上慢指针
因为:慢指针进环后,快慢指针之间的距离最多就是环的长度,而两个指针在移动时,每次它们的距离都缩减一步,因此在慢指针移动一圈之前快指针肯定是可以追上慢指针的
而快指针速度是慢指针的两倍,因此有如下关系是:2*(L+X)=L+X+nR 
上式可得:L=nR-X (n为1,2,3,4……,n的大小取决于环的大小,环越小n越大)

极端情况下,假设n=1,此时:L=R-X

所以快指针本来要走n圈的,但是此时快指针从相遇点开始走,所以就少走了X步,最终它们的相遇点就在环的入口点了
即:一个指针从链表起始位置走,一个指针从相遇点位置绕环,每次都走一
步,两个指针最终会在入口点的位置相遇

链表的部分相关OJ题就分享到这里了,886!文章来源地址https://www.toymoban.com/news/detail-460291.html

到了这里,关于链表的相关OJ题解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构:图文详解双向链表的各种操作(头插法,尾插法,任意位置插入,查询节点,删除节点,求链表的长度... ...)

    目录 一.双向链表的概念 二.双向链表的数据结构 三.双向链表的实现 节点的插入 头插法 尾插法 任意位置插入 节点的删除 删除链表中第一次出现的目标节点 删除链表中所有与相同的节点 节点的查找 链表的清空 链表的长度 四.模拟实现链表的完整代码 前言: 在上一

    2024年02月05日
    浏览(50)
  • 数据结构:图文详解单链表的各种操作(头插法,尾插法,任意位置插入,删除节点,查询节点,求链表的长度,清空链表)

    目录  一.什么是链表 二.链表的实现 节点的插入 头插法 尾插法 指定位置插入 节点的删除 删除第一次出现的节点 删除所有节点 节点的查找 链表的清空 链表的长度 前言: 在上一篇文章中,我们认识了线性数据结构中的顺序表,而本篇文章则是介绍线性数据结

    2024年02月05日
    浏览(61)
  • 【数据结构】移除链表元素-图文解析(单链表OJ题)

    LeetCode链接:203. 移除链表元素 - 力扣(LeetCode) 本文导航 💭做题思路 🎨画图更好理解: ✍️代码实现 🗂️分情况讨论: ❄️极端情况: 遍历链表,找到值为 val 的节点删除 这里需要两个指针  cur 用来遍历链表  prev 指向 cur 的前一个位置,方便删除一个节点后,链接前

    2024年02月14日
    浏览(35)
  • 【链表OJ 2】反转链表

    前言:          🎈欢迎大家来到Dream_Chaser~的博客🎈         🚩本文收录于 C--数据结构刷题的专栏中 --http://t.csdn.cn/n6UEP         首先欢迎大家的来访,其次如有错误,非常欢迎大家的指正,互相学习进步。 来源:206. 反转链表 - 力扣(LeetCode) 题目: 思路: 首先,检查

    2024年02月12日
    浏览(30)
  • 【单链表OJ题:反转链表】

    题目来源

    2024年02月14日
    浏览(40)
  • 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

    /**  * Definition for singly-linked list.  * struct ListNode {  *     int val;  *     ListNode *next;  *     ListNode(int x) : val(x), next(NULL) {}  * };  */ class Solution { public:     ListNode* reverseList(ListNode* head) {              } };

    2024年02月22日
    浏览(49)
  • 【链表OJ 3】链表的中间结点

    前言:          本文收录于http://t.csdn.cn/n6UEP数据结构刷题的博客中,首先欢迎大家的来访,其次如有错误,非常欢迎大家的指正!我会及时更正错误! 目录 一.链表的中间结点  1.1原理:快慢指针的使用 链表元素个数为奇数时 链表元素个数为偶数时 1.2循环条件问题? 来源:87

    2024年02月14日
    浏览(50)
  • 【链表OJ题 6】链表的回文结构

    目录 题目来源: 代码实现: 思路分析: 实现过程: 链表的回文结构_牛客题霸_牛客网 (nowcoder.com) 题目描述: 本题的难点在于时间复杂度为O(n),空间复杂度为O(1)。 因为回文结构是正着读反着读是一样的,因此我们 找到链表的中间结点,然后从中间节点开始逆置到尾结点,

    2024年02月06日
    浏览(40)
  • 【Leetcode】反转链表 合并链表 相交链表 链表的回文结构

      目录 一.【Leetcode206】反转链表 1.链接 2.题目再现  3.解法A:三指针法 二.【Leetcode21】合并两个有序链表 1.链接 2.题目再现  3.三指针尾插法 三.【Leetcode160】相交链表 1.链接 2.题目再现 3.解法 四.链表的回文结构 1.链接 2.题目再现  3.解法 1.链接 反转链表 2.题目再现  3.解法

    2024年02月02日
    浏览(50)
  • 【算法入门&链表】【模板】链表|反转链表|合并排序链表|删除链表的节点

    ✅作者简介:热爱后端语言的大学生,CSDN内容合伙人 ✨精品专栏:C++面向对象 🔥系列专栏:算法百炼成神 本专栏收录的均为牛客网的算法题目,内含链表、双指针、递归、动态规划、基本数据结构等算法思想的具体运用。牛客网不仅有大量的经典算法题目,也有大厂的面

    2024年02月17日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包