题目
输入两个链表,找出它们的第一个公共结点。
分析
- 链表是否为空
- 链表是否是无环链表?是否是单链表?
- 如果两个链表存在公共结点,那从公共结点开始一直到链表的结尾都是一样的,因此只需要从链表的结尾开始,往前搜索,找到最后一个相同的结点即可。单向链表,只能从前向后搜索,借助栈来完成。先把两个链表依次装到两个栈中,然后比较两个栈的栈顶结点是否相同,如果相同则出栈,如果不同,那最后相同的结点就是公共节点。
- 先求2个链表的长度,让长的先走两个链表的长度差,然后再一起走,直到找到第一个公共结点。
- 由于2个链表都没有环,可以把第二个链表接在第一个链表后面,这样就把问题转化为求环的入口节点问题。
- 两个指针p1和p2分别指向链表A和链表B,它们同时向前走,当走到尾节点时,转向另一个链表,比如p1走到链表A的尾节点时,下一步就走到链表B,p2走到链表B的尾节点时,下一步就走到链表A,当p1==p2时,就是链表的相交点
解答
public class FirstCommonNode {
public static void main(String[] args) {
ListNode node1 = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode node4 = new ListNode(4);
ListNode node5 = new ListNode(5);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
ListNode node9 = new ListNode(9);
ListNode node8 = new ListNode(8);
ListNode node7 = new ListNode(7);
ListNode node6 = new ListNode(6);
node8.next = node7;
node7.next = node6;
node6.next = node4;
System.out.println(findFirstCommonNode(null, node9));
System.out.println(findFirstCommonNode(node1, null));
System.out.println(findFirstCommonNode(node1, node9));
System.out.println(findFirstCommonNode(node1, node8).val);
node5.next = node3;
System.out.println(hasLoop(node1));
}
/**
* 判断一个给定链表是否有环
*/
public static boolean hasLoop(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head.next;
ListNode fast = head.next.next;
while (true) {
if (fast == null || fast.next == null) {
// fast走到链表尾
return false;
} else if (fast.next == slow || fast == slow) {
return true;
} else {
slow = slow.next;
fast = fast.next.next;
}
}
}
public static ListNode findFirstCommonNode(ListNode current1, ListNode current2) {
HashMap<ListNode, Integer> hashMap = new HashMap<>(16);
while (current1 != null) {
hashMap.put(current1, null);
current1 = current1.next;
}
while (current2 != null) {
if (hashMap.containsKey(current2)) {
return current2;
} else if (getNoLoopLength(current2) == 1) {
// 链表2长度为1的特殊情况
return null;
}
current2 = current2.next;
}
return null;
}
/**
* 无环单链表长度
*/
private static int getNoLoopLength(ListNode pHead) {
int length = 0;
ListNode current = pHead;
while (current != null) {
length++;
current = current.next;
}
return length;
}
// 记得重写hashCode()和equals()方法
public static class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
}
判断链表是否有环
参考上面的hasLoop方法
拓展