LeetCode 解题报告 LinkedListCycleII

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Follow up:

Can you solve it without using extra space?

分析:

题目中要求求出一个循环链表的第一个循环结点,这个题目还要求不能外加空间。

其实这个题可以把他分成两步来做,一个是判断一个链表是不是有环,另一个是求两个链表的第一个交点

判断两个链表是不是有环的存在,就是两个指针,一个快,一个慢,如果两个指针能相遇,那就说明这个链表有环,否则没有环

求两个相交链表的第一个交点,可以分别遍历两个链表,求出其长度,然后让长链表先走对应的两个链表长度的差值步,然后两个链表同时走,

并判断俩结点是否相同,如果相同就返回这个结点

下面是上述思路的代码:

public class LinkedListCycleII {
	public ListNode detectCycle(ListNode head) {
		if(head == null)
			return null;
		//判断是否存在环
		ListNode node = head;
		ListNode fast = node,slow = node;
		while(fast.next != null && fast.next.next != null){
			fast = fast.next.next;
			slow = slow.next;
			if(fast == slow)
				break;
		}
		//无环
		if(fast.next == null || fast.next.next == null)
			return null;
		//有环,需要断开环
		fast = fast.next;
		slow.next = null;
		//现在有了两个链表,一个是head开头,一个是fast开头
		//找到两个链表的第一相交的结点
		//首先依次遍历两个链表,确定两个链表的长度,得到count = l1 - l2 的值,然后长链表先走
		//count步,之后两个同时走,并判断两个结点是否相同,如果相同就是第一个相交的结点
		return FindFirstNode(head,fast);
	}
	public ListNode FindFirstNode(ListNode l1,ListNode l2){
		//遍历两个链表,分别求长度
		int len1 = GetListLength(l1);
		int len2 = GetListLength(l2);
		int count = len1 - len2;
		if(count < 0){
			count = - count ;
			//令长链表先走,第一个变量放置长链表
			return FindNode(l2,l1,count);
		}
		else
			return FindNode(l1,l2,count);
	}
	public int GetListLength(ListNode head){
		int len = 0;
		ListNode node = head;
		while(node != null){
			len ++;
			node = node.next;
		}
		return len;
	}
	public ListNode FindNode(ListNode h1,ListNode h2,int count){
		ListNode l1 = h1,l2 = h2;
		while(count-- != 0){
			l1 = l1.next;
		}
		while(l1 != null && l2 != null && l1 != l2){
			l1 = l1.next;
			l2 = l2.next;
		}
		ListNode result = l1;
		return result;
	}	
}

思路2:

上述思路简单明了,就是实现起来代码比较繁琐,当时我在A这个题的过程中,会遇到很多意想不到的错误,

下面就给出网上的另一种思路,真的是分析透彻了之后再代码实现会让代码更美

思路是这样的

首先当一个快指针和一个满指针在环内循环的时候,在他俩相遇之前,慢指针是不会循环一圈的,假设slow指针走了s步,那么fast指针就走了2s步,当然这其中fast指针走了n圈,假设一圈有r步,外加S步,假设这个链表的圈内共有r步,那么2s = s + nr

可以得出s = nr,由此可以看出当这个链表就只是一个环的时候,快慢指针会在head出相遇,fast指针转两圈,slow指针刚好转一圈

同时,我们假设从环的入口点到相遇点共有a步,从起点到环的入口点为x,整个链表的长度为L,则慢指针走的s步就为x+a, 那么:x+a = nr

= (n-1)r+r = (n-1)r + (L-x)

所以x = (n-1)r + (L-x-a)

L-x-a正好是从相遇点到环的入口点的距离, 那么从链表的头结点到环的入口结点的距离就等于(n-1)圈环内距离加上从相遇点到环的入口距离,

那么可以再设置一个指针slow2从链表的头结点开始,slow和slow2指针同时走一步,知道两个指针相同,就是环的入口地址

下面是代码:

public ListNode detectCycle2(ListNode head){
		ListNode fast = head,slow = head;
		while(fast != null && fast.next != null){
			slow = slow.next;
			fast = fast.next.next;
			if(fast == slow){
				ListNode slow2 = head;
				while(slow != slow2){
					slow = slow.next;
					slow2 = slow2.next;
				}
				return slow;
			}
		}
		return null;
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值