版权声明:本文为博主NJU_ChopinXBP原创文章,发表于CSDN,仅供交流学习使用,转载请私信或评论联系,未经博主允许不得转载。感谢您的评论与点赞。 https://blog.csdn.net/qq_20304723/article/details/87876347
2019.2.22 《剑指Offer》从零单刷个人笔记整理(66题全)目录传送门
重复问题考虑用哈希表,链表问题考虑用快慢指针。这正好是解这道题的两种思路。
哈希表法:没什么好说的,依次存储和验证,check到的第一个结点就是环的入口结点。
快慢指针法:
1.分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相遇点。当p1==p2时,p2所经过节点数为2x,p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈有2x=n+x; n=x;可以看出p1实际走了一个环的步数。
2.令起点到入口的距离为a,入口到相遇点距离为b,相遇点再到入口为c。已知a+b=x;b+c=x;因此a=c。也就是起点到入口距离=相遇点到入口距离。再让p2指向链表头部,p1位置不变,p1,p2每次走一步一共走a步直到p1==p2; 此时p1与p2指向环的入口。
题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
Java实现:
/**
*
* @author ChopinXBP
* 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
*
*/
import java.util.HashMap;
public class EntryNodeOfLoop_54 {
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public void main(String[] args) {
// TODO Auto-generated method stub
}
//哈希表法
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null) return null;
HashMap<ListNode, Boolean> map = new HashMap<>();
ListNode p = pHead;
while(p != null) {
if(map.containsKey(p))return p;
map.put(p, true);
p = p.next;
}
return p;
}
//快慢指针法
//1.分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相遇点。
//当p1==p2时,p2所经过节点数为2x,p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈有2x=n+x; n=x;可以看出p1实际走了一个环的步数。
//2.令起点到入口的距离为a,入口到相遇点距离为b,相遇点再到入口为c。已知a+b=x;b+c=x;因此a=c。也就是起点到入口距离=相遇点到入口距离。
//再让p2指向链表头部,p1位置不变,p1,p2每次走一步一共走a步直到p1==p2; 此时p1与p2指向环的入口。
ListNode EntryNodeOfLoop2(ListNode pHead) {
if (pHead == null || pHead.next == null)
return null;
ListNode p1 = pHead;
ListNode p2 = pHead;
while (p2 != null && p2.next != null) {
p1 = p1.next;
p2 = p2.next.next;
if (p1 == p2) {
p2 = pHead;
while (p1 != p2) {
p1 = p1.next;
p2 = p2.next;
}
if (p1 == p2)
return p1;
}
}
return null;
}
}
C++实现示例:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead==NULL)return NULL;
//先计算环中结点的个数
//快慢指针相遇结点一定在环中
ListNode *pFast=pHead,*pSlow=pHead->next;
while(pFast!=NULL&&pSlow!=NULL&&pFast!=pSlow){
pSlow=pSlow->next;
pFast=pFast->next;
if(pFast!=NULL)
pFast=pFast->next;
}
//开始统计环结点数
int countNum=1;
ListNode *pTempNode=pFast->next;
if(pFast==pSlow&&pFast!=NULL){
while(pTempNode!=pFast){
pTempNode=pTempNode->next;
++countNum;
}
}
else
return NULL;
//再设两指针,一先一后
ListNode *pNode1=pHead,*pNode2=pHead;
for(int i=0;i<countNum;i++){
pNode1=pNode1->next;
}
while(pNode1!=pNode2){
pNode1=pNode1->next;
pNode2=pNode2->next;
}
return pNode1;
}
};
#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#