目录
前言:上次链表OJ开了个素,这次直接上荤菜,让你回味无穷!
1、链表分割
链接:牛客:链表分割
题目:
题解:
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class Partition { public: ListNode* partition(ListNode* pHead, int x) { // write code here struct ListNode* lessHead,*lessTail,*greaterHead,*greaterTail; lessHead=lessTail=(struct ListNode*)malloc(sizeof(struct ListNode)); greaterHead=greaterTail=(struct ListNode*)malloc(sizeof(struct ListNode)); lessTail->next=greaterTail->next=NULL; struct ListNode* cur=pHead; while(cur) { //1、将小于x的放在less链表中 if(cur->val<x) { lessTail->next=cur; lessTail=lessTail->next; } //2、将大于或等于x放在greater链表中 else{ greaterTail->next=cur; greaterTail=greaterTail->next; } cur=cur->next; } //3、连接两个链表 lessTail->next=greaterHead->next; greaterTail->next=NULL; struct ListNode* list=lessHead->next; free(lessHead); free(greaterHead); return list; } };
讲解:
首先我们重新创建两个链表,一个放小于x的值,一个放大于或等于x的值,然后连接两个链表。
2、链表的回文结构
链接:链表的回文结构
题目:
题解:
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class PalindromeList { public: //找链表中间值(如果mid有两个则取后面那个) struct ListNode* Findmid(struct ListNode* head) { struct ListNode* slow=head; struct ListNode* fast=head; while(fast && fast->next) { slow=slow->next; fast=fast->next->next; } return slow; } struct ListNode* reverlist(struct ListNode* head) { struct ListNode* newHead=NULL; struct ListNode* cur=head; while(cur) { struct ListNode* next=cur->next; cur->next=newHead; newHead=cur; cur=next; } return newHead; } bool chkPalindrome(ListNode* A) { // write code here struct ListNode* mid=Findmid(A); struct ListNode* rHead=reverlist(mid); while(A&&rHead) { if(A->val==rHead->val) { A=A->next; rHead=rHead->next; } else { return false; } } return true; } };
讲解:
题目要求我们返回的是一个Bool值,也就是让我们判断这个链表是不是回文结构。
那么什么是回文结构?
比如:1->2->3->3->2->1是回文结构
1->2->3->4->3->2->1不是回文结构,就相当于这个链表要对称。
想要判断是不是回文结构也好办,先找到链表的中间值,然后再把中间值作为新的头,将后部分的链表倒置,再一个一个判断是否相等,如果中间有一个不相等,那么就返回false,等成功走完循环以后,就返回true。
3、相交链表
链接:相交链表
题目:
题解:
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) { int lenA=0,lenB=0; struct ListNode *tailA=headA; struct ListNode *tailB=headB; while(tailA) { lenA++; tailA=tailA->next; } while(tailB) { lenB++; tailB=tailB->next; } if(tailA!=tailB) { return NULL; } int gap=abs(lenA-lenB); struct ListNode *longList=headA,*shortList=headB; if(lenA<lenB) { shortList=headA; longList=headB; } while(gap--) { longList=longList->next; } while(shortList&&longList) { if(shortList==longList) return shortList; shortList=shortList->next; longList=longList->next; } return NULL; }
讲解:
首先,我们要先了解一下相交链表,我们先来判断一下下面这个属于相交链表吗?
答案是显而易见的,一个结点不可能 指向两个结点,所以,我们判断的时候,这种情况一定要考虑到,也就是说,两个链表从头开始走,走到尾部,两个结点不一样,就肯定不是相交链表。
题目中需要我们返回相交的结点,所以也就是说,两个链表第一个相等的结点就是相交结点,如果两个链表长度相等倒好判断,但如果不相等呢,我们就可以采用快慢指针,先求出两个链表的长度差gap,再让长的先走gap步,再两个一起走,走到相等的时候就可以返回了。
4、环形链表
链接:环形链表
题目:
题解:
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode *detectCycle(struct ListNode *head) { struct ListNode *fast=head; struct ListNode *slow=head; while(fast && fast->next) { slow=slow->next; fast=fast->next->next; if(slow==fast) { struct ListNode* meet=slow; while(meet!=head) { meet=meet->next; head=head->next; } return meet; } } return NULL; }
讲解:
题目要求是返回入环的起始结点,首先,我们还要判断的是这个链表是不是环形链表,然后再去求入环的起始结点。
那么我们怎样来判断链表是否带环呢?这里我们还是用到快慢指针,slow一次走一步,fast一次走两步,最后,fast肯定能追上slow,所以带环的结果就是fast=slow。我们来推理一下为什么slow一次走一步,fast一次走两步就一定会相遇。
那如果说,slow每次走一步,fast每次走三步呢?fast每次走四步呢?最后fast一定会追上slow吗?答案是不确定。
当fast每次走三步的时候,进环后,slow每走一步,两个的距离减少2,也就是N-2,下一次是N-4,当N为偶数时,会减到0,但N为奇数时,会减到1,再到-1,刚好又错过,所以是不确定的。同理,fast每次走四步也是同样的道理。
5、复制带随机指针的链表
链接:复制带随机指针的链表
题目:
题解:
/** * Definition for a Node. * struct Node { * int val; * struct Node *next; * struct Node *random; * }; */ struct Node* copyRandomList(struct Node* head) { struct Node* cur=head; struct Node* copyHead=NULL; struct Node* copyTail=NULL; //1、把结点拷贝下来链接到原结点 while(cur) { struct Node* copy=(struct Node*)malloc((sizeof(struct Node))); copy->val=cur->val; copy->next=cur->next; cur->next=copy; cur=cur->next->next; } //2、更新拷贝结点的random cur=head; while(cur) { struct Node* copy=cur->next; if(cur->random==NULL) { copy->random=NULL; } else { copy->random=cur->random->next; } cur=cur->next->next; } //3、将拷贝结点解下来,连在一起 cur=head; while(cur) { struct Node* copy=cur->next; struct Node* next=copy->next; cur->next=next;//恢复原链表 if(copyTail==NULL) { copyHead=copyTail=copy; } else { copyTail->next=copy; copyTail=copy; } cur=next; } return copyHead; }
讲解:
这个题的关键就在于如何处理新链表的random指针,random是随机的,所以很难定,这里我们有个方法,就是将原来的结点拷贝下来,一次接在原结点的后面,然后我们发现,新拷贝后的random指向的就是原结点的random的下一个,但当原结点的random指向的是NULL时,拷贝结点的random指向的也是NULL(这一点要注意一下)。最后再把拷贝结点解下来,链接在一起,这样就很好的解决了新链表的random指针了。
今天的荤菜到此结束,希望你可以收货满满!!!