【Leetcodenowcode数据结构】单链表的应用(初阶)
系列文章目录
《Leetcode&nowcode代码强化刷题》
文章目录
- 系列文章目录
- 前言
- 正文
- 一.移除链表元素
- 二.反转链表
- 三.链表的中间结点
- 四.合并两个有序链表
- 五.链表的回文结构
- 六.相交链表
- 七.环形链表I
- 八.环形链表II
- 总结
前言
数据结构与算法
是计算机领域的核心,既是面试考察重点,也是优化项目性能的关键。而刷题是掌握它最有效的方式,能帮我们巩固理论、提升解题能力。
我选择LeetCode
和NowCode
作为主要刷题平台:LeetCode 题目丰富、分类清晰,适合夯实基础;NowCode贴近国内企业
笔试场景,助力对接实战需求,二者互补性强。
这份刷题记录不只是题目与答案的罗列,更会记录解题思路、难点易错点,以及解法优化过程。希望它能成为我的复盘工具
,也为其他学习者提供参考
。
接下来,就从第一道题开始,在刷题中积累提升,让数据结构与算法成为解决问题的有力工具。
正文
一.移除链表元素
题目链接:203.移除链表元素
题目描述:
解题思路:创建新链表,把原链表中的值依次尾插到新链表的尾部
代码展示:
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode LTN;
struct ListNode* removeElements(struct ListNode* head, int val) {LTN* newHead = NULL; // 新头LTN* pcur = head; // 遍历链表LTN* newTail = NULL; // 新尾while (pcur) {if (pcur->val != val) // 符合要求{// 尾插if (newHead == NULL) // 新链表为空newHead = newTail = pcur;// 新链表不为空else {newTail->next = pcur;newTail = newTail->next;}}pcur = pcur->next;}if (newTail)newTail->next = NULL;return newHead;
}
博主题解
二.反转链表
题目链接:206.反转链表
题目描述:
解题思路:
创建三个指针,分别指向,前一个节点,当前节点,后一个节点
依次反转当前节点的指向,利用后一个节点来 让三个指针继续向后走
代码展示:
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode LTN;
struct ListNode* reverseList(struct ListNode* head) {if(head==NULL){return head;}//定义三个指针
LTN* n1=NULL,*n2=head,*n3=n2->next;
//开始遍历
while(n2)//n2不为空
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3)//如果3不为空的时候
n3=n3->next;}return n1;
}
博主题解
三.链表的中间结点
题目链接:876.链表的中间结点
题目描述:
解题思路:
创建一个快指针,一个慢指针
快指针每次走两步
慢指针每次走一步
当快指针走完,慢指针指向的就是链表的中间结点
代码展示:
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode LTN;
struct ListNode* middleNode(struct ListNode* head) {//创建快慢指针LTN* fast=head;LTN* slow=head;//慢指针走一步,快指针走两步while(fast!=NULL&&fast->next!=NULL)//不能换顺序,要先确保fast不为NULL{slow=slow->next;fast=fast->next->next;}return slow;
}
博主题解
四.合并两个有序链表
题目链接:21.合并两个有序链表
题目描述:
解题思路:
创建一个哨兵位,依次比较两个链表的值,按序插入新链表
一个链表插完,把另一个剩下的直接插到后面
代码展示:
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode LTN;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {LTN* newhead=malloc(sizeof(LTN));//创建链表哨兵位newhead->next=NULL;LTN* l1=list1;LTN* l2=list2;
LTN* newTail=newhead;
while(l1!=NULL&&l2!=NULL)
{if(l1->val>l2->val){
newTail->next=l2;
newTail=newTail->next;
l2=l2->next;}else{newTail->next=l1;newTail=newTail->next;l1=l1->next;}
}if(l1!=NULL)
{newTail->next=l1;
}
if(l2!=NULL)
{newTail->next=l2;
}
return newhead->next;
}
博主题解
五.链表的回文结构
题目链接:链表的回文结构
题目描述:
解题思路:
会了上面两道,这道题目就很简单了
先快慢指针找中间节点
从中间节点开始三指针逆置
逆置完比较
逆置完之后,对逆置那部分链表与原来的链表进行比较
代码展示:
/*
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};*/
//快慢指针找中间节点
ListNode* FindMid(ListNode* head)
{
ListNode* fast=head;
ListNode* slow=head;
while(fast->next!=NULL&&fast!=NULL)
{slow=slow->next;fast=fast->next->next;
}
return slow;
}ListNode* reList(ListNode* head)//三指针反转链表
{if(head==NULL)return head;ListNode* n1=NULL,*n2=head,*n3=head->next;while(n2!=NULL){n2->next=n1;n1=n2;n2=n3;if(n3!=NULL)n3=n3->next;}return n1;
}class PalindromeList {
public:bool chkPalindrome(ListNode* A) {ListNode* mid=FindMid(A);//找中间节点ListNode* newhead=reList(mid);//反转后新节点while(newhead!=NULL){if(newhead->val!=A->val)return false;else{newhead=newhead->next;A=A->next;}}return true;}
};
博主题解
六.相交链表
题目链接:160.相交链表
题目描述:
解题思路:
单链表,方向唯一
如果相交,那么最后肯定会到相同的终点
由于交点之后的路程一样,差别就在前面
①分别计算两个链表的长度
②计算差值
③让长链表先走差的绝对值步,这样两个链表到交点距离相同了
④再一起走到的同一个位置,就是交点了
代码展示:
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode LTN;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {//相交链表,必有相同的终点//计算两条链表的长度int lenA=0,lenB=0;LTN* pa=headA;LTN* pb=headB;while(pa!=NULL){pa=pa->next;lenA++;}while(pb!=NULL){pb=pb->next;lenB++;}//计算长度差的绝对值size_t cnt=abs(lenA-lenB);//定义长短指针
LTN* longList=headA;
LTN* shortList=headB;
//根据实际情况调整
if(lenA<lenB)
{
longList=headB;
shortList=headA;
}
//让长指针先走
while(cnt--)
{
longList=longList->next;
}
//长短指针一起走
while(longList!=NULL)
{if(longList==shortList){return longList;}longList=longList->next;shortList=shortList->next;
}
//出来了说明不是相交链表
return NULL;}
博主题解
七.环形链表I
题目链接:141.环形链表
题目描述:
解题思路:
快慢指针,如果最后两个指针相遇,就存在环
兔子和乌龟在跑道上面跑,兔子套了乌龟一圈,最后二者会相遇,说明跑道是圆形的,即存在环
代码展示:
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/
typedef struct ListNode LTN;
bool hasCycle(struct ListNode* head) {// 快慢指针LTN* fast = head;LTN* slow = head;while (fast != NULL && fast->next !=NULL) // 顺序不能变,防止空指针解引用{slow = slow ->next;if(fast->next!=NULL)fast = fast->next->next;//相遇if (fast == slow)return true;}return false;
}
博主题解
八.环形链表II
题目链接:142.环形链表II
题目描述:
解题思路:
这里需要掌握一个技巧,就是找到相遇结点之后,我们再分别从头结点和相遇结点开始向后依次遍历,两个指针会在入环结点相遇,证明如下:
(字有点丑,大家不要介意ovo)
代码展示:
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode LTN;
struct ListNode *detectCycle(struct ListNode *head) {// 快慢指针LTN* fast = head;LTN* slow = head;while (fast != NULL && fast->next !=NULL) // 顺序不能变,防止空指针解引用{slow = slow ->next;if(fast->next!=NULL)fast = fast->next->next;//找到后和头一起向后遍历,就会相遇if (fast == slow){
LTN* pcur=head;
while(fast!=NULL)
{if(fast==pcur)return pcur;fast=fast->next;pcur=pcur->next;
}}}return NULL;
}
博主题解
总结
单链表部分的题目,我们需要去多多注意一些空链表
的情况(博主刚开始写WA了好多次),掌握一些快慢指针
的用法,和一些技巧,下一篇我会为大家带来单链表进阶
题目,希望大家可以多多支持,有什么问题可以评论留言或者后台私信,感谢大家
后续会开始感谢
数据结构
相关的知识性内容,C语言栏
会再上上传一些剩下的知识性内容!!!