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;
}