剑指offer-15:单链表有趣问题-有环-环长度-环入口等(续)
2017-08-15 15:40
316 查看
第15题要求找到倒数第k个结点。采用快慢出发不同的指针,卡出k-1的距离,当快指针到尾结点时,慢指针刚好在倒数第k个位置上。
还有一些相关题目比较有趣,类似的思路。
(1)求链表的中间结点
答:设置两个指针,移动快慢不同。快指针每次移动2步,慢指针每次移动1步。两者同时从头结点开始出发。当快指针到达尾结点时,走的路程是n,由于慢指针速度是其一半,则相同时间走的路程就是n/2,恰好位于链表的中间。
如果链表中的结点为奇数,则返回中间结点;如果链表中的结点为偶数,则返回中间两个结点的任意一个(前一个)。
(2)判断单向链表是否有环
答:若单链表有环,则可定义两个快慢指针。和操场跑圈类似,若有环,则快指针势必会追上慢指针,此时就是有环。若没有环,快指针会走到尾结点也不会和慢指针相遇,此时无环。
代码:
(3)若单链表有环,环的长度?
答:第一次相遇点开始,两指针同时跑,开始计数。到第二次相遇时,慢指针跑了一圈,快指针跑了2圈,停止计数。计数值即为一圈长度。
(4)如何找到环的入口点?
答:由归纳推理可得,从第一次的相遇点处,到环入口的距离,等于头结点到环入口的距离。
假设头结点到入口处为L1,相遇点顺时针入口点为L3,入口点到相遇点为L2。则当两指针相遇时,慢指针走了(L1+L2),快指针速度是2倍,应该走的是2(L1+L2)。再根据图上关系,快指针走的还可以表示为(L1+L2+L3+L2),则
2(l1+l2)=l1+l2+l3+l2则l1=l3
所以当第一次相遇时,从相遇点和头结点分别设置两个移动步长均为1的指针,当相遇时,相遇点即为入口点。
(5)如何判断两个链表(不带环)是否相交?
答:可将其中一个链表的尾指针指向头结点。从另一个链表查找是否有环。如果有环说明相交;没有环说明不相交。
参考资料
【1】http://blog.csdn.net/thefutureisour/article/details/8174313
还有一些相关题目比较有趣,类似的思路。
(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
相关文章推荐
- 单链表中的常见算法问题(剑指offer5/13/15/16/17)
- 剑指offer--判断链表是否带环?若带环求环的长度?若带环求环的入口点?
- 剑指offer面试题-判断链表是否带环并求环的入口点和环的长度
- 剑指offer_面试题15_链表中倒数第k个节点(考虑问题要全面)
- 剑指offer----链表中环的入口节点----java实现
- 剑指offer-15:单链表中倒数第k个结点
- 剑指offer-题15:链表中倒数第k个节点
- 剑指offer | 训练题54:链表中环的入口结点
- 剑指Offer--15.反转链表
- 判断链表是否带环?若带环求环的长度?若带环求环的入口点?并计算以上每个问题的时间复杂度?
- 剑指offer--面试题15:链表中倒数第k个结点
- 剑指offer代码解析——面试题15求链表中倒数第K个结点
- 剑指Offer15 合并两个已排序链表
- 剑指Offer 15 输入一个链表,输出该链表中倒数第k个结点
- 剑指offer-面试题15-链表中倒数第k个结点
- 【剑指offer】15反转链表
- 剑指 offer 56:求链表中环的入口节点
- 剑指offer-面试题56:链表中环的入口结点
- 【剑指offer-解题系列(56)】链表中环的入口
- 剑指Offer面试题:15.反转链表