您的位置:首页 > Web前端

剑指offer-15:单链表有趣问题-有环-环长度-环入口等(续)

2017-08-15 15:40 246 查看
第15题要求找到倒数第k个结点。采用快慢出发不同的指针,卡出k-1的距离,当快指针到尾结点时,慢指针刚好在倒数第k个位置上。

还有一些相关题目比较有趣,类似的思路。

(1)求链表的中间结点

答:设置两个指针,移动快慢不同。快指针每次移动2步,慢指针每次移动1步。两者同时从头结点开始出发。当快指针到达尾结点时,走的路程是n,由于慢指针速度是其一半,则相同时间走的路程就是n/2,恰好位于链表的中间。

如果链表中的结点为奇数,则返回中间结点;如果链表中的结点为偶数,则返回中间两个结点的任意一个(前一个)。

// fast每次走2步,终点时:偶数时自身会为null,奇数时next会为null
while( fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
}


(2)判断单向链表是否有环

答:若单链表有环,则可定义两个快慢指针。和操场跑圈类似,若有环,则快指针势必会追上慢指针,此时就是有环。若没有环,快指针会走到尾结点也不会和慢指针相遇,此时无环。

代码:

bool isLoop(pNode *pHead)
{
pNode *fast = pHead;
pNode *slow = pHead;
//如果无环,则fast先走到终点
//当链表长度为奇数时,fast->Next为空
//当链表长度为偶数时,fast为空
while( fast != NULL && fast->next != NULL)
{

fast = fast->next->next;
slow = slow->next;
// 若有环则会从此处跳出while
if(fast == slow)
{
break;
}
}
// 判断出while循环是相遇而跳,还是快指针到尾结点了退出?
if(fast == NULL || fast->next == NULL  )
return false;
else
return true;
}


(3)若单链表有环,环的长度?

答:第一次相遇点开始,两指针同时跑,开始计数。到第二次相遇时,慢指针跑了一圈,快指针跑了2圈,停止计数。计数值即为一圈长度。

int loopLength(pNode *pHead)
{
// 判断是否有环
if(isLoop(*pHead) == false)
return 0;

pNode *fast = pHead;
pNode *slow = pHead;
int length = 0;
bool begin = false;
bool agian = false;
while( fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
//第2次相遇,停止计数,出循环
if(fast == slow && agian == true)
break;
//第一次相遇,开始计数
if(fast == slow && agian == false)
{
begin = true;
agian = true;
}
//计数
if(begin == true)
++length;
}

return length;
}


(4)如何找到环的入口点?

答:由归纳推理可得,从第一次的相遇点处,到环入口的距离,等于头结点到环入口的距离。



假设头结点到入口处为L1,相遇点顺时针入口点为L3,入口点到相遇点为L2。则当两指针相遇时,慢指针走了(L1+L2),快指针速度是2倍,应该走的是2(L1+L2)。再根据图上关系,快指针走的还可以表示为(L1+L2+L3+L2),则

2(l1+l2)=l1+l2+l3+l2则l1=l3

所以当第一次相遇时,从相遇点和头结点分别设置两个移动步长均为1的指针,当相遇时,相遇点即为入口点。

Node* findLoopEntrance(pNode *pHead)
{
pNode *fast = pHead;
pNode *slow = pHead;
while( fast != NULL && fast->next != NULL)
{

fast = fast->next->next;
slow = slow->next;
//如果有环,则fast会超过slow一圈
if(fast == slow)
{
break;
}
}
if(fast == NULL || fast->next == NULL)
return NULL;
slow = pHead;
while(slow != fast)
{
slow = slow->next;
fast = fast->next;
}

return slow;
}


(5)如何判断两个链表(不带环)是否相交?

答:可将其中一个链表的尾指针指向头结点。从另一个链表查找是否有环。如果有环说明相交;没有环说明不相交。

参考资料

【1】http://blog.csdn.net/thefutureisour/article/details/8174313
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: