先说下看到问题后我的最初想法:
1、如何判断链表是否有环:有环也就是有重复的节点,那么我可以把已经遍历过的节点位置进行存储,然后每遍历到一个新的节点就去查找一下刚才存储的节点位置跟当前节点是否重合,如果重合就是有环
2、环的入口:重合的节点就是环的入口
3、换的长度:知道了入口,对这个节点做下标记,然后继续遍历,此次遍历的同时计数,再次遍历到这个节点的时候计数值就是环的长度。
这个方法容易想到,但是需要额外的存储空间,所以上网查优化。
1、如何判断链表是否有环
类比操场跑步,两个人速度不同,那么肯定会相遇。用在链表上,
设置两个指针fast和slow,然后开始遍历。初始的时候都指向链表头节点,fast指针每次向下移动两个节点,slow指针每次向下移动一个节点,判断两个指针是否相同。
如果无环链表,当fast遍历到null的时候,停止遍历,判断链表无环。
如果是有环链表,fast指针一定会与slow指针在环上相遇,所以如果fast==slow ,那么链表有环。
2、链表长度
方法一:(这是看别人博客的方法)
fast和slow相遇后,两个指针继续以刚才的速度遍历,同时计数,当下一次相遇的时候slow走的步数就是环的长度。
因为:第二次相遇的时候,就是fast把slow落了一圈,所以只需要记录这段过程里每次一步的slow指针走了多少步就是环的长度了。
方法二:是我想的太简单了?如有错误,欢迎提醒
fast和slow相遇后,fast不动了,然后slow指针继续遍历(就只需要slow自己遍历了,难道这样不是更省事吗,为什么要一起动?),同时计数,下次再相遇的时候计数值就是环长度。
3、环的入口
2中已经知道了环的长度length,求环入口的时候依然两个指针last 和 next,两个指针之间的距离为length,指针在向前移动的时候都是一次移动一步。当两个指针相遇的时候就是环的入口
因为:last比next快length步,当next到达环入口的时候,last正好把环走了一圈。