美文网首页
链表中环的检测

链表中环的检测

作者: 云飞扬1 | 来源:发表于2020-02-21 14:17 被阅读0次

1. 怎么检测一个单向链表中是否有环

同样借助于快慢指针,思路如下:

  1. 定义 fast、slow 两个指针同时指向链表头部;
  2. 开始遍历链表,slow 每次移动步数为 1 ,fast 每次移动步数为 2 ;
  3. 如果链表中没有环,则 fast 指针必然会移动到链表尾部,最后会指向 null;
  4. 如果链表中有环,则在移动的过程中,fast 与 slow 两个指针必然会在某个节点相遇;

想象成环形运动场跑步,跑得慢的人与跑得快的人同时出发,跑得快的人必然会超过跑得慢的人,并且会再次追上。

代码如下(kotlin编写):

/**
 * 链表数据结构
 */
class Node constructor(val data: Char) {
    var next: Node? = null

    override fun toString(): String {
        val sb = StringBuilder()
        sb.append(data)
        var tmp: Node? = next
        while (tmp != null) {
            sb.append(tmp.data)
            tmp = tmp.next
        }
        return sb.toString()
    }
}

/**
 * 检测是否有环
 */
fun detectCircle(head: Node?): Boolean {
    head ?: return false
    head?.next ?: return false

    var fast = head
    var slow = head
    while (fast?.next != null) {
        slow = slow?.next
        fast = fast?.next?.next
        if (fast == slow) {
            return true
        }
    }
    return false
}

//测试代码
fun main() {
    var node1 = Node('1')
    var node2 = Node('2')
    var node3 = Node('3')
    var node4 = Node('4')
    var node5 = Node('5')
    var node6 = Node('6')
    node1.next = node2
    node2.next = node3
    node3.next = node4
    node4.next = node5
    node5.next = node6
    node6.next = node3

    println(detectCircle(node1))
}

2. 找到链表环的入口节点

image.png

图中入口节点为 3 ,由于 x 与 z 相等,所以我们用 2 个指针,一个从链表头部 1,一个从相遇点 6, 同时开始同速度移动,最后它俩的相遇点就是环的入口节点。

这个图比较简单,只是方便理解。实际上,x 可能会很大,而链表内的环长度比较小,并不能照图中来推论,下面是具体推论:

首先根据图中所示,需要求解 x 的长度?
环长:L = y + z
slow指针移动长度:S = x + y
fast指针移动长度:2S = x + nL + y(fast 是 slow 的 2 倍速度,n 目前未知)
所以: 2(x + y) = x + nL + y
求得:x = nL - y = nL - y - z + z = nL - (y + z) + z = (n - 1)L + z
最终:x = (n - 1)L + z,这里 n >= 1

假设一个指针从链表头部,一个指针从环里的相遇点开始移动,当前者移动到环入口节点时:
当 n = 1 ,从相遇点到环入口节点只需移动 z 次;
当 n = 2 ,从相遇点到环入口节点,需要绕着环走一圈后,再移动 z 次;
以此类推,不管怎么样,这2个指针最终都会在入口处相遇。

代码如下:

fun findCircleEntryNode(head: Node?): Node? {
    head ?: return null
    head?.next ?: return null

    var fast = head
    var slow = head
    while (fast?.next != null) {
        slow = slow?.next
        fast = fast?.next?.next
        if (fast == slow) {
            break
        }
    }
    //如果有环
    if (fast == slow) {
        if (fast == head)
            return head
        var tmp = head
        while (tmp?.next != null) {
            tmp = tmp?.next
            fast = fast?.next
            if (tmp == fast) {
                return tmp
            }
        }
    }
    return null
}

时间复杂度:O(n)
空间复杂度:O(1)

相关文章

  • 关于链表经典算法题都在这里了

    1.单链表反转(LeetCode 206) 2.链表中环的检测 (LeetCode 141) 3.求链表中环开始结...

  • 链表中环检测

  • 链表——链表中环的检测

  • 链表--链表中环的检测

    给定一个链表,判断链表中是否有环。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索...

  • 链表中环的检测

    1. 怎么检测一个单向链表中是否有环 同样借助于快慢指针,思路如下: 定义 fast、slow 两个指针同时指向链...

  • 链表中环的检测

  • 链表中环的检测

    思路一:哈希表 我们遍历链表中的每个节点,并将它记录下来;一旦遇到了此前遍历过的节点,就可以判定链表中存在环。借助...

  • 常见算法总结

    链表 单链表反转链表中环的检测两个有序的链表合并删除链表倒数第 n 个结点求链表中间第n个节点

  • 链表

    链表 单链表反转链表中环的检测两个有序链表合并删除链表倒数第n个节点求链表的元素总个数 一.单向链表 链表共有特征...

  • Java实现链表中环的检测

    链表中环的检测,就是判断链表中是否存在环形结构。带有环形结构的链表如下图所示: image.png 这里提供两种解...

网友评论

      本文标题:链表中环的检测

      本文链接:https://www.haomeiwen.com/subject/wfwfqhtx.html