作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址:https://leetcode.com/problems/linked-list-cycle-ii/description/

题目描述

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

To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Note: Do not modify the linked list.

Example 1:

Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a cycle in the linked list, where tail connects to the second node.

Example 2:

Input: head = [1,2], pos = 0
Output: tail connects to node index 0
Explanation: There is a cycle in the linked list, where tail connects to the first node.

Example 3:

Input: head = [1], pos = -1
Output: no cycle
Explanation: There is no cycle in the linked list.

Follow up:

  • Can you solve it without using extra space?

题目大意

找出单链表是否有环,如果有环返回环的入口,否则返回None.

解题方法

双指针

做过之前判断一个单链表中是否有环的题,我们知道可以通过一个指针走两步,一个指针走一步的方式,看两者是否相遇即可。这个题是之前的拓展。

如图所示,两个指针同时从直线起点开始,这个圈是顺时针方向走的,即走的顺序是S-O-x-c-O-x。

感谢评论区指正,如果SO线段的长度a足够长,而圈很小的时候,当两者相遇时,快指针多走的可能不止一圈。下面要证明如果相遇之后,慢指针回到原点继续走再相遇的点在O点。

  1. 首先要证明的是,两指针相遇时,慢指针还没有走完整个链表。

    • 当慢指针没走完一圈时,显然成立
    • 假设慢指针走完了一圈之后相遇,可以假定快指针在O的前一个位置,慢指针走一圈回到了O点,此时快指针走了两圈又回到了O的前一个位置,所以在慢指针走玩一圈之前就已经相遇。
  2. 快慢指针在x处第一次汇合,xo之间距离为x,假如快指针走了n圈,快指针走过的路程为a+x+n*(c + x),慢指针走过的路程为a+x,所以a+x+n*(c + x) = 2(a+x),所以a + x = n*(c + x),也就是SOx之间的距离等于n圈的长度,所以令慢指针从起点开始一次一步,快指针从x开始顺时针方向转也一次一步,同时前进,则慢指针走a时,快指针走了n*(c+x) - x的长度,则必会在O处相遇!

同时注意题目中说了,有可能不存在环,所以要进行判断。

二刷的时候提交错误了几次,原因在于判断fast == slow的时候写错位置了。应该写在移动指针之后,而不是在while循环刚开始的时候就判断。因为刚开始就判断的话,那么底下移动之后,可能直接就退出while了,没有做是否相等的判断。

# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
slow, fast = head, head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
break
if not fast or not fast.next:
return None
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return fast

C++代码如下:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if (!head) return nullptr;
ListNode* fast = head;
ListNode* slow = head;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
if (slow == fast)
break;
}
if (!fast || !fast->next || slow != fast) return nullptr;
slow = head;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return fast;
}
};

set

其实也可以简单一点,如果我们保存走过的每个位置不就好了吗?所以,对于Python来说,可以直接把对象放到set中去,这样,当我们再次遍历到已经访问过的节点时,说明有了环,直接返回该节点即可。

# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head: return None
visited = set()
while head:
if head in visited:
return head
visited.add(head)
head = head.next
return None

对于C++来说,有set和unordered_set两种集合,这里使用unordered_set,里面存放的内容是指向节点的指针,放指针一是可以成功存放,第二是如果已经遍历过了某个节点就相当于遍历过了这个指针。

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if (!head) return nullptr;
unordered_set<ListNode*> visited;
while (head) {
if (visited.count(head))
return head;
visited.insert(head);
head = head->next;
}
return nullptr;
}
};

参考资料:

http://blog.csdn.net/monkeyduck/article/details/50439840
https://blog.csdn.net/l294265421/article/details/50478818

日期

2018 年 3 月 12 日
2019 年 1 月 11 日 —— 小光棍节?

【LeetCode】142. Linked List Cycle II 解题报告(Python & C++)的更多相关文章

  1. 【算法分析】如何理解快慢指针?判断linked list中是否有环、找到环的起始节点位置。以Leetcode 141. Linked List Cycle, 142. Linked List Cycle II 为例Python实现

    引入 快慢指针经常用于链表(linked list)中环(Cycle)相关的问题.LeetCode中对应题目分别是: 141. Linked List Cycle 判断linked list中是否有环 ...

  2. LeetCode: Linked List Cycle II 解题报告

    Linked List Cycle II Given a linked list, return the node where the cycle begins. If there is no cyc ...

  3. Java for LeetCode 142 Linked List Cycle II

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

  4. [LeetCode] 142. Linked List Cycle II 链表中的环 II

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

  5. [LeetCode] 142. Linked List Cycle II 单链表中的环之二

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

  6. LeetCode 142. Linked List Cycle II 判断环入口的位置 C++/Java

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

  7. (链表 双指针) leetcode 142. Linked List Cycle II

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

  8. leetcode 142. Linked List Cycle II

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

  9. leetcode 142. Linked List Cycle II ----- java

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

随机推荐

  1. Python基础之流程控制if判断

    目录 1. 语法 1.1 if语句 1.2 if...else 1.3 if...elif...else 2. if的嵌套 3. if...else语句的练习 1. 语法 1.1 if语句 最简单的i ...

  2. Linux-centos7设置静态IP地址

    参考:https://blog.csdn.net/sjhuangx/article/details/79618865

  3. Identity Server 4 从入门到落地(七)—— 控制台客户端

    前面的部分: Identity Server 4 从入门到落地(一)-- 从IdentityServer4.Admin开始 Identity Server 4 从入门到落地(二)-- 理解授权码模式 ...

  4. adverb

    An adverb is a word or an expression that modifies a verb, adjective, another adverb, determiner [限定 ...

  5. 实时数仓(二):DWD层-数据处理

    目录 实时数仓(二):DWD层-数据处理 1.数据源 2.用户行为日志 2.1开发环境搭建 1)包结构 2)pom.xml 3)MykafkaUtil.java 4)log4j.properties ...

  6. Linux 设置时区

    一.查看和修改Linux的时区 1. 查看当前时区命令 : "date -R" 2. 修改设置Linux服务器时区方法 A命令 : "tzselect" 方法 ...

  7. Linux基础命令---mail邮件管理程序

    mail mail是一个邮件的管理程序,可以用来发送或者接收邮件. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.Fedora.   1.语法       mail  [选项] ...

  8. Siebel调用WebService

    Siebel可以调用外部系统的接口,通过WebService的接入方式实现,所在的项目都是通过ESB,其他系统的接口都要经过ESB,由ESB提供WSDL文档,通过Siebel调用. 一.修改Tools ...

  9. 数据库ER图基础概念

    ER图分为实体.属性.关系三个核心部分.实体是长方形体现,而属性则是椭圆形,关系为菱形. ER图的实体(entity)即数据模型中的数据对象,例如人.学生.音乐都可以作为一个数据对象,用长方体来表示, ...

  10. OpenStack之之一: 快速添加计算节点

    根据需求创建脚本,可以快速添加节点#:初始化node节点 [root@node2 ~]# systemctl disable NetworkManager [root@node2 ~]# vim /e ...