问题1:判断链表是否带环
解题思路:
用两个指针,快指针一次走两步,慢指针一次走一步,如果两指针相遇,那么链表带环,若两指针不相遇,则链表不带环。
pLinkNode CheckCycle(pList head) { pLinkNode fast = head; pLinkNode slow = head; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; if (fast == slow) { return slow; 两指针相遇,链表带环,返回相遇点 } } return NULL; //若两指针不相遇,返回null,链表不带环 }
问题2:若链表带环则求环的长度
解题思路:
面试题1已经判断过链表带环,且返回两指针相遇节点,求环长度时我们可以让一个指针从相遇节点处开始遍历,当再次回到相遇节点时,它走过的步数就是环的长度。
int GetCircleLength(pLinkNode meet) { pLinkNode cur = meet; int count = 0; do { cur = cur->next; count++; } while (cur != meet); return count; }
问题3:获取环入口点
解题思路:
方法一:假设上图是一个单链表,两指针走到相遇节点时,慢指针走了x+y步,快指针走了x+y+nl步,(l为环的长度),由于快指针速度是慢指针速度的一倍,那么就有以下的等式:
(x+y)*2=x+y+nl;
化解可得:
x=nl-y;
那解题时我们可以用两个指针,一个指针从链表的开始位置走,另一个指针从相遇的节点处开始走,也就是y,两个指针相遇的节点就是入口点。
pLinkNode GetCycleEntryNode(pList head, pLinkNode MeetNode) { pLinkNode Entry= head; pLinkNode meet = MeetNode; while (meet != Entry) { Entry = Entry->next; meet = meet->next; } return Entry; }
方法二:
将相遇的节点处断开,转化为两条链表相交求交点问题,两个指针meet和Entry分别遍历到链表尾,记录两链表的长度len_l1和len_l2,然后让较长的链表先走len=|len_l1 - len_l2|步,然后两指针一起走,直到两指针相遇,相遇的节点就是链表的交点,即环的入口点。
pLinkNode _GetCycleEntryNode(pList head, pLinkNode MeetNode)//链表带环转化为链表相交问题获取入口
{ pLinkNode Entry = head; pLinkNode meet = MeetNode->next; int len_head = 0; int len_meet = 0; int len = 0; while (Entry != MeetNode) //求链表长度 { len_head++; Entry = Entry->next; } while (meet != MeetNode)//求链表长度 { len_meet++; meet = meet->next; } Entry = head; meet = MeetNode->next; if (len_head > len_meet) { len = len_head - len_meet; while (len--) { Entry = Entry->next; }//较长链表先走len=|len_l1 - len_l2|步 } else { len = len_meet - len_head; while (len--) { meet = meet->next; }//较长链表先走len=|len_l1 - len_l2|步 } while (meet != Entry) { Entry = Entry->next; meet = meet->next; } //两指针同时走,相遇节点就是环入口点 return Entry; }