目录
一.【Leetcode203】移除链表元素
1.链接
2.题目再现
A.双指针法
B.类尾删法
C.哨兵位
二.【Leetcode876】链表的中间节点
1.链接:链表的中间节点
2.题目再现
3.解法:快慢指针
三.链表中倒数第k个节点
1.链接:链表中倒数第k个节点
2.题目再现
3.解法 :快慢指针
一.【Leetcode203】移除链表元素
1.链接
移除链表元素
2.题目再现
A.双指针法
1.创建一个指针 cur=head 和一个指针 pre=NULL;
2.用cur->val 与 val 比较,如果不相等则把 cur 赋给 pre 使cur 指向下一个节点,即
cur=cur->next;
3.如果相等则使 pre 的 next 指向 cur 的 next ,即:
pre->next=cur->next ,然后再 free 掉 cur ,最后再使 cur 等于 pre 的 next,注意在进行这些步骤之前要判断 pre 是否为空 ,若为空即为头删;
演示:
双指针
代码:
- struct ListNode* removeElements(struct ListNode* head, int val)
- {
- struct ListNode*pre=NULL;
- struct ListNode*cur=head;
- while(cur)
- {
- if(cur->val!=val)
- {
- pre=cur;
- cur=cur->next;
- }
- else
- {
- if(pre==NULL)
- {
- head=cur->next;
- free(cur);
- cur=head;
- }
- else
- {
- pre->next=cur->next;
- cur=pre->next;
- }
- }
- }
- return head;
- }
B.类尾删法
1.创建一个新的指针newhead ,同时为了省去找尾的麻烦,我们可以定义一个尾指针 tail 来保存尾节点;
2.再创建一个指针 cur =head ,用来遍历链表;
3.如果 cur->val != val ,则尾插 ,注意要判断 tail 是否为空 ,类似于单链表的尾插那部分,如果不理解的话,可查看文章 :单链表的增删查改;
4.如果 cur->val ==val,则 cur=cur->next ;
5.最后要将尾节点置空。
演示:
类尾插
代码:
- struct ListNode* removeElements(struct ListNode* head, int val)
- {
- struct ListNode *newhead=NULL;
- struct ListNode*tail=NULL;
- struct ListNode*cur=head;
- while(cur)
- {
- if(cur->val!=val)
- {
- if(tail==NULL)
- {
- newhead=tail=cur;
- }
- else
- {
- tail->next=cur;
- tail=tail->next;
- }
- cur=cur->next;
- }
- else
- {
- cur=cur->next;
- }
- }
- if(tail)
- {
- tail->next=NULL;
- }
- return newhead;
- }
C.哨兵位
1.malloc 一个哨兵位节点 dummyhead,使其 next 指向 head ;
2.再定义一个节点 tmp = dummyhead ,用这个遍历链表;
3.注意因为 tmp ->next 才是 head ,所以 while 里要写 tmp->next !=NULL
演示:
移除链表元素 哨兵位法动态演示
代码:
- struct ListNode* removeElements(struct ListNode* head, int val)
- {
- struct ListNode*dummyhead=(struct ListNode*)malloc(sizeof(struct ListNode));
- dummyhead->next=head;
- struct ListNode*tmp=dummyhead;
- while(tmp->next!=NULL)
- {
- if(tmp->next->val==val)
- {
- tmp->next=tmp->next->next;
- }
- else
- {
- tmp=tmp->next;
- }
- }
- return dummyhead->next;
- }
二.【Leetcode876】链表的中间节点
1.链接:链表的中间节点
2.题目再现
3.解法:快慢指针
1.定义一个快指针 fast 和一个慢指针 slow 都初始化为 head;
2.遍历链表,快指针一次走2步,慢指针一次走1步 ;
3.注意:因为链表的长度可能是单数也可能是双数,所以当我们已 fast 是否为NULL 作为循环控制条件的话,要在 fast 走2步前判断 fast->next 是否为空;
4.最后慢指针就是中间节点。
演示:
链表中间节点 快慢指针动态演示
代码:
- struct ListNode* middleNode(struct ListNode* head)
- {
- struct ListNode*slow=head;
- struct ListNode*fast=head;
- while(fast)
- {
- if(fast->next==NULL) //注意判断
- {
- break;
- }
- else
- {
- fast=fast->next->next; //fast 走2步
- }
- slow=slow->next; //slow 走1步
- }
- return slow; //返回慢指针
- }
三.链表中倒数第k个节点
1.链接:链表中倒数第k个节点
2.题目再现
3.解法 :快慢指针
1.定义一个快指针 fast 和一个慢指针 slow 都初始化为 head;
2.因为倒数第k个节点和尾节点的差为 k-1 ,所以我们先让快指针先走 k-1 步;
或者因为尾节点所指向的NULL 和倒数第k个节点相差k,也可以先让快指针走k步;
这个时候慢指针不动;
3.快指针走完后,快指针和慢指针依次走,每次只走1步;
注意,如果是k-1,那么遍历结束的条件是fast->next 是否为空 ,如果是k,那么遍历结束的条件是fast 是否为空;
4.返回慢指针。
演示:
链表倒数第K个节点 快慢指针动态演示
代码:
- struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
- {
- if(pListHead==NULL)
- {
- return NULL;
- }
- struct ListNode*slow=pListHead;
- struct ListNode*fast=pListHead;
- while(k--) //这里以先走k步为例
- {
- if(fast==NULL)
- {
- return NULL;
- }
- fast=fast->next;
- }
- while(fast)
- {
- slow=slow->next;
- fast=fast->next;
- }
- return slow;
- }
😽本篇文章到此就结束了,若有错误或是建议,欢迎小伙伴们指出;😻
😍请多多支持博主哦~🥰
🤩谢谢你的阅读~😃