leetcode#141环形链表

一.题目

1.1题目描述

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

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

进阶:

你能用 O(1)(即,常量)内存解决此问题吗?

1.2 示例

在这里插入图片描述
在这里插入图片描述

1.3题目提示

链表中节点的数目范围是 [0, 104]
-105 <= Node.val <= 105
pos 为 -1 或者链表中的一个 有效索引 。

二.题解

由于链表只能单向遍历,环形链表的结尾无法判断,造成了不小的难度。

2.1辅助指针数组

2.1.1思路

一个环形链表,长度为length,最后一个节点经length次迭代,会回到环形圈内,需要设计一个方法来比较已走过的节点和迭代测试走过的节点。
这里为了理清思路,假设圈子内有CircleLen个节点,已走过length个节点(包括将要判断的当前节点)

1
2
3
4
5
6
7

圈内节点经length步回到原位,那么只要length%CirclLen==0就能判断为环形。设0为当前指针的位置,我们要判断它是否迭代进环中。

O
O
O
O
0
1
2
O
O
O
O
2
0
1
O
O
O
O
1
2
0

可以看出,对环起始点处的长度length*,
只要存在 0 < = n < C i r c l e L e n 使 得 0<=n<CircleLen使得 0<=n<CircleLen使(length*+n)%(CircleLen)==0
那么就可以断定是个环形链表。
从n的范围很容易看出一定有n使之成立。而 l e n g t h ∗ + n length*+n length+n实际上就是圈子里的第n-1个节点的length。
所以只要遍历到某个节点length%(CircleLen)==0,我们就可以断言它是环形链表。

2.1.2复杂度分析

时间复杂度: O ( n 2 ) O(n^2) O(n2)对第length个节点最多需要length次操作。
空间复杂度: O ( 1 ) O(1) O(1)未调用局部内存空间。

2.1.2代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        vector<ListNode*> pointers(NULL);
        ListNode*temp(NULL);
        int i(0),length(0);
        while(head!=NULL)
        {   
            pointers.push_back(head);
            temp=head;
            for(i=0;i<length&&temp!=NULL;i++)
            {
                if(temp==pointers[i])
                return true;
                else
                temp=temp->next;
            }
            head=head->next;
            ++length;
        }
        return false;
        
    }
};

2.2切断法

2.2.1思路

我考虑过用NULL切断,迭代它原本的next节点找爸爸的方法,想到可能死循环考虑使用递归,但找不到判断结尾的方法。浏览题解发现用自己的next切断,用自己的next找爸爸的神奇方法。(大概是昨天调试的错误让我默认避免自己指自己的节点)

2.2.2复杂度分析(两种实现方法)

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

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public://直接法
    bool hasCycle(ListNode *head) {
        ListNode *cut;
        while(head!=NULL&&head->next!=NULL)
        {
               if(head->next==head->next->next)
            return true;
            cut=head;
            head=head->next;
            cut->next=cut;
        }
        return false;
        
    }
};

在这里插入图片描述
使用递归

class Solution {

        public :bool hasCycle(ListNode* head) {
//结尾判断
    if (head == NULL || head->next == NULL)
        return false;
    
    if (head->next == head)
        return true;
        //归纳
    ListNode* nextNode = head->next;
     head->next = head;
    return hasCycle(nextNode);
}

        
    
};

在这里插入图片描述

2.3快慢指针

2.3.1思路

环形赛道追及问题
设两指针速度v1,v2且v1<v2
设进入跑道前有m个节点
跑道有n个节点,经时间t,k圈两针相遇
t = ( m + k n ) / v 2 − v 1 t=(m+kn)/v2-v1 t=(m+kn)/v2v1

2.3.2复杂度

时间:O(n)
空间O(1)

2.3.3代码

class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head==NULL)
        return false;
        ListNode *v1(head),*v2(head->next);
        
        while(v2!=NULL&&v2->next!=NULL)
        {
            if(v2==v1)
            return true;
            else
           { v1=v1->next;
           v2=v2->next->next;
           }
        }
        return false;
    }
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值