结构体定义如下:
typedef struct ListNode
{
DataType data;
struct ListNode* next;
}ListNode;
1.判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复杂度&空间复杂度。
ListNode* IsOrNotRing(ListNode* pHead)
{
ListNode* slow = pHead;
ListNode* fast = pHead;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(fast == slow)
{
printf("have ring\n");
return fast;
}
}
printf("have not ring\n");
return NULL;
}
size_t LengthOfRing(ListNode* pHead)
{
ListNode* slow = pHead;
ListNode* fast = pHead;
size_t count = 0;
ListNode* tmp = NULL;
while(fast && fast->next)
{
if(fast == slow)
{
tmp = slow;
break;
}
slow = slow->next;
fast = fast->next->next;
}
slow = slow->next;
while(tmp != slow)
{
count++;
slow = slow->next;
}
count++;
return count;
}
求环的入口点:
这个问题需要一定的数学推理,结论列出来:
交点node到入口点的距离=头指针到连接点的距离,因此,分别从交点,头指针开始走,相遇的那个点就是连接假设链表总长为L,头节点到入口点的距离为A,入口点到快慢指针交点距离为X,环的长度为R,现在假设慢指针走了S步与快指针相遇,S = A + X;那么快指针走了2S步,2S = A + NR + X; 可得:A + X = NR; A = NR - X;可以看出来头节点到入口点的距离等于,交点到入口点的距离,那么我们让两个指针,一个从交点走,一个从头节点走,最后一定在入口点相遇。
ListNode* EnterPointOfRing(ListNode* pHead)
{
ListNode* slow = pHead;
ListNode* fast = pHead;
ListNode* meetNode = NULL;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next
if(fast == slow)
{
meetNode = slow;
break;
}
}
while(pHead != meetNode)
{
pHead = pHead->next;
meetNode = meetNode->next;
}
return pHead;
}
2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
思路:将两个链表遍历到最后一个节点,若相同,则相交;若不相同,则不相交。
ListNode* GetCrossNode(ListNode* list1, ListNode* list2)
{
int len1 = 0, len2 = 0;
ListNode* cur1= list1, *cur2 = list2;
ListNode* shortList, *longList;
int gap;
while (cur1)
{
len1++;
cur1 = cur1->next;
}
while (cur2)
{
len2++;
cur2 = cur2->next;
}
shortList = list1;
longList = list2;
if (len2 < len1)
{
shortList = list2;
longList = list1;
}
gap = abs(len1-len2);
while (gap--)
longList = longList->next;
while (shortList != longList)
{
shortList = shortList->next;
longList = longList->next;
}
return shortList;
}
3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
这个问题分为三个大的情况:
(1)如果两个链表都不带环,就和例2一样;
(2)如果一个链表带环,一个不带环,则一定不相交;
(3)如果两个链表都带环,有可能相交,有可能不相交。
当两个链表有环时,相交判断:
<1>首先找出两个链表入环的第一个节点,记为p1,p2;
<2>如果p1 == p2,说明两个链表在入环之前或入环的第一个加点相交,此时将p1,p2当做两个链表的最后一个节点,将问题又转化为两个链表不带环的问题进行处理。
<3>如果p1 != p2,此时两个链表可能完全不相交,也有可能两个链表完全共用同一个环。
ListNode* GetMeetNodeInCycle(ListNode* pHead)
{
assert(pHead);
ListNode* slow = pHead;
ListNode* fast = pHead;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(fast == slow)
{
return fast;
}
}
return NULL;
}
int* IsOrNotIntersectHaveRing(ListNode* List1, ListNode* List2)
{
ListNode* meet1 = GetMeetNodeInCycle(List1);
ListNode* meet2 = GetMeetNodeInCycle(List2);
if (meet1 != NULL && meet2 != NULL)
{
Node* cur = meet1;
while (meet1 != cur->_next)
{
if (meet2 == cur)
{
return 1;
}
cur = cur->next;
}
}
return 0;
}
//判断两个链表是否相交(链表可能带环)
ListNode* IsOrNotIntersectMaybeHaveRing(ListNode* List1, ListNode* List2)
{
int m, n;
int k
ListNode* p1 = EnterPointOfRing(List1); //首先找出两个链表入环的第一个节点,记为p1,p2;
ListNode* p2 = EnterPointOfRing(List2);
ListNode* tail1 = NULL;
ListNode* tail2 = NULL;
m = IsOrNotRing(List1);
n = IsOrNotRing(List2);
if(m = n = 0) //两个链表都不带环
{
return IsOrNotIntersect(List1, List2);
}
if(m = n = 1) //两个链表都带环
{
//如果p1 == p2,说明两个链表在入环之前或入环的第一个加点相交,
//此时将p1,p2当做两个链表的最后一个节点,将问题又转化为两个链
//表不带环的问题进行处理
if(p1 == p2)
{
int len1 = 0, len2 = 0;
ListNode* cur1= list1, *cur2 = list2;
ListNode* shortList, *longList;
int gap;
while (cur1)
{
len1++;
cur1 = cur1->next;
}
while (cur2)
{
len2++;
cur2 = cur2->next;
}
shortList = list1;
longList = list2;
if (len2 < len1)
{
shortList = list2;
longList = list1;
}
gap = abs(len1-len2);
while (gap--)
{
longList = longList->next;
}
while (shortList != longList)
{
shortList = shortList->next;
longList = longList->next;
}
return shortList;
}
//如果p1 != p2,此时两个链表可能完全不相交,也有可能两个链表完全共用同一个环
if(p1 != p2)
{
k = IsOrNotIntersectHaveRing(List1,List2);
if(k == 0)
{
return NULL;
}
if(k == 1)
{
tail1 = p1;
tail2 = p2;
while(p1 != tail1->next)
{
tail1 = tail->next;
}
while(p2 != tail2->next)
{
tail2 = tai2->next;
}
while(p1 != tail1)
{
while(p2 != tail2)
{
if(p1 == p2)
{
return p1;
}
p2 = p2->next;
}
p1 = p1->next;
}
}
}
}
else //一个链表带环,一个不带环,肯定不相交
{
return NULL;
}
}
4.复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。
http://mp.blog.csdn.net/postedit/79149550