leetcode[141&142]:Linked List Cycle I & II

Linked List Cycle

Given a linked list, determine if it has a cycle in it.

Follow up:
Can you solve it without using extra space?

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode *fp, *sp;
    if( head == NULL || head->next == NULL ) return false;
    fp = head->next;
    sp = head;
    while( fp->next != NULL && fp->next->next != NULL)
    {
        if(fp == sp ) return true;
        fp = fp->next->next;
        sp = sp->next;
    }


    return false;
}

第一种方法,将所有的遍历过的节点用某个结构存储起来,然后每遍历一个节点,都在这个结构中查找是否遍历过,如果找到有重复,则说明该链表存在循环;如果直到遍历结束,则说明链表不存在循环。
这个结构我们可以使用hash来做,hash中存储的值为节点的内存地址,这样查找的操作所需时间为O(1),遍历操作需要O(n),hash表的存储空间需要额外的O(n)。所以整个算法的时间复杂度为O(n),空间复杂度为O(n)。
第二种方法,比较的特别,是使用反转指针的方法,每过一个节点就把该节点的指针反向。
当有环的时候,最后指针会定位到链表的头部,如果到最后,都没有再到头部,那说明链表不存在循环。
这个方法会破坏掉链表,所以如果要求是不能破坏链表的话,我们最后就还需要反转一下,再将链表恢复。
这个方法使用的空间复杂度为O(1),其实是使用了3个指针,用于进行反转。同时,时间复杂度为O(n)。
第三种方法,可能大家已经知道了,同时也是面试官大多想要得到的答案,就是快慢指针。
快指针pf(f就是fast的缩写)每次移动2个节点,慢指针ps(s为slow的缩写)每次移动1个节点,如果快指针能够追上慢指针,那就说明其中有一个环,否则不存在环。
这个方法的时间复杂度为O(n),空间复杂度为O(1),实际使用两个指针。

参考:百度百科

Linked List Cycle II

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *fp, *sp;
    if( !head  || !head->next) return NULL;
    fp = head;
    sp = head;
    while(fp->next && fp->next->next)
    {
        fp = fp->next->next;
        sp = sp->next;
        if(fp == sp) 
        {
            sp=head;
            while(fp!=sp)
            {
                fp = fp->next;
                sp = sp->next;
            }
            return fp;
        }
    }
    return NULL;
}

不能像I那样是的fp和sp不在同一起点,不好找环起点,故I的算法也需要改进。
改后的I:

bool hasCycle(struct ListNode *head) {
    struct ListNode *fp, *sp;
    if( head == NULL || head->next == NULL ) return false;
    fp = head;
    sp = head;
    while( fp->next != NULL && fp->next->next != NULL)
    {
        fp = fp->next->next;
        sp = sp->next;
        if(fp == sp ) return true;
    } 
    return false;
}

参考:求有环单链表中的环长、环起点、链表长

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值