[牛客算法总结]:判断链表中是否有环

标签:

链表、Hash、双指针

题目:

判断给定的链表中是否有环。如果有环则返回true,否则返回false。

数据范围:链表长度 0 \le n \le 100000≤n≤10000,链表中任意节点的值满足 |val| <= 100000∣val∣<=100000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

输入分为两部分,第一部分为链表,第二部分代表是否有环,然后将组成的head头结点传入到函数里面。-1代表无环,其它的数字代表有环,这些参数解释仅仅是为了方便读者自测调试。实际在编程时读入的是链表的头节点。

例如输入{3,2,0,-4},1时,对应的链表结构如下图所示:
请添加图片描述
可以看出环的入口结点为从头结点开始的第1个结点(注:头结点为第0个结点),所以输出true。

输入:{3,2,0,-4},1
返回值:true

说明:第一部分{3,2,0,-4}代表一个链表,第二部分的1表示,-4到位置1(注:头结点为位置0),即-4->2存在一个链接,组成传入的head为一个带环的链表,返回true

输入:{1},-1
返回值:false

说明:第一部分{1}代表一个链表,-1代表无环,组成传入head为一个无环的单链表,返回false

反思:

方法一:使用Hash
首先我们可以创建一个HashSet集合来作为缓存(无序,不重复)来存储曾遍历过的节点,然后同样从头结点开始,依次遍历链表中的下一个节点,如果Hash集合中没有下一个节点,则我们把该节点存放到我们的Hash集合中,如果存在,则直接返回true。

方法二:使用双指针
对于链表,我们一个节点只能指向下一个节点,不能指向两个节点,所以我们可以先说一下线性链表的其中一个性质:普通的线性链表的末尾一定有null,那么我们就可以根据链表中是否有null判断是不是有环。而环型链表的环一定在末尾,末尾没有null了。

但是,唤醒链表遍历过程中会不断循环,线性链表遍历到null就结束了,但是环形链表何时才能结束呢?我们可以使用双指针的技巧,同向访问的双指针,速度是快慢的,只要有环,两者会在环内不断循环,因为两者速度有差异,两者必定会相遇。
1、设置快慢指针,初始值都指向链表头。
2、遍历链表,快指针每次走两步,慢指针每次走一步。
3、如果快指针到了链表的末尾,说明没有环,因为它每次走两步,所以快指针会在环内追到慢指针,两者相遇代表有环。

用到的知识点:

链表、HashSet集合、双指针

代码:

链表定义

class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
        next = null;
    }

方法一:使用Hash

    public boolean hasCycle1(ListNode head) {
        HashSet<ListNode> listNodes = new HashSet<ListNode>();
        listNodes.add(head);
        while (head != null && head.next != null) {
            if (!listNodes.contains(head.next)) {
                listNodes.add(head.next);
            } else {
                return true;
            }
            head = head.next;
        }
        return false;
    }
    public boolean hasCycle2(ListNode head) {
        // 先判断当前节点是否为null
        if (head == null) {
            return false;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = head.next.next;
            slow = head.next;
            if (fast == slow) {
                return true;
            }
        }
        return false;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值