系列文章目录
文章目录
前言
数据结构与算法
是计算机领域的核心,既是面试考察重点,也是优化项目性能的关键。而刷题是掌握它最有效的方式,能帮我们巩固理论、提升解题能力。我选择
LeetCode
和NowCode
作为主要刷题平台:LeetCode 题目丰富、分类清晰,适合夯实基础;NowCode贴近国内企业
笔试场景,助力对接实战需求,二者互补性强。这份刷题记录不只是题目与答案的罗列,更会记录解题思路、难点易错点,以及解法优化过程。希望它能成为我的
复盘工具
,也为其他学习者提供参考
。接下来,就从第一道题开始,在刷题中积累提升,让数据结构与算法成为解决问题的有力工具。
正文
一.移除链表元素
题目链接 :203.移除链表元素
题目描述 :
解题思路 :创建新链表,把原链表中的值依次尾插到新链表的尾部
代码展示:
c
/**
* 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.反转链表
题目描述 :
解题思路:
创建三个指针,分别指向,前一个节点,当前节点,后一个节点
依次反转当前节点的指向,利用后一个节点来 让三个指针继续向后走
代码展示:
c
/**
* 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.链表的中间结点
题目描述 :
解题思路 :
创建一个快指针,一个慢指针
快指针每次走两步
慢指针每次走一步
当快指针走完,慢指针指向的就是链表的中间结点
代码展示:
c
/**
* 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.合并两个有序链表
题目描述 :
解题思路 :
创建一个哨兵位,依次比较两个链表的值,按序插入新链表
一个链表插完,把另一个剩下的直接插到后面
代码展示:
c
/**
* 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;
}
五.链表的回文结构
题目链接 :链表的回文结构
题目描述 :
解题思路 :
会了上面两道,这道题目就很简单了
先快慢指针找中间节点
从中间节点开始三指针逆置
逆置完比较
逆置完之后,对逆置那部分链表与原来的链表进行比较
代码展示:
c
/*
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.相交链表
题目描述 :
解题思路 :
单链表,方向唯一
如果相交,那么最后肯定会到相同的终点
由于交点之后的路程一样,差别就在前面
①分别计算两个链表的长度
②计算差值
③让长链表先走差的绝对值步,这样两个链表到交点距离相同了
④再一起走到的同一个位置,就是交点了
代码展示:
c
/**
* 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.环形链表
题目描述:
解题思路:
快慢指针,如果最后两个指针相遇,就存在环
兔子和乌龟在跑道上面跑,兔子套了乌龟一圈,最后二者会相遇,说明跑道是圆形的,即存在环
代码展示:
c
/**
* 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)
代码展示:
c
/**
* 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语言栏
会再上上传一些剩下的知识性内容!!!