剑指 Offer II 022. 链表中环的入口节点(142. 环形链表 II && 141. 环形链表)

题目:

 

 

 

思路:

【1】剑指 Offer II 022. 链表中环的入口节点(142. 环形链表 II )

【1.1】哈希表作为辅助空间的方式

【1.2】进阶的,不借助辅助空间,采用双指针的方式

双指针的原理:
当f与s在环内相遇时, s与f相对于入口起点的距离为c:
f 总路程= a + xb + c (f已经走了x圈, x > y)
s 总路程 = a + yb + c (s已经走了y圈, y >= 0)

由于 f 比 s移动快 所以 x > y, 所以假设 z = x - y;
f 总路程 = a + (y + z)b + c = a + yb  + c + zb;

所以 代入 s总路程 = a + yb +c 得到: f 总路程 = s 总路程 + zb (z为正整数)
所以 最后结论 第一次相遇时 f 比 s 多走 z 圈

所以此时两者任意一者重新从起点出发,再次相遇必然是环的入口

 【2】141. 环形链表

本质上是借鉴上面进阶版本的双指针思路
用走两步的快指针和走一步的慢指针
如果快指针会变为null,则说明不存在环,会到底的
如果快指针=慢指针,则说明存在环,两者会相遇

代码展示:

【1】剑指 Offer II 022. 链表中环的入口节点(142. 环形链表 II ):

哈希表辅助空间的方式:

//时间3 ms击败21.36%
//内存42.4 MB击败7.29%
public class Solution {
    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;
    }
}

 

双指针的方式:

//时间0 ms击败100%
//内存41.6 MB击败70.14%
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head, slow = head;

        //如果无环返回null
        while (true) {
            if (fast == null || fast.next == null) return null;
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) break;
        }
        //如果有环输出环入口
        fast = head;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }

        return fast;
    }
}

  【2】141. 环形链表

//时间0 ms 击败 100%
//内存42.7 MB 击败 8.77%
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode fast = head, slow = head;
        while (true){
            if (fast == null || fast.next == null) return false;
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) break;
        }
        return true;
    }
}

 

posted @ 2023-07-06 11:33  忧愁的chafry  阅读(11)  评论(0编辑  收藏  举报