【数据结构和算法】链表是否有环3种方式解决

判断链表中是否有环

http://www.nowcoder.com/questionTerminal/650474f313294468a4ded3ce0f7898b9

1,快慢指针解决

判断链表是否有环应该是老生常谈的一个话题了,最简单的一种方式就是快慢指针,慢指针针每次走一步,快指针每次走两步,如果相遇就说明有环,如果有一个为空说明没有环。代码比较简单

public boolean hasCycle(ListNode head) {
    if (head == null)
        return false;
    //快慢两个指针
    ListNode slow = head;
    ListNode fast = head;
    while (fast != null && fast.next != null) {
        //慢指针每次走一步
        slow = slow.next;
        //快指针每次走两步
        fast = fast.next.next;
        //如果相遇,说明有环,直接返回true
        if (slow == fast)
            return true;
    }
    //否则就是没环
    return false;
}

到这里问题好像并没有结束,为什么快慢指针就一定能判断是否有环。我们可以这样来思考一下,假如有环,那么快慢指针最终都会走到环上,假如环的长度是m,快慢指针最近的间距是n,如下图中所示

图片说明

快指针每次走两步,慢指针每次走一步,所以每走一次快慢指针的间距就要缩小一步,在图一中当走n次的时候就会相遇,在图二中当走m-n次的时候就会相遇。


2,存放到集合中

这题还可以把节点存放到集合set中,每次存放的时候判断当前节点是否存在,如果存在,说明有环,直接返回true,比较容易理解

import java.util.Set;
import java.util.HashSet;

public class Solution {
    public boolean hasCycle(ListNode head) {
        Set<listnode> set = new HashSet<>();
        while (head != null) {
            //如果重复出现说明有环
            if (set.contains(head))
                return true;
            //否则就把当前节点加入到集合中
            set.add(head);
            head = head.next;
        }
        return false;
    }
}

3,逐个删除

一个链表从头节点开始一个个删除,所谓删除就是让他的next指针指向他自己。如果没有环,从头结点一个个删除,最后肯定会删完,如下图所示 图片说明 如果是环形的,那么有两种情况,一种是o型的,一种是6型的。原理都是一样,我们就看一下o型的 图片说明

如上图所示,如果删到最后,肯定会出现head=head.next

    public boolean hasCycle(ListNode head) {
        //如果head为空,或者他的next指向为空,直接返回false
        if (head == null || head.next == null)
            return false;
        //如果出现head.next = head表示有环
        if (head.next == head)
            return true;
        ListNode nextNode = head.next;
        //当前节点的next指向他自己,相当于把它删除了
        head.next = head;
        //然后递归,查看下一个节点
        return hasCycle(nextNode);
    }

数据结构和算法 文章被收录于专栏

专注于算法题的讲解,包含常见数据结构,排序,查找,动态规划,回溯算法,贪心算法,双指针,BFS和DFS等等。

全部评论
如果链表中只有一个节点且无环,则快指针一次走两步会发生错误,所以第一句判断语句应加上||head.next==NULL
2 回复 分享
发布于 2021-08-13 21:42
方法二的空间复杂度是O(N)吧。
2 回复 分享
发布于 2021-04-07 09:35
方法二不行吧,如果链表中存在重复数据就不行了呢。
2 回复 分享
发布于 2021-03-12 10:14
第三种太牛了
点赞 回复 分享
发布于 2022-09-10 22:35 黑龙江
太强了
点赞 回复 分享
发布于 2022-04-29 17:04
第三种方***把链表本身破坏掉了
点赞 回复 分享
发布于 2022-03-26 13:40
第三种方法太6了
点赞 回复 分享
发布于 2021-10-14 23:50
膜拜大佬
点赞 回复 分享
发布于 2021-08-03 19:23
请问为什么方法一的循环的判断语句是fast.next和fast,为什么改成fast.next.next就是空指针异常呢?
点赞 回复 分享
发布于 2021-07-27 18:07
你的这个网盘的提取码不对呀
点赞 回复 分享
发布于 2021-04-15 23:54
谢谢!
点赞 回复 分享
发布于 2021-03-20 16:15
优秀,超赞!
点赞 回复 分享
发布于 2021-02-28 17:17

相关推荐

评论
223
28
分享

创作者周榜

更多
牛客网
牛客企业服务