程序员编程艺术--->6、关于链表的追赶问题

本章主要涉及链表的相关检测问题,诸如:

  1. 链表的倒数第k个结点
  2. 检测链表是否带环
  3. 两链表是否相交

而此类问题,如果用直观的想法去做的话,无疑时间复杂度不太可观,因此可以继续寻求更加的解决方案。下面就这些问题展开来谈。

1、求链表的倒数第k个结点

 解析:(1)两次遍历链表,第一次求出链表的长度,第二次找出n-k个结点,便是倒数第k个结点。

           (2)既然要尔链表的倒数第k 个结点,那么是不是可以用两个指向该链表的指针,让它们保持k的距离遍历链表呢?当然可以,那么在前的指针到达末尾的时候,后面的指针便是指向倒数第k个结点。这样的话,只需要遍历一次链表

            追赶之一。

代码如下:

Node * GetKNode(int k)
{
	Node *first = NULL, *second = NULL;
	first = second = head;
	int count = 0;
	while(count<k-1)
	{
		first = first->next;
		count++;
	}
	while(first->next!=NULL)
	{
		first = first->next;
		second = second->next;
	}
	return second;

}


2、检测单链表是否带环

解析:其实这个问题也是一个两指针遍历链表时的追赶问题。p1,p2同时遍历链表,并且p2的速度是p1的两倍,如果链表不带环的话,p1肯定是追赶不上p2的,那如果二者能相遇,则必须存在环呀。

Node *IsCircled(Node *head)
{
	Node *fast = head, *slow = head;
	while(fast!=NULL && slow!= NULL)
	{
		if(fast == slow)
			return fast;
		fast = fast->next->next;
		slow = slow->next;
	}
	return NULL;
}


3、检测两单链表是否相交

解析:1,假设链表无环的情况,如何判断相交呢?

           (1)最直观的方法,分别遍历两链表上的结点,看其是否在另外一条链表中。那么最坏的情况下时间复杂度为O(length1 * length2).

            (2)将第二个链表接在第一个链表后面,如果得到的链表有环,则说明一定相交

           (3)如果两个链表相交,则在它们的第一个交点到尾节点都是公共的。那么只需要判断它们的最后一个结点是否相同就可以啦。这样时间复杂度降到了O(length1 + length2)。

         2、如果链表有环的情况

           (1)一条有环,一条无环,则不可能相交

          (2)两条都有环,则判断带环链表的连接点(即,上面提到的快慢两指针第一次相遇的那个结点)是否也在另外一条链表上。

因此,判断链表是否相交:

         判断链表是否带环,若都不带环,则判断它们的尾结点是否相同;若都带环,则判断其中一条带环链表的连接点是否也在另一条上。

Node *IsCircled(Node *head)
{
	Node *fast = head, *slow = head;
	while(fast!=NULL && slow!= NULL)
	{
		if(fast == slow)
			return fast;
		fast = fast->next->next;
		slow = slow->next;
	}
	return NULL;
}

bool CheckCrossing(Node *head1, Node *head2)
{
	Node *p1 = head1, *p2 = head2;
	Node *CrossingNode1 = IsCircled(head1);
	Node *CrossingNode2 = IsCircled(head2);
	if(!CrossingNode1 && !CrossingNode2)//无环
	{
		while(p1->next)
			p1 = p1->next;
		while(p2->next)
			p2 = p2->next;
		if(p1 == p2)
			return true;
		else 
			return false;
	}
	else if(CrossingNode2 && CrossingNode1)//都有环
	{
		while(head2)
		{
			if(CrossingNode1 == head2)
				return true;
			head2 = head2->next;
		}
	}
	else
		return false;
}

4、求两链表相交的第一个交点

解析:记录两个链表的长度length1 , length2, 会发现二者之差为m, 那么让指向长链表的指针先行m 步,然后指向短链表的指针再和它一起同时往前走,并进行比较,发现第一个相同的结点便是它们的交点。


思考题:

题目描述:
    在一条左右水平放置的直线轨道上任选两个点,放置两个机器人,请用如下指令系统为机器人设计控制程序,使这两个机器人能够在直线轨道上相遇。(注意两个机器人用你写的同一个程序来控制)
    指令系统:只包含4条指令,向左、向右、条件判定、无条件跳转。其中向左(右)指令每次能控制机器人向左(右)移动一步;条件判定指令能对机器人所在的位置进行条件测试,测试结果是如果对方机器人曾经到过这里就返回true,否则返回false;无条件跳转,类似汇编里面的跳转,可以跳转到任何地方。

解析:这也同样是链表的追赶问题。机器人A和B,B在A的前面,如果A和B一直保持相同的速度往前走,那么它们永远也不会相遇的。但是如果A一但到达B曾经走过的点,那么马上提速至原来的两倍,那么肯定可以在{AB}/move_right个单位内追上B.





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值