新建一个哨兵位,用cur指针遍历原链表,cur->val!=val,将该节点连接至哨兵链表,反之释放。迭代遍历原链表即可,最后记得将哨兵链表的尾节点的next置空!!!
- struct ListNode* removeElements(struct ListNode* head, int val){
- struct ListNode* guard=(struct ListNode*)malloc(sizeof(struct ListNode));
- struct ListNode* guardcur=guard;//用于记录哨兵链表的尾插
- struct ListNode* cur=head;//用于原链表的遍历
- while(cur)
- {
- struct ListNode* next=cur->next;
- if(cur->val!=val)
- {
- guardcur->next=cur;
- guardcur=cur;
- }
- else
- {
- free(cur);
- }
- cur=next;
- }
- guardcur->next=NULL;//最后需要把尾节点的next置空
- head=guard->next;
- free(guard);//记得释放哨兵位
- return head;
- }
遍历原链表,将每一个节点取下来,不断头插反转链表
- struct ListNode* reverseList(struct ListNode* head){
- struct ListNode* cur=head;
- struct ListNode* newhead=NULL;
- while(cur)
- {
- struct ListNode* next=cur->next;
- cur->next=newhead;
- newhead=cur;
- cur=next;
- }
- return newhead;
- }
思路1:可以遍历计数找中间节点
思路2:快慢指针,快指针走两步,慢指针走一步,快指针走到尾节点或者空节点,慢指针就指向链表的中间节点
- struct ListNode* middleNode(struct ListNode* head){
- struct ListNode* fast=head,*slow=head;
- while(fast!=NULL&&fast->next!=NULL)
- {
- fast=fast->next->next;
- slow=slow->next;
- }
- return slow;
- }
注意,while循环内两个条件的顺序不能颠倒。如果颠倒,当fast为NULL时,先判断fast->next!=NULL,这是一个对空指针解引用的问题!
定义快慢指针,不难发现,快指针需要比慢指针快k-1步,所以先让快指针向前走k-1步,判断fast==NULL是防止原链表为空,判断fast->next=NULL是因为,后面fast=fast->next,说明k大于链表长度。
- struct ListNode* getKthFromEnd(struct ListNode* head, int k){
- struct ListNode* fast=head,*slow=head;
- int tmp=k-1;//快慢指针相差的距离
- while(tmp--)
- {
- if(fast==NULL||fast->next==NULL)//考虑下值大于节点个数的问题
- return NULL;
- fast=fast->next;
- }
- while(fast->next)
- {
- fast=fast->next;
- slow=slow->next;
- }
- return slow;
- }
创建一个哨兵节点,用两个指针分别指向原链表,将val小的节点尾插即可。记得释放哨兵位。
- struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
- struct ListNode* cur1=list1,*cur2=list2;
- struct ListNode* guard=(struct ListNode*)malloc(sizeof(struct ListNode));
- struct ListNode* guardcur=guard;
- struct ListNode* small,*big;
- while(cur1!=NULL&&cur2!=NULL)
- {
- if(cur1->val>cur2->val)
- {
- small=cur2;
- big=cur1;
- cur2=cur2->next;
- }
- else
- {
- small=cur1;
- big=cur2;
- cur1=cur1->next;
- }
- guardcur->next=small;
- guardcur=small;
- }
- if(cur1==NULL)
- {
- guardcur->next=cur2;
- }
- else
- {
- guardcur->next=cur1;
- }
- struct ListNode* head=guard->next;
- free(guard);
- return head;
- }
创建两个哨兵位,遍历原链表,将val小于x和大于等于x的节点分别尾插至两个哨兵链表,再将两个链表连接起来。注意要把大的哨兵链表的尾指针置空。
- class Partition {
- public:
- ListNode* partition(ListNode* pHead, int x) {
- ListNode* guard1=(ListNode*)malloc(sizeof(ListNode));//哨兵位1
- ListNode* guard2=(ListNode*)malloc(sizeof(ListNode));//哨兵位2
- ListNode* small=guard1,*big=guard2;
- ListNode* cur=pHead;//用于遍历链表
- while(cur)
- {
- if(cur->val
- {
- small->next=cur;
- small=small->next;
- cur=cur->next;
- }
- else
- {
- big->next=cur;
- big=big->next;
- cur=cur->next;
- }
- }
- big->next=NULL;
- small->next=guard2->next;//链接两个链表
- free(guard2);
- pHead=guard1->next;
- free(guard1);
- return pHead;
- }
- };
七、回文链表
1、思路
1、找出中间节点(本文题三)
2、对后半段进行逆置(本文题二)
3、比对val是否相等,当逆置指针为空,比对结束
2、代码
- bool isPalindrome(struct ListNode* head){
- //先用快慢指针找到中间节点
- struct ListNode* fast=head,*slow=head;
- while(fast!=NULL&&fast->next!=NULL)
- {
- slow=slow->next;
- fast=fast->next->next;
- }
- //现在slow是中间节点
- //反转后半部分链表
- struct ListNode* newnode=NULL;
- struct ListNode* cur=slow;
- while(cur)
- {
- struct ListNode* next=cur->next;
- cur->next=newnode;
- newnode=cur;
- cur=next;
- }
- //比较
- fast=head;
- slow=newnode;
- while(slow)//fast和slow会同时为空或slow先空
- {
- if(fast->val!=slow->val)
- return false;
- fast=fast->next;
- slow=slow->next;
- }
- return true;
- }
八、相交链表
1、思路
1、分别遍历链表,算出两个链表的长度。
2、让长链表先往前走,走到和短链表一样长
3、两个链表再同时走,走到两个指针一样即为相交点,如果走到空还没有找到,则不相交
2、代码
- struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
- struct ListNode* curA=headA,*curB=headB;//用于遍历链表
- int lenA=1,lenB=1;//统计A和B的长度
- while(curA)
- {
- curA=curA->next;
- ++lenA;
- }
- while(curB)
- {
- curB=curB->next;
- ++lenB;
- }
- int a=abs(lenA-lenB);//A和B链表长度的差值
- struct ListNode* longlist=headA,*shortlist=headB;//设两个节点
- if(lenA
//通过一个判断,让longlist指向较长的链表 - {
- longlist=headB;
- shortlist=headA;
- }
- while(a--)//让较长的链表先把差值走掉
- {
- longlist=longlist->next;
- }
- while(longlist)
- {
- if(longlist==shortlist)
- return longlist;
- longlist=longlist->next;
- shortlist=shortlist->next;
- }
- return NULL;
- }
九、环形链表
1、思路
定义快慢指针,快指针一次走两步,慢指针一次走一步,如果相遇,说明有环,当快指针等于NULL,说明没环
2、代码
- bool hasCycle(struct ListNode *head) {
- //快指针一次走两步,慢指针一次走一步,快指针先进环,慢指针后进环,相对静止
- //能追上说明有环,有一个指针为空说明没环
- struct ListNode* fast=head,*slow=head;
- while(fast&&fast->next)//这里不用判断slow是否为空,不管带不带环,slow没有机会为空
- {
- fast=fast->next->next;
- slow=slow->next;
- if(fast==slow)
- return true;
- }
- return false;
- }
十、环形链表 II
1、思路一
1、定义快慢指针,快指针一次走两步,慢指针一次走一步,找到相遇点(本文题九)
2、将相遇点的后一个节点当成另一个链表的头结点,问题转化为本文题八
2、代码
- 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)
- break;
- }
- if(fast==NULL||fast->next==NULL)
- return NULL;
-
- struct ListNode* headA=fast->next;//两个链表的头结点
- struct ListNode* curA=headA;//cur用于遍历统计链表长度
- struct ListNode* headB=head;
- struct ListNode* curB=headB;
- int lenA=1,lenB=1;
- while(curA!=fast)
- {
- curA=curA->next;
- ++lenA;
- }
- while(curB!=fast)
- {
- curB=curB->next;
- ++lenB;
- }
- struct ListNode* longlist=headA,*shortlist=headB;
- if(lenA
- {
- longlist=headB;
- shortlist=headA;
- }
- int a=abs(lenA-lenB);//长度的差值
- while(a--)
- {
- longlist=longlist->next;
- }
- while(1)
- {
- if(longlist==shortlist)
- return longlist;
- longlist=longlist->next;
- shortlist=shortlist->next;
- }
- }
3、思路二
1、设进环前的长度为L,入环点到相遇点的距离为X,环的长度为R
2、两指针相遇时,slow走的距离是L+X,fast走的距离是L+N*R+X,N为fast指针在环里绕的圈数(注意这里N一定大于等于1,因为快慢指针在环内相遇,说明快指针和慢指针相遇前,快指针起码路过了一次相遇点)(而且当慢指针进环后,快指针肯定会一圈追上慢指针,因为快指针比慢指针每次多走一步,相对静止,走一圈的距离必定追上)
3、那么2*(L+X)=L+N*R+X,化简得L=N*R-X,再化简得L=(N-1)*R+R-X
4、可得结论:一个指针从头结点开始走,另一个指针从相遇点开始走,那么他们会在入口处相遇
4、代码
- struct ListNode *detectCycle(struct ListNode *head) {
- struct ListNode* fast=head,*slow=head;//找相遇点
-
- while(fast!=NULL&&fast->next!=NULL)
- {
- fast=fast->next->next;
- slow=slow->next;
- if(fast==slow)
- break;
- }
- if(fast==NULL||fast->next==NULL)
- return NULL;
- slow=head;
- while(fast!=slow)
- {
- fast=fast->next;
- slow=slow->next;
- }
- return fast;
- }
十一、复制带随即指针的链表
1、思路
题目要求是复制一个一模一样的链表,难点在于random指针的控制
1、在每个节点后边插入一个节点,复制对应的val
2、再复制random指针,复制时要分空和非空情况,对于空,复制节点random为NNULL;非空,
则为cur->next->random=cur->random->next
3、再创建两个哨兵节点,将原链表与复制链表节点分开。
2、代码
- struct Node* copyRandomList(struct Node* head) {
- struct Node* cur=head;
- while(cur)//插入复制节点
- {
- struct Node* next=cur->next;
- struct Node* newnode=(struct Node*)malloc(sizeof(struct Node));
- cur->next=newnode;
- newnode->val=cur->val;
- cur=next;
- newnode->next=cur;
- }
- cur=head;
- while(cur)//复制random指针
- {
- if(cur->random==NULL)
- cur->next->random=NULL;
- else
- {
- cur->next->random=cur->random->next;
- }
- cur=cur->next->next;
- }
- //将链表复原
- cur=head;
- struct Node* guard=(struct Node*)malloc(sizeof(struct Node));
- struct Node* guardcopy=(struct Node*)malloc(sizeof(struct Node));
- guardcopy->next=NULL;
- struct Node* curA=guard,*curB=guardcopy;
- int count=1;
- while(cur)
- {
- struct Node* next=cur->next;
- if(count%2==1)
- {
- curA->next=cur;
- curA=cur;
- }
- else
- {
- curB->next=cur;
- curB=cur;
- }
- cur=next;
- ++count;
- }
- curA->next=NULL;
- struct Node* newhead=guardcopy->next;
- free(guardcopy);
- free(guard);
- return newhead;
- }
-
相关阅读:
患上肝内胆管结石症状有哪些?
数据库——集群与读写分离 <--->设计优化【补】
竞赛无人机搭积木式编程(四)---2023年TI电赛G题空地协同智能消防系统(无人机部分)
力扣每日一题 自定义字符串排序
springboot源码理解三、自动配置(第三方依赖中的bean)
跑得“快”还要走得“稳”,看头部车企数字化实践怎么做
Gradle系列——Gradle文件操作,Gradle依赖(基于Gradle文档7.5)day3-1
系统介绍浏览器缓存机制及前端优化方案
荣耀手机如何开启地震预警功能
已解决 TypeError: Fetch argument None has invalid type <class ‘NoneType‘>
-
原文地址:https://blog.csdn.net/gfdxx/article/details/126318887