1.判断单链表是否带环?若带环,求环的长度?求环的入口点?
分析:
(1) 如果一个链表不带环,那么他的结尾就是NULL。
(2) 如果一个链表带环,设置一个快慢指针,快指针每次走两步,慢指针每次走一步,考虑一下,如果带环他们是不是会在环里面相遇?既然如此。可以设置一个走一步,一个走三步么?很明显是不行的。为什么不行?可以画一个图来证明它。如果快慢指针位于如图所示位置,就不可能会相交了。而选择一个走一步,一个走两步可以解决这个问题。
//检测是否带环
ListNode* CycleList(ListNode* pList)
{
ListNode* fast = pList;
ListNode* slow = pList;
if(pList == NULL || pList->next == NULL)
return NULL;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
if(slow == fast)
return slow;
}
return NULL;
}
求环的长度
分析:当我们证明了链表带环以后,就找到了一个节点,然后把这个节点循环走一圈是不是就求出了环的长度?
//求环的长度
int CycleLength(ListNode* pList)
{
ListNode* first = CycleList(pList);
ListNode* tmp = first;
int length = 1;
while(first->next!= tmp)
{
first = first->next;
length++;
}
return length;
}
求环的入口点
分析: 我们可以设置一个快慢指针,长指针走的路程是慢指针走的路程的两倍因此我们可以从图中得到以下关系式
分析清楚了写代码也就不难了吧。
//环的入口点
ListNode* entryCycleList(ListNode* pList)
{
ListNode* meet = CycleList(pList);
ListNode* first = pList;
while(first != meet)
{
first = first->next;
meet = meet->next;
}
pList = first;
return first;
}
判断两个链表是否相交,若相交,求交点
分析:
(1)链表可能带环,可能不带环
1)链表不带环
a. 链表不带环的情况我们前面分析过了
2)链表带环分为以下几种情况
//判断两个链表是否相交
ListNode* intersectList(ListNode* pList1, ListNode* pList2)
{
ListNode* tmp1 = NULL;
ListNode* tmp2 = NULL;
if(pList1 == NULL || pList2 == NULL)
return NULL;
while(pList1->next != NULL)
{
pList1 = pList1->next;
}
while(pList2->next != NULL)
{
pList2 = pList2->next;
}
tmp1 = pList1;
tmp2 = pList2;
if(tmp1 == tmp2)
return tmp1;
return NULL;
}
//求不相交的两个链表的交点
ListNode* intersectNode(ListNode* pList1, ListNode* pList2)
{
ListNode* first = pList1;
ListNode* second = pList2;
ListNode* inter = intersectList(pList1, pList2);
if(inter == NULL)
return NULL;
while(second->next!= NULL)
{
second = second->next;
}
second->next = first;
return entryCycleList(pList2);
}
//判断两个链表是否相交
ListNode* JudgeCycleList(ListNode* pList1, ListNode* pList2)
{
//1.检测是否带环,两个都不带环判断最后一个节点是否相等
//2.一个带环,一个不带环永不相交
//3.两个带环,环外相交
//4,两个带环,环内相交
ListNode* first = CycleList(pList1);
ListNode* second = CycleList(pList2);
ListNode* inter = NULL;
if(first == NULL && second == NULL)//两个链表都不带环
{
inter = intersectNode(pList1, pList2);
return inter;//找入口点
}
else if(first == NULL || second == NULL)
return NULL;
else//两个都带环
{
ListNode* interNode1 = entryCycleList(pList1);
ListNode* interNode2 = entryCycleList(pList2);
ListNode* tmp1 = interNode1;
ListNode* tmp2 = interNode2;
while(interNode1->next != tmp1)
{
while(interNode2->next!= tmp2)
{
if(interNode1 == interNode2)
return interNode1; //两链表相交
interNode2 = interNode2->next;
}
if(interNode1 == interNode2)
return interNode2;
interNode1 = interNode1->next;
}
}
return NULL;
}
//链表交点(可能循环)
ListNode* FindCycleNode(ListNode* pList1, ListNode* pList2)
{
ListNode* entry = entryCycleList(pList1);
ListNode* tmp = JudgeCycleList(pList1, pList2);
if(tmp == NULL) //为空表示不相交
return NULL;
else
{
ListNode* inter = CycleList(pList1);
//ListNode* entry = entryCycleList(pList1);
ListNode* next = NULL;
while(inter->next != entry)
{
inter = inter->next;
}
next = inter;
next->next = NULL;
entry = intersectNode(pList1, pList2);
}
return entry;
}
对于链表的面试题,只要分析清楚以后,只需要为数不多的代码就可以写完了,最重要的就是分析,不落下任何一种可能的情况。