相交链表
输入两个链表,找出它们的第一个公共结点
示例1:
输入:intersectVal=8,listA=[4,1,8,4,5],listB=[5,0,1,8,4,5],
skipA=2,skipB=3
输出:Reference of the node with value=8
输入解释:相交结点的值为8(注意:如果两个列表相交则不能为0)。
从各自的表头开始算起,链表 A 为[4,1,8,4,5],链表 B 为[5,0,1,8,4,5]。
在 A 中,相交结点前有 2 个结点;在 B 中,相交结点前有 3 个结点。
示例2:
输入:intersectVal=2,listA=[0,9,1,2,4],listB=[3,2,4],
skipA=3,skipB=1
输出:Reference of the node with value=2
输入解释:相交结点的值为2(注意:如果两个列表相交则不能为0)。
从各自的表头开始算起,链表 A 为[0,9,1,2,4],链表 B 为[3,2,4]。
在 A 中,相交结点前有 3 个结点;在 B 中,相交结点前有 1 个结点。
示例3:
输入:intersectVal=0,listA=[2,6,4],listB=[1,5],
skipA=3,skipB=2
输出:null
输入解释:从各自的表头开始算起,链表 A 为[2,6,4],链表 B 为[1,5]。
由于这两个链表不相交,所以intersectVal必须为0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
注意:
1.如果两个链表没有交点,返回 null;
2.在返回结果后,两个链表仍必须保持原有的结构;
3.可假定整个链表结构中没有循环;
4.程序尽量满足O(n)时间复杂度,且仅用O(1)内存。
思路:
1.先各自求出链表的长度
2.让长的先走 长度差步
3.同时走,第一次相遇时,就是交点
private int getLength(ListNode head) {
int len = 0;
for (ListNode c = head; c != null; c = c.next) {
len++;
}
return len;
}
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = getLength(headA);
int lenB = getLength(headB);
ListNode longer = headA;
ListNode shorter = headB;
int diff = lenA - lenB;
if (lenA < lenB) {
longer = headB;
shorter = headA;
diff = lenB - lenA;
}
for (int i = 0; i < diff; i++) {
longer = longer.next;
}
while (longer != shorter) {
longer = longer.next;
shorter = shorter.next;
}
return longer;
}
环形链表
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例1:
示例2:
示例3:
快慢指针:
快的一次 2 步,慢的一次 1 步
问:快的一次 3 步或者 n(>=3) 步?
答:不可以,可能会一直错过
办法:
1.把带环转为相交问题
2.一个引用从起点出发
一个引用从相遇点出发
一定会在环的入口点相遇
证明:
1.慢引用走的距离 L+C
2.快引用走的距离 L+C+(n+1)*R
3.快引用走的距离 2*(L+C)=2L+2C
2L+2C = L+C+(n+1)*R
L = nR+(R-C)
1.快慢指针(一个1步,一个2步,不能1步,一个n步,因为可能会错过)
2.如果相遇,带环;如果快的遇到null,不带环
3.求入环点
1.转化为相交问题
2.一个从起点出发,一个从相遇点出发,都走一步,一定相遇在入环点
思路:
// 求相遇点
// 如果快的遇到 null,表示没有环,直接返回 null
// 相遇点出发 + 起点出发,最终相遇
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
// fast 遇到 null,表示不带环,返回 null
// fast == slow,表示遇到相遇点了
do {
if (fast == null) {
return null;
}
fast = fast.next;
if (fast == null) {
return null;
}
fast = fast.next;
slow = slow.next;
} while (fast != slow);
ListNode p = head;
ListNode q = slow;
while (p != q) {
p = p.next;
q = q.next;
}
return p;
}
}