【剑指offer】链表中环的入口结点(链表)

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

链接

https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=13&tqId=11208&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

思路

第一种解法:
用一个set集合保存访问到的每一个指针,然后对整个链表依次进行访问,如果访问到NULL都没有遇到相同的指针,则该链表无环。如果某个时刻访问到的指针曾经出现过,则该指针就是环的入口。

第二种解法:
1、用1快1慢的两个指针对链表进行访问,慢的指针每次前进1个,快的指针每次前进2个。如果快的指针某个时刻指向NULL,则证明无环,如果某个时刻快的指针追上慢的指针,则证明有环。且相遇时的指针一定位于环中。
2、在有环的情况下,从相遇的指针处开始遍历访问,并计数,当指针再次为相遇时的指针时,计数的值便是环的大小。
3、得到了环的大小num,就可以让一前一后两个指针相隔num,然后两个指针同步向前,某个时刻两个指针必将指向相同的节点,即为入口点。

代码

/*
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;
    	} 
		set<ListNode*> ss;
		while(pHead){
			if(ss.find(pHead) == ss.end()){
				ss.insert(pHead);
			}
			else{
				return pHead;
			}
			pHead = pHead->next;
		}
		return NULL;
    }
};
// 第二种解法
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
    	ListNode* meetingNode = MeetingNode(pHead);
    	if(meetingNode == NULL){
    		return NULL;
    	}
    	// 获取环中的节点数
		int num = 1;
		ListNode* temp = meetingNode->next;
		while(temp != meetingNode){
			num++;
			temp = temp->next;
		}
		// 让两个指针相差num去寻找入口
		ListNode* pNode1 = pHead;
		ListNode* pNode2 = pHead;
		while(num--){
			pNode1 = pNode1->next;
		} 
		while(pNode1 != pNode2){
			pNode1 = pNode1->next;
			pNode2 = pNode2->next;
		}
		return pNode1;
    }
    ListNode* MeetingNode(ListNode* pHead)
    {
    	if(pHead == NULL){
    		return NULL;
    	}
    	ListNode* first = pHead->next;
    	if(first == NULL){
    		return NULL;
    	}
    	ListNode* second = first->next;
    	while(second != NULL && first != NULL){
    		if(first == second){
    			return first;
    		}
    		first = first->next;
    		second = second->next;
    		if(second != NULL){
    			second = second->next;
    		}
    	}
    	return NULL;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值