美文网首页
142. Linked List Cycle II(week4)

142. Linked List Cycle II(week4)

作者: piubiupiu | 来源:发表于2018-09-26 20:05 被阅读0次

    142. Linked List Cycle II

    题目描述

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

    <b>Note: Do not modify the linked list.</b>

    Follow up:

    Can you solve it without using extra space?

    解题思路

    无视Follow up中的内容的话,很容易就能想到,用一个长度为N的数组存已经经过的节点,然后每次访问下一个元素时,先在数组中查找是否访问过这个元素,若没有,放入数组,并继续访问下一个元素;若有,则返回这个元素。如果下一个元素为空,则返回空值。这样做我们不难发现,经过第k个元素时,需要查找k-1个元素,也就是说,时间复杂度是O(N^2)的规模,而且,数组开辟的额外空间是O(N)的规模。显然这不是一个好方法。

    那么我们要如何改善它呢?数组的查找显然是耗费时间非常多的,因此,如果我们把查找时间降低到O(1)的规模,那么,整个算法的复杂度规模就可以显著下降了。查找时间为O(1)的数据结构,我们马上就能想到哈希表也就是对应c++中的map类型。经过这一轮优化,我们不难发现,时间复杂度已经下降到了O(N)的规模。

    然而,题目要求的不可开辟O(N)复杂度的额外空间要怎么解决呢?要解决这个问题的核心在于,我们如何确定链表有环,即什么时候再次经过我们访问过的元素。如果单纯的用一个指针来遍历整个链表的话,我们是很难得知是否访问过这个元素的,要确定这个就必须要开辟空间存储访问过的元素。但这时,聪明的discussion中的老哥们想到,如果有两个不一样快的指针,同时在遍历这个链表,若它有环存在,快的指针就必定能在后面追上慢的指针;反之,则环不存在。

    既然确定环的问题解决了,我们又要如何确定环开始的节点呢?假设两个指针,快的指针在每次迭代中走两步,慢的指针在每次迭代中走一步。当快的指针追上慢的指针时,快的指针比慢的指针走的路程要多一倍。先证明:快的指针会在慢指针到达终点前与它相遇:

    k为环的长度,s为起点到循环开始的长度,慢指针走了t次后到达终点。
    慢指针走的路程 = s + k
    快指针走的路程 = 2(s + k) = s + k + k + s
    显然,快指针已经超过了慢指针。因此它们一定会在慢指针走到终点前相遇。并且快指针超过了慢指针s的长度。
    

    也就是说,当它们相遇时,快指针比慢指针多走了kr的长度,假如这时,快指针的速度变得跟慢指针一样,并且从链表头开始走会怎么样呢?

    由于速度相同,它们之间的路程差不会再拉开,一直维持在k
    r。这时候,让慢指针和速度跟它一致的快指针一起开始走,当慢指针走到终点并回到循环开始元素时,快指针由于刚好快它k倍数的长度,就会在循环开始元素二者相遇。这时候,我们把它们相遇的元素返回即可。

    时间复杂度分析

    慢指针刚好跑完整个链表,总时间复杂度为O(N)。

    空间复杂度分析

    两个指针复杂度O(1)

    源码

    class Solution {
    public:
      ListNode *detectCycle(ListNode *head) {
        if (head == NULL || head->next == NULL || head->next->next == NULL)
          return NULL;
        ListNode* p = head;
        ListNode* q = head;
        bool cycle = false;
        while (p != NULL && q != NULL) {
          p = p->next;
          if (q->next == NULL)
            return NULL;
          else {
            q = q->next->next;
          }
          if (p == q) {
            cycle = true;
            break;
          }
        }
        if (!cycle)
          return NULL;
        p = head;
        while (p != q) {
          p = p->next;
          q = q->next;
        }
        return p;
      }
    };
    

    相关文章

      网友评论

          本文标题:142. Linked List Cycle II(week4)

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