【数据结构】链表力扣刷题详解
创始人
2024-12-27 16:08:23
0

前言

题目链接

移除链表元素

链表的中间结点

反转链表

分割链表

环形链表的约瑟夫问题


 

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗~

如有错误,欢迎指出~


移除链表元素

题述

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 

思路1:直接删除原链表中不符合的节点

遍历原链表,遇到val就执行删除操作
执行删除操作修改指针的指向有点麻烦,还有其他办法

思路2:满足要求的节点放在新链表上

定义新链表,利用pcur遍历原链表,找不为val的节点,尾插在新链表中
新链表:newHead  newTail

要考虑链表是否为空
链表为空:插入进来的节点就是链表的头节点和尾节点
链表不为空,插入进来的节点就是链表的新的尾节点

代码实现思路2

/**  * Definition for singly-linked list.  * struct ListNode {  *     int val;  *     struct ListNode *next;  * };  */ typedef struct ListNode ListNode; struct ListNode* removeElements(struct ListNode* head, int val) {     //定义新链表的头尾指针     ListNode* newHead,* newTail;     newHead=newTail=NULL;      ListNode* pcur=head;     while(pcur)     {         //不是val,尾插到新链表         if(pcur->val!=val){             //链表为空             if(newHead==NULL)             {                 newHead=newTail=pcur;             }             else{                 //链表不为空                 newTail->next=pcur;                 newTail=newTail->next;//             }         }         //pcur继续往下走         pcur=pcur->next;     }     if(newTail)//要先判断newTail本来是否为空     {         newTail->next=NULL;     }     return newHead; }

链表的中间结点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点

思路1:统计链表中节点的个数,通过除2找到中间节点

for(统计链表个数)
    for(根据除2结果走到中间节点)

思路2:快慢指针

slow指针每次走1步,fast走2步
当fast->next或者fast走到为空,则slow刚好指向的就是中间节点
 

/**  * Definition for singly-linked list.  * struct ListNode {  *     int val;  *     struct ListNode *next;  * };  */   typedef struct ListNode ListNode; struct ListNode* middleNode(struct ListNode* head) {     ListNode* fast,*slow;     fast=slow=head;     while(fast&&fast->next)//条件fast和fast->next不能相反,会造成短路     {         slow=slow->next;//slow走1步         fast=fast->next->next;//fast走2步     }     return slow; }

 反转链表


给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

思路1

创建新链表,遍历原链表的节点将其插入到新链表中

思路2:创建3个指针

分别记录前驱节点,当前节点,后继节点,改变原链表的指向1

/**  * Definition for singly-linked list.  * struct ListNode {  *     int val;  *     struct ListNode *next;  * };  */  typedef struct ListNode ListNode; struct ListNode* reverseList(struct ListNode* head) {     //要先处理空链表     if(head==NULL)     {         return head;     }     ListNode *n1,*n2,*n3;     n1=NULL;     n2=head;     n3=head->next;      while(n2)     {         //修改n2的指向         n2->next=n1;         //n1,n2,n3往下走         n1=n2;         n2=n3;         if(n3)//要先判断n3不为空,才能往下走         {             n3=n3->next;         }     }     return n1; }

合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

代码实现

/**  * Definition for singly-linked list.  * struct ListNode {  *     int val;  *     struct ListNode *next;  * };  */  typedef struct ListNode ListNode; struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {     if (list1 == NULL)         return list2;     if (list2 == NULL)         return list1;      ListNode *l1, *l2;     l1 = list1, l2 = list2;     //创建头节点     ListNode *newHead, *newTail;     newHead = newTail = (ListNode*)malloc(sizeof(ListNode));      while (l1 && l2) {         if (l1->val < l2->val) {             // l1小,l1上,但要先判断l1不为空指针             // if (newHead == NULL)             //     newHead = newTail = l1;             // else {             //     newTail->next = l1;             //     newTail = newTail->next;             // }             // l1 = l1->next;              //代码优化             newTail->next=l1;             newTail=newTail->next;             l1=l1->next;         } else {             // l2小             // if (newHead == NULL)             //     newHead = newTail = l2;             // else {             //     newTail->next = l2;             //     newTail = newTail->next;             // }             // l2 = l2->next;               //代码优化             newTail->next=l2;             newTail=newTail->next;             l2=l2->next;         }     }     if (l1) {         newTail->next = l1;     }     if (l2) {         newTail->next = l2;     }     return newHead->next; }

分割链表


给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你不需要 保留 每个分区中各节点的初始相对位置。

思路

定义2个链表:大链表和小链表,遍历原链表的节点将其放到对应的新链表中,最将大小链表首尾相连

创建大小链表都要先创建一个哨兵位

利用pcur遍历链表

代码实现

/**  * Definition for singly-linked list.  * struct ListNode {  *     int val;  *     struct ListNode *next;  * };  */  typedef struct ListNode ListNode;  struct ListNode* partition(struct ListNode* head, int x){     if(head==NULL)         return head;     //创建带头的大小链表     ListNode* lessHead ,*lessTail;     ListNode* greaterHead,*greaterTail;     lessHead=lessTail=(ListNode*)malloc(sizeof(ListNode));     greaterHead=greaterTail=(ListNode*)malloc(sizeof(ListNode));      //遍历原链表,将节点放在对应的新链表中     ListNode*pcur=head;     while(pcur)     {         if(pcur->val < x)         {             //放在小链表中             lessTail->next=pcur;             lessTail=lessTail->next;         }         else         {             //放在大链表中             greaterTail->next=pcur;             greaterTail=greaterTail->next;         }     pcur=pcur->next;     }     //大链表尾要置为空     greaterTail->next=NULL;      //大小链表首尾相连     lessTail->next=greaterHead->next;     ListNode*ret=lessHead->next;     free(greaterHead);     free(lessHead);     return ret; }

环形链表的约瑟夫问题

编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数,报到 m 的人离开。

下一个人继续从 1 开始报数。

n-1 轮结束以后,只剩下一个人,问最后留下的这个人编号是多少?、

代码实现

 //这道OJ题已经创建好了结构体结点,只是没有展示出来  typedef struct ListNode ListNode; //申请新节点 ListNode* BuyNode(int x) {     ListNode* newNode=(ListNode*)malloc(sizeof(ListNode));     //可写可不写,一般不会申请失败     if(newNode==NULL)     {         exit(1);     }     newNode->val=x;     newNode->next=NULL;     return newNode; } //创建循环链表 ListNode*createList(int n) {     //创建头节点     ListNode* phead=BuyNode(1);     ListNode* ptail=phead;     //从2开始,共创建了n个节点     for(int i=2;i<=n;i++)     {         ptail->next=BuyNode(i);         ptail=ptail->next;     }     //链表要首尾相连,循环起来     ptail->next=phead;     return phead; } int ysf(int n, int m ) {     //创建不带头单向循环链表     //逢m删除节点     ListNode*head=createList(n);     ListNode*pcur=head;     ListNode*prev=NULL;//用于记录pcur走过的位置,是pcur的前驱节点      int count=1;     //逢m删除节点     while(pcur->next!=pcur)//表示删除节点到只剩下自己跳出循环     {         if(count==m)         {             //删除当前节点pcur             prev->next=pcur->next;             free(pcur);             //删除pcur节点后,要让pcur走到新的位置,count置为初始值             pcur=prev->next;             count=1;         }         else          {             //pcur往后走             prev=pcur;             pcur=pcur->next;             count++;         }     }     //此时pcur节点就是幸存下来的节点     return pcur->val; }

相关内容

热门资讯

三分钟秒懂!八闽掌上辅助软件!... 三分钟秒懂!八闽掌上辅助软件!(透视)外挂辅助器插件(2024已更新)-哔哩哔哩是一款可以让一直输的...
中日区块链“大比拼”!中国蚂蚁... 科技巨头在区块链和加密货币领域的动作越来越频繁。近期,中国金融科技巨头蚂蚁集团进一步加...
向日葵、Todesk、team... 问题描述:用向日葵远程等桌面时,当把显示器断电或者就没有显示器时或者笔记...
第十了解!wpk俱乐部外挂辅助... 第十了解!wpk俱乐部外挂辅助器插件,微扑克wpk安全的(有挂解密)-哔哩哔哩;1、完成wpk俱乐部...
超越实体机?深度评测揭示ToD... 前言随着科技的飞速发展,IT服务正在经历一场深刻的变革。云电脑,作为这场...
2分钟掌握!胡乐麻将app专用... 自定义新版胡乐麻将app专用神器系统规律,只需要输入自己想要的开挂功能,一键便可以生成出胡乐麻将ap...
FL Studio Mobil... FL Studio Mobile  4.4.3手机版介绍FL Studio Mobile其实也叫水果...
Windows系统电脑本地部署... 文章目录前言1. 本地部署2. 使用方法介绍3. 内网穿透工具下载安装4. 配置公网地址5. 配置固...
笔记本电脑连WiFi后,如何将...     笔记本电脑连接Wi-Fi后,想要共享网络给手机,其实有多种方法可...
第二个了解!德州微扑克外挂辅助... 第二个了解!德州微扑克外挂辅助器作弊,微扑克ai辅助(有挂秘诀)-哔哩哔哩;1、点击下载安装,德州微...