环形链表、

2023-11-18 15:45:38 浏览数 (1)

给你一个链表的头节点 head ,判断链表中是否有环。

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

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

示例 1:

代码语言:javascript复制
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

代码语言:javascript复制
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

代码语言:javascript复制
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

提示:

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

1,什么是指针?     对于学习C 的伙伴们对指针估计已经很熟悉了,但是在其他语言中却没有直接的指针可以使用,那么其他语言就不能和指针一起玩了嘛?其实不是的,指针是一个宽泛的概念,其实在你用循环遍历容器的时候,那个在循环中不断自增的 i 其实就可以被称为指针了;其实指针就是指一个指向容器中某一个值的东西而已,就好像下面这个代码:

C Python3 int i = 1; vector<int> nums = {1,2,3}; cout << nums[i] << endl; 其中我们将 i 作为下标访问了列表的第2个元素(数组下标从0开始),这时候我们也可以把 i 称为指向列表第2个元素的一个指针。

2,什么是快慢指针?     我们在遍历容器的时候,有一般都会习惯性的定义一个指针 i ,每经历一轮循环 i 都会向后移一位指向下一个元素(通过自增实现);而快慢指针就是定义两个指针 fast 和 slow ,一开始都处于容器的头部,他们唯一的区别就是每经历一轮循环,快指针向后移动的位数比慢指针多(比如快指针走两步,慢指针走一步)。

3,快慢指针有啥用?     快慢指针可以干的事情很多,可以用于返回不支持随机访问容器(不可以直接通过下标访问元素的容器)的中间元素,比如返回链表的中间节点(876. 链表的中间结点)(题解:快慢指针解决链表的中间节点),亦或是像本题一样解决环问题等等。

4,本题思路     这道题是检测链表中是否有环的存在,如果有则返回true,没有则返回false;有的朋友就直接使用集合去计数了,如果某个节点在访问时已经被记录访问过就返回true,否则当指针走到链表尾部时返回false。但这种写法无疑对内存的占用不会小,那有没有其他的办法呢?这里就可以用到快慢指针了。像下图的链表:

上面的链表是一个简单的环形链表,我们可以试着用两根手指来代替两个指针,开始两个指针都在头部,开始循环后快指针走两步,慢指针走一步;稍加模拟之后就会发现,快指针虽然比慢指针快,但因为环的存在,快指针比慢指针先进入环,然后快指针会到慢指针的后面,最终在-4节点相遇;当没有环的情况下,快指针永远比慢指针快,所以他们出发之后便不可能再相遇,所以,这题的思路就是,快慢指针如果在链表的遍历过程中相遇,则证明链表中存在环。

5,代码实现

代码语言:javascript复制
class Solution {
public:
    bool hasCycle(ListNode *head) {
        //快慢指针定义
        ListNode* fast = head;
        ListNode* slow = head;
        //fast指针不为空指针且fast指针下一个节点也不为空指针
        while(fast != NULL && fast -> next != NULL){
            //快指针两步,慢指针一步
            fast = fast -> next -> next;
            slow = slow -> next;
            //相遇时返回true
            if(fast == slow) return true;
        }
        //遍历结束还未相遇,返回false
        return false;
    }
};

0 人点赞