题目:输入两个单链表,找出它们的第一个公共节点。以下图为例,对一个公共节点为6所在的节点。
例子如下:
1 -> 2 -> 3 -> 6 -> 7
4 -> 5 ↗
思路:
思路一:具体算法为:分别遍历两个链表,得到分别对应的长度。然后求长度的差值,把较长的那个链表向后移动这个差值的个数,然后一一比较即可。
思路二:可以用环的思想来做,我们让两条链表分别从各自的开头开始往后遍历,当其中一条遍历到末尾时,我们跳到另一个条链表的开头继续遍历。两个指针最终会相等,而且只有两种情况,一种情况是在交点处相遇,另一种情况是在各自的末尾的空节点处相等。为什么一定会相等呢,因为两个指针走过的路程相同,是两个链表的长度之和,所以一定会相等。这个思路真的很巧妙,而且更重要的是代码写起来特别的简洁。
基于以上思路,java参考代码如下:
package chapter5;
public class P253_FindFirstCommonNode{
public static class ListNode{
int val;
ListNode next;
public ListNode(int val){
this.val=val;
this.next=null;
}
}
//解法一:
public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;
ListNode cur1=headA,cur2=headB;
int lenA = getLength(cur1), lenB = getLength(cur2);
if (lenA > lenB) {
for (int i = 0; i < lenA - lenB; ++i) cur1 = cur1.next;
} else {
for (int i = 0; i < lenB - lenA; ++i) cur2 = cur2.next;
}
while (cur1 != null && cur2 != null && cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return (cur1 != null && cur2 != null) ? cur1 : null;//注意点1:考虑两个链表没有公共节点的情况
}
public static int getLength(ListNode head) {
int cnt = 0;
ListNode cur=head;
while (cur != null) {
++cnt;
cur = cur.next;
}
return cnt;
}
//解法二:
public static ListNode getIntersectionNode2(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;//注意点1:特殊情况一定要考虑
ListNode a = headA, b = headB;
while (a != b) {
a = (a != null) ? a.next : headB;//注意点2:条件运算符用得恰当的话,可以简化代码
b = (b != null) ? b.next : headA;// a!=null b!=null 换成 a.next!=null b.next!=null 均可
}
return a;
}
public static void main(String[] args){
// 1->2->3->6->7
// 4->5↗
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);
ListNode node6 = new ListNode(6);
ListNode node7 = new ListNode(7);
node1.next = node2;
node2.next = node3;
node3.next = node6;
node4.next = node5;
node5.next = node6;
node6.next = node7;
ListNode commonNode = getIntersectionNode(node1,node4);
System.out.println(commonNode.val);
ListNode commonNode2 = getIntersectionNode2(node1,node4);
System.out.println(commonNode2.val);
}
}
相应的注意点见代码注解部分。
测试用例:
a.功能测试(输入的两个链表有公共节点:第一个公共节点在链表的中间,第一个公共节点在链表的末尾,第一个公共节点是链表的头节点;输入的两个链表没有公共节点)。
b.特殊输入测试(输入的链表头节点是nullptr指针)。