问题描述
问题一: 如何判断一个链表是否有环,如果有, 则返回第一个进入环的节点, 没有则返回null.
问题二: 如何判断两个无环链表是否相交, 相交则返回第一个相交节点, 不相交则返回null.
问题三: 如何判断两个有环链表是否相交, 相交则返回第一个相交节点, 不相交则返回null.
问题一
问题一: 如何判断一个链表是否有环,如果有, 则返回第一个进入环的节点, 没有则返回null.
算法:
- 设置两个指针 pLow, pFast, 都从第一个节点出发
- pLow每次前进一个节点
- pFast每次前进两个节点
- 如果pFast遇到了null 节点, 则说明链表无环, 返回null
- 如果pLow和pFast相遇, 则说明链表有环
- 确定第一个进入环的节点:
- 记从头节点到入环节点的距离为x
- 入环节点到pLow和pFast相遇节点的距离为y
- pLow到相遇节点走过的距离为s, 则由
s = x + y
- 记环的长度为r, 则pFast到相遇时走过的距离为
s + nr, n >= 1
- 因为pFast走过的距离为pLow的两倍, 则有
s + nr = 2s
- 则可推出
s = nr -> x + y = nr -> x = nr - y
- 由以上公式可得到, 当一个指针p1从头节点触发, 一个指针p2从相交节点出发, p1走过x的距离时, p2走过nr - y的距离, 又因为p2离相交点的距离为y(此处可画图理解), 所以当p1与p2相遇时, 必然在相交点处.
问题二:
问题二: 如何判断两个无环链表是否相交, 相交则返回第一个相交节点, 不相交则返回null.
算法:
- 得到链表1和链表2的长度, 分别记为 len1, len2, 假设 len1 > len2
- p1指向链表1的头节点, p2指向链表2的头节点
- p1先移动 len1 - len2的距离
- 之后p1和p2同时移动, 并比较两个指针指向的节点是否相同, 如果相同,则说明两个链表相交, 返回该节点. 如果不相同, 继续移动, 直到链表结尾, 说明两个链表不相交.
问题三:
问题三: 如何判断两个有环链表是否相交, 相交则返回第一个相交节点, 不相交则返回null.
算法:
分为三种情况
- 先根据问题一的算法, 找到两个有环链表的入环节点.
- case 1: 如果两个链表的入环节点相同, 则两个链表相交
- 入环节点作为尾部节点, 转换为问题二.
- 如果两个链表的入环节点不同
* case 2: 固定一个入环节点, 从另一个入环节点出发, 遍历环一周, 如果遇到第一个入环节点, 则两个链表相交, 返回任意一个入环节点即可.
* case 3: 如果遍历环一周, 没有遇到第一个入环节点, 则两个链表不相交.