算法通关村第一关——链表经典问题之有环链表笔记

大家好,我是Ryan,本篇记录我在学习链表时遇到的一个情况:有环链表。

考察有环链表通常是首先让你判断链表是否有环,若有环,则进一步地让你找到环的入口位置。接下来我们分析这两个问题。

判断链表是否有环

集合

若是学过Java的集合,可以想到用hashset来解决,一边遍历链表,一边加入到集中,同时判断节点是否已经存在。

public ListNode detectCycle(ListNode head) {
	ListNode pos =head;
	Set<ListNode> visited = new HashSet<ListNode>(); 
	while (pos != null){
		if (visited.contains(pos)) { 
			return pos;
		} else {
			visited.add(pos); 
		}
		pos = pos.next; 
	}
	return null; 
}

这种方法也是我们写工程时常用的,但是面试的时候用这个就体现不出来算法能力了。所以我们还要想另外一个办法。

双指针

这里我们可以用快慢指针来做,首先要想明白这两个指针一定会相遇。

举个例子,两个人在操场跑步,一个人跑得快,一个人跑得慢,这样只要时间足够,快的人一定能再次遇到跑的慢的人。

下面直接给出代码:

public static boolean hasCycleByTwoPoint(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow)
                return true;
        }
        return false;
    }    

确定入口

判断出有环之后,我们接着研究环的入口在哪。

这里可以用数学来简单证明:请添加图片描述
这里假设快指针在第二圈就遇到了慢指针

图中Z是相遇的点,Y是入口。

可以知道fast指针走了a+b+c+b步,slow指针走了a+b步
那么:
2*(a+b)=a+b+c+b 所以a=c

public static ListNode detectCycleByTwoPoint(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode slow = head, fast = head;
        while (fast != null) {
            slow = slow.next;
            if (fast.next != null) {
                fast = fast.next.next;
            } else {
                return null;
            }
            if (fast == slow) {
                ListNode ptr = head;
                while (ptr != slow) {
                    ptr = ptr.next;
                    slow = slow.next;
                }
                return ptr;
            }
        }
        return null;
    }

好了,这次的分享就到这里,下期再见。

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值