1.判斷單鏈表是否帶環?若帶環,求環的長度?求環的入口點?並計算每個算法的時間複雜度&空間複雜度。
判斷是否帶環:利用快慢指針,快指針每次走兩步,慢指針每次走一步,如果快慢指針相遇,則該鏈表帶環。
ListNode* IsHaveLoop(ListNode* plist)
{
if (plist == NULL)
{
return NULL;
}
ListNode* fast = plist;
ListNode* slow = plist;
while (fast->next&&fast)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
return slow;
}
}
return NULL;
}
求環的長度:相遇之後,每次追一步,再次相遇剛好追一圈——環的長度。
int SizeofLoop(ListNode* plist)//求環長
{
ListNode* meet = IsHaveLoop(plist);
if (meet)
{
int count = 1;
ListNode* tmp = meet->next;
while (tmp != meet)
{
tmp = tmp->next;
count++;
}
return count;
}
return 0;
}
求環入口點: T——尾長(非環長度),S——慢指針入環到被追上, C——快指針追慢指針多跑的圈。那麼,慢指針走的路程爲 T+S,快指針走的路程爲 T+S+C,可得 2(T+S)=T+S+C,T=C-S,此時,一個指針從起點出發走T步,一個指針從快慢指針相遇點出發走 C-S 步,此時兩指針剛好都在入口點。
ListNode* EnterNode(ListNode* plist)
{
ListNode* meet = IsHaveLoop(plist);
if(meet)
{
while (meet != plist)
{
meet = meet->next;
plist = plist->next;
}
return plist;
}
return NULL;
}
2.判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表不帶環)
ListNode* Intersect(ListNode* pList1, ListNode* pList2)
{
int count1 = 0, count2 = 0;
ListNode* p1 = pList1, *p2 = pList2;
while (p1->next)
{
count1++;
p1 = p1->next;
}
while (p2->next)
{
count2++;
p2 = p2->next;
}
if (p1 != p2)
return NULL;
if (count1 >= count2)
{
count1 -= count2;
while (count1--)
pList1 = pList1->next;
while (pList1 != pList2)
{
pList1 = pList1->next;
pList2 = pList2->next;
}
return pList1;
}
else
{
count2 -= count1;
while (count2--)
pList2 = pList2->next;
while (pList1 != pList2)
{
pList1 = pList1->next;
pList2 = pList2->next;
}
return pList1;
}
}
3.判斷兩個鏈表是否相交,若相交,求交點。(假設鏈表可能帶環)【升級版】
ListNode* Intersect(ListNode* plist1, ListNode* plist2)//判斷鏈表是否相交升級版
{
//先判斷是否爲空
if ((plist1 == NULL) || (plist2 == NULL))
{
return NULL;
}
ListNode* enter1 = EnterNode(plist1);
ListNode* enter2 = EnterNode(plist2);
//1和2:若兩個鏈表都無環,則直接用題目二的函數解決
if ((enter1 == NULL) && (enter2 == NULL))
{
return IsListIntersect(plist1, plist2);
}
//4:若一個有環,一個無環,則不想交,返回NULL
else if ((enter1 == NULL) && (enter2 != NULL) || (enter1 != NULL) && (enter2 == NULL))
{
return NULL;
}
//3: 若入口點相同都在尾巴,去掉環,轉化成無環相交問題
else if (enter1 == enter2)
{
enter1->next = NULL;
enter2->next = NULL;
return IsListIntersect(plist1, plist2);
}
//6 :同環,兩個入口點 一個入口點開始遍歷一圈,看環上是否有另一個入口點
// 找到則返回plist1的入口點
else
{
ListNode* tmp = enter1->next;
while (tmp != enter1)
{
if (tmp == enter2)
{
return enter1;
}
tmp = tmp->next;
}
return NULL;
}
}
4.複雜鏈表的複製。一個鏈表的每個節點,有一個指向next指針指向下一個節點,還有一個random指針指向這個鏈表中的一個隨機節點或者NULL,現在要求實現複製這個鏈表,返回複製後的新鏈表。
ComplexNode* CopyList(ComplexNode* plist)
{
if (plist == NULL)
{
return NULL;
}
ComplexNode* newnode = NULL;
ComplexNode* tmp = plist;
//1.1 插入節點
while (tmp != NULL)
{
newnode = (ComplexNode*)malloc(sizeof(ComplexNode));
newnode->_data = tmp->_data;
newnode->_next = tmp->_next;
newnode->_random = NULL;
tmp->_next = newnode;
tmp = tmp->_next->_next;
}
//1.2開始連接random
tmp = plist;
newnode = plist->_next;
while (tmp != NULL)
{
if (tmp->_random != NULL)
{
newnode->_random = tmp->_random->_next;
}
tmp = tmp->_next->_next;
if (tmp)
{
newnode = tmp->_next;
}
}
//2.分離兩個鏈表
ComplexNode* res = plist->_next;
tmp = plist;
tmp->_next = tmp->_next->_next;
tmp = tmp->_next;
newnode = plist->_next;
while ((tmp->_next != NULL)&&(tmp != NULL))
{
newnode->_next = newnode->_next->_next;
tmp->_next = tmp->_next->_next;
tmp = tmp->_next;
newnode = newnode->_next;
}
return res;
}