C语言单链表面试题(进阶)

结构体定义如下:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值