#数据结构与算法学习笔记#剑指Offer53:链表中环的入口结点(Java、C/C++)

版权声明:本文为博主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一秒钟。留个言点个赞呗,谢谢你#

猜你喜欢

转载自blog.csdn.net/qq_20304723/article/details/87876347