算法题之环形链表问题

算法题之环形链表问题

环形链表问题1

在这里插入图片描述

思路1:利用快慢指针来实现

分析:
我们定义两个指针:分别指向头节点和头节点的下一个节点;
每一次慢指针平移一步(即平移到它的next节点),而快指针则平移两步(即平移到它的next的next节点),完成快指针追赶慢指针的操作;
如果该链表时环形链表,则一定会在某一个时间点,快指针会和慢指针在环内相遇

代码实现
/*
    * 环形链表I:方法1:使用两个指针(快慢指针)来完成环形链表的是否有环判断问题
    * 即定义一个指针first和指针second同时指向链表的头节点
    * 将first指向下一个节点,second指向下下个节点,若second能赶上first,则表示存在环
    * */
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            //即表示该链表不存在节点或者只存在一个节点
            return false;
        }
        //定义两个指针slow和fast:进行追赶
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {//只要first不等于second,就一直进行追赶
            if (fast == null || fast.next == null) {//若first为null或者first的下一个节点为null,说明不存在环形链表,则直接返回false
                return false;
            }
            //将first指向它的下一个节点,second指向它的下下个节点
            slow = slow.next;
            fast = fast.next.next;

        }
        //退出while循环,说明second追赶上了first
        return true;
    }
思路2:使用HashSet存储的唯一性

分析:我们创建一个HashSet,遍历该链表:将节点加入HashSet中
如果存储的节点已经在HashSet中存在了,说明链表为环形的,则返回true;
如果遍历链表结束,没有返回true,则表示该链表不是环形的,则返回false;

代码实现
/*
    * 环形链表I:方法2:使用HashSet的唯一性:将每一个节点的next域添加到HashSet中,若存在相同的next域,则说明存在环
    * */
    public boolean hasCycleByHash(ListNode head) {
        if (head == null || head.next == null) {
            //即表示该链表不存在节点或者只存在一个节点
            return false;
        }
        HashSet<ListNode> set = new HashSet<>();
        ListNode temp = head;
        while (temp != null) {
            if (!set.contains(temp)) {
                set.add(temp);
                temp = temp.next;
            }else {
                return true;
            }
        }
        //说明遍历到链表尾部,仍未发现环,则返回false
        return false;
    }
环形链表问题2

在这里插入图片描述

问题分析

此时环形链表不仅需要判断是否为环形链表,而且还要返回环形链表的入口索引节点:
在这里插入图片描述

代码实现
//环形链表II:方法1:hashset法:
    public ListNode detectCycle01(ListNode head) {
        //如果头节点为空或者只有一个节点:则表示无环
        if(head == null || head.next == null) {
            return null;
        }

        //定义一个HashSet
        HashSet<ListNode> set = new HashSet<>();
        ListNode temp = head;
        while (temp != null) {
            if (set.contains(temp)) {
                return temp;
            }else {
                set.add(temp);
                temp = temp.next;
            }
        }
        //while循环遍历结束,仍未发现环,则返回null
        return null;
    }

在这里插入图片描述

代码实现
//环形链表II:方法2:快慢指针法:快指针追赶上慢指针一定是在环的内部
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        //定义两个指针:slow和fast,以及一个存储最后返回的ListNode变量
        ListNode slow = head;
        ListNode fast = head;
        ListNode temp = head;
        while (true) {
            if (fast == null || fast.next == null) {//当遍历到最后链表的最后一个节点:即无环,返回null
                return null;
            }
            //将快指针指向next.next域,慢指针指向next域
            fast = fast.next.next;
            slow = slow.next;
            //若快慢指针相遇了,则直接break返回,此时slow和fast指针指向的都是相遇时的位置
            if (fast == slow) {
                //当两者相遇了
                break;
            }
        }
        //将temp指针和fast指针一起同步移动,再次相遇则是环的起始位置
        while (temp != fast) {
            temp = temp.next;
            fast = fast.next;
        }
        return temp;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值