[LintCode] Linked List Cycle(带环链表)

描述

给定一个链表,判断它是否有环。

样例

给出 -21->10->4->5, tail connects to node index 1,返回 true。

这里解释下,题目的意思,在英文原题中,tail connects to node index 1 表示的是节点 5 还要链接回索引号 为 1 的节点。

一个典型的带环链表如下:

挑战

不要使用额外的空间

代码

GitHub 的源代码,请访问下面的链接:

https://github.com/cwiki-us/java-tutorial/blob/master/src/test/java/com/ossez/lang/tutorial/tests/lintcode/LintCode0102HasCycleTest.java

package com.ossez.lang.tutorial.tests.lintcode;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ossez.lang.tutorial.models.ListNode;

/**
 * <p>
 * 102
 * <ul>
 * <li>@see <a href=
 * "https://www.cwiki.us/display/ITCLASSIFICATION/Linked+List+Cycle">https://www.cwiki.us/display/ITCLASSIFICATION/Linked+List+Cycle</a>
 * <li>@see<a href= "https://www.lintcode.com/problem/linked-list-cycle/">https://www.lintcode.com/problem/linked-list-cycle/</a>
 * </ul>
 * </p>
 *
 * @author YuCheng
 *
 */
public class LintCode0102HasCycleTest {

  private final static Logger logger = LoggerFactory.getLogger(LintCode0102HasCycleTest.class);

  /**
   *
   */
  @Test
  public void testMain() {
    logger.debug("BEGIN");
    // INIT LINKED LIST
    ListNode head = new ListNode(1);
    head.next = new ListNode(2);
    head.next.next = new ListNode(3);
    head.next.next.next = new ListNode(4);

    // CREATE A LOOP
    head.next.next.next.next = head.next.next.next;

    boolean retResult = false;

    // LIKED LIST MAY NULL:
    if (!(head == null || head.next == null)) {
      ListNode s = head;
      ListNode f = head.next;

      while (f.next != null && f.next.next != null) {

        s = s.next;
        f = f.next.next;

        if (f == s) {
          retResult = true;
          break;
        }
      }
    }

    System.out.println(retResult);

  }
}

点评

链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。

使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

在计算机科学中,链表作为一种基础的数据结构可以用来生成其它类型的数据结构。链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个/或下一个节点的位置的链接(”links”)。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的访问往往要在不同的排列顺序中转换。而链表是一种自我指示数据类型,因为它包含指向另一个相同类型的数据的指针(链接)。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。

要判断一个链表中是否有循环,可以借助额外的存储空间,将链表插入到 HashSet 中。创建一个以节点ID为键的HashSet集合,用来存储曾经遍历过的节点。然后同样是从头节点开始,依次遍历单链表的每一个节点。每遍历到一个新节点,就用新节点和HashSet集合当中存储的节点作比较,如果发现HashSet当中存在相同节点ID,则说明链表有环,如果HashSet当中不存在相同的节点ID,就把这个新节点ID存入HashSet,之后进入下一节点,继续重复刚才的操作。

这个方法在流程上和方法一类似,本质的区别是使用了HashSet作为额外的缓存。

假设从链表头节点到入环点的距离是D,链表的环长是S。而每一次HashSet查找元素的时间复杂度是O(1), 所以总体的时间复杂度是1*(D+S)=D+S,可以简单理解为O(N)。而算法的空间复杂度还是D+S-1,可以简单地理解成O(N)。

也可以采用指针的方式。

首先创建两个指针1和2(在java里就是两个对象引用),同时指向这个链表的头节点。然后开始一个大循环,在循环体中,让指针1每次向下移动一个节点,让指针2每次向下移动两个节点,然后比较两个指针指向的节点是否相同。如果相同,则判断出链表有环,如果不同,则继续下一次循环。

例如链表A->B->C->D->B->C->D,两个指针最初都指向节点A,进入第一轮循环,指针1移动到了节点B,指针2移动到了C。第二轮循环,指针1移动到了节点C,指针2移动到了节点B。第三轮循环,指针1移动到了节点D,指针2移动到了节点D,此时两指针指向同一节点,判断出链表有环。

此方法也可以用一个更生动的例子来形容:在一个环形跑道上,两个运动员在同一地点起跑,一个运动员速度快,一个运动员速度慢。当两人跑了一段时间,速度快的运动员必然会从速度慢的运动员身后再次追上并超过,原因很简单,因为跑道是环形的。

https://www.cwiki.us/display/ITCLASSIFICATION/Linked+List+Cycle

原文地址:https://www.cnblogs.com/huyuchengus/p/10126327.html

时间: 2024-11-05 22:48:36

[LintCode] Linked List Cycle(带环链表)的相关文章

[Leetcode] Linked list cycle ii 判断链表是否有环

Given a linked list, return the node where the cycle begins. If there is no cycle, returnnull. Follow up:Can you solve it without using extra space? 题意:给定链表,若是有环,则返回环开始的节点,没有则返回NULL 思路:题目分两步走,第一.判断是否有环,第二若是有,找到环的起始点.关于第一点,可以参考之前的博客 Linked list cycle.

[LeetCode]93. Linked List Cycle II查找链表中环的起始节点

Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Note: Do not modify the linked list. Follow up:Can you solve it without using extra space? Subscribe to see which companies asked this question 解法:这道题是题目L

带环链表的入口

带环的单链表: 如上图,List 为一个带有环的单链表,环的大小为5: 证明: S 为 slow 指针相遇前走的距离,2S 为 fast 指针相遇前走过的距离: ∵ 2S = S + n*R;        //n slow,fast指针相遇前 fast 多经历的圈数  S = H_I + R1: ∴S = n*R; ∴n*R = H_I  + R1; ∵ R1 + R2 = R; ∴(n-1)*R = H_I - R2; ∴(n-1)*R + R2 = H_I;       //结论:(交点到

[PHP] 算法-请找出带环链表的环的入口结点的PHP实现

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null 1.找链表倒数第k个结点,输入一个链表,输出该链表中倒数第k个结点.第一个指针走(k-1)步,到达第k个节点,两个指针同时往后移动,当第一个结点到达末尾的时候,第二个结点所在位置就是倒数第k个节点了 2.原理有点像上面的,定义两个指针,一个是快指针每次走两步,一个是慢指针每次走一步,当两个相遇的时候,假设环的长度为n个结点,慢指针走x步,快指针走2x步,2x=x+kn ;x=kn; k暂时假定为1圈 ,也就是慢指针slow

关于相交链表、带环链表、链表深拷贝的思路整理

返回相交链表的交点:1.先求出两个链表的各自长度2.让长的先走他们的(长度差)步3.然后两者同时走,第一次相遇就是交点(返回该结点) 判断链表是否带环:1.快慢指针(快的走两步,慢的走一步,不能一个一步,一个n步(N>2),可能会错过)2.如果两个指针相遇,则链表带环:如果快的遇到null,则不带环(直线形) 求入环点:1).转化为相交问题(求取相遇结点)2).一个从起点,一个从交点,都每次走一步,第一次相遇点为入环点 相交+带环(六种情况) 复杂链表的复制1)简单复制无法解决(因为是浅拷贝)2

[LintCode] Linked List Cycle 单链表中的环

Given a linked list, determine if it has a cycle in it. ExampleGiven -21->10->4->5, tail connects to node index 1, return true Challenge Follow up:Can you solve it without using extra space? s

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

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? 这个求单链表中的环的起始点是之前那个判断单链表中是否有环的延伸,可参见我之前的一篇文章 (http://www.cnblogs.com/grandyang/p/4137187.html). 还是要设

LeetCode Linked List Cycle II 单链表环2 (找循环起点)

题意:给一个单链表,若其有环,返回环的开始处指针,若无环返回NULL. 思路: (1)依然用两个指针的追赶来判断是否有环.在确定有环了之后,指针1跑的路程是指针2的一半,而且他们曾经跑过一段重叠的路(即1跑过,2也跑过),就是那段(环开始处,相遇处),那么指针2开始到环开始处的距离与head到指针相遇处是等长的喔~,那么再跑一次每次一步的就必定会相遇啦.画个图图好方便看~ (2)其实还有另一个直观的思路,就是指针1和2相遇后,p指向他们的next,在他们相遇处的next给置空,再跑一遍那个“找两

142 Linked List Cycle II(如果链表有环,找到入口结点)

题目意思:如果有环,返回入口结点 思路:先判断有没环,再计算环的结点数,然后p1指向头,p2往后移结点次数,p1.p2相遇为入口结点 ps:还是利用指针间距这个思路 1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */ 9 class Sol