1. 找到链表的中间节点
思路:用两个指针,初始时都指向链表头,然后一个每次往前走一步,另一个每次往前走两步,走两步的指针走到尾时,走一步的指针的位置即为链表的中间位置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Node* findMiddleNode(Node* pHead) { if (pHead == nullptr) { return(pHead); } if (pHead->next == nullptr) { return(pHead); } Node *pSlow = pHead; Node *pFast = pHead; while (pFast->next != nullptr && pFast->next->next!=nullptr) { pSlow = pSlow->next; pFast = pFast->next->next; } return(pSlow); }
2. 找到倒数第K个节点
思路:设置两个指针,让其中一个指针先走K步,然后两个指针等速往前走,先走的指针走到尾时,后走指针的位置即为倒数第K个节点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Node* findReverseKNode(Node* pHead, int k) { Node* kNode = nullptr; Node* p = pHead; for (int i = 0; i < k-1; i++) { if (p == nullptr) { return(nullptr); } p = p->next; } kNode = pHead; while (p != nullptr) { p = p->next; kNode = kNode->next; } return(kNode); }
3. 链表倒转
思路:假设p1->p2->p3,倒转p1->p2的时候,需要记录p3
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Node* reverseList(Node* pHead) { if (pHead == nullptr || pHead->next == nullptr) { return(nullptr); } Node* p = pHead; Node* pNext = p->next; while (pNext != nullptr) { Node *pNextNext = pNext->next; pNext->next = p; p = pNext; pNext = pNextNext; } pHead->next = nullptr; pHead = p; return(pHead); }
4. 找到两个链表的交叉点
思路:如果两个链表交叉,则可以想象两个链表构成Y形,只是Y的分叉部分不一样长,所以解法为先求出两个链表的长度l1和l2,然后求差值|l1-l2|,设置两个指针分别指向两个链表头,让指向长链表的指针先走|l1-l2|步,然后两个指针再一起走,判断是否相等
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Node* getCrossNode(Node* pHead1, Node* pHead2) { Node* p1 = pHead1; Node* p2 = pHead2; if (p1 == nullptr || p2 == nullptr) { return(nullptr); } int l1 = 0; while (p1 != nullptr) { l1++; p1 = p1->next; } int l2 = 0; while (p2 != nullptr) { l2++; p2 = p2->next; } p1 = pHead1; p2 = pHead2; if (l2 > l1) { for (int i = 0; i < (l2 - l1); i++) { p2 = p2->next; } } else if (l1 > l2) { for (int i = 0; i < (l1 - l2); i++) { p1 = p1->next; } } while (p1 != nullptr && p2 != nullptr && p1 != p2) { p1 = p1->next; p2 = p2->next; } if (p1 == p2) { return(p1); } else { return(nullptr); } }
5. 判断是否存在环
思路:设置两个指针,同时指向表头,一个每次往前走一步,另一个走两步,如果两个指针相遇,即存在环
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
bool doesContainLoop(Node* pHead) { if (pHead == nullptr || pHead->next == nullptr) { return(false); } Node* pSlow = pHead; Node* pFast = pHead; while (pFast != nullptr && pFast->next != nullptr && pSlow != pFast) { pSlow = pSlow->next; pFast = pFast->next->next; } if (pSlow == pFast) { return(true); } else { return(false); } }
6. 求环的起点
思路:
假设两个指针,在Z点相遇,相遇时慢的走了m圈,快的走了n圈,则(a+b+m*r)*2=a+b+n*r,可以推导出a=(n-2m)*r-b=(n-2m-1)*r+r-b=(n-2m-1)*r+c,所以可以设置两个指针,一个从表头X点开始走,另一个从相遇点Z开始走,两个指针相遇的位置即为环的起点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Node* getLoopOrigin(Node* pHead) { if (pHead == nullptr || pHead->next == nullptr) { return(nullptr); } Node* pSlow = pHead; Node* pFast = pHead; while (pFast != nullptr && pFast->next != nullptr && pSlow != pFast) { pSlow = pSlow->next; pFast = pFast->next->next; } if (pSlow != pFast) { return(nullptr); } Node* p = pHead; while (p != pSlow) { p = p->next; pSlow = pSlow->next; } return(p); }
7. 求环的长度
思路:让两个指针都从相遇点开始走,步速为2的指针和步速为1的指针再次相遇时,步速为1的指针所走的长度即为环的长度
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
int getLoopLength(Node* pHead) { if (pHead == nullptr || pHead->next == nullptr) { return(0); } Node* pSlow = pHead; Node* pFast = pHead; while (pFast != nullptr && pFast->next != nullptr && pSlow != pFast) { pSlow = pSlow->next; pFast = pFast->next->next; } if (pSlow != pFast) { return(0); } int loopLen = 0; pSlow = pSlow->next; pFast = pFast->next->next; while (pSlow != pFast) { loopLen++; pSlow = pSlow->next; pFast = pFast->next->next; } loopLen++; return(loopLen) }
8. 求有环链表的长度
思路:6求出了环的起点,可以得出无环部分的长度,加上7的环的长度,即为有环链表的长度