题目描述
输入两个链表,找出它们的第一个公共结点
编程思路
1.在第一个链表上顺序遍历每一个结点,每遍历到一个结点的时候,在第二个链表上顺序遍历每一个结点。如果在第二个链表上有一个结点和第一个链表上的结点一样,说明两个链表在这个结点上重合,便找到了他们的公共结点。如果,第一个链表的长得为m,第二个的为n,则时间复杂度为O(mn).
2.如果两个单向链表有公共结点,那么该结点的next也指向同一个结点,这样,从第一个公共结点开始,之后的所有节点都是重合的,而且公共结点出现在两个链表的尾部。如果从尾部开始往前比较,那么最后一个相同的结点就是我们找的结点。但是单向链表只能从头到尾顺序遍历,最后才能到尾结点,因此最后到达的尾结点要最先被比较,这就是典型的“后进先出”,因此可以用栈实现。分别把两个链表的结点放入两个栈里,这样链表的尾结点就是栈顶,接下来比较两个栈顶的结点是否相同,如果相同,则把栈顶弹出接着比较下一个栈顶,直到找到最后一个相同的结点。这这种思路的时间复杂度是O(m+n)。
3.由于两个链表的长度可能不一样,因此从头开始遍历到达尾结点的时间就不一致,因此,我们可以先遍历一遍两个链表得到他们的长度,知道哪个链表长,并且长几个结点,然后在第二次遍历时,在较长的链表上先走若干步,接着再同时在两个链表上遍历,找到的第一个相同的结点就是他们的第一个公共结点。这种思路的时间复杂度也是O(m+n),但不需要辅助栈,提高了空间效率,因此,就使用这种思路来编程。
程序代码(Java语言)
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int length1 = getLength(pHead1);
int length2 = getLength(pHead2);
int length = 0;
ListNode ListHeadLong = null;
ListNode ListHeadShort = null;
if(length2 > length1) {
ListHeadLong = pHead2;
ListHeadShort = pHead1;
length = length2 - length1;
} else {
ListHeadLong = pHead1;
ListHeadShort = pHead2;
length = length1 - length2;
}
for(int i = 0;i < length;i++) {
ListHeadLong = ListHeadLong.next;
}
while((ListHeadLong != null) && (ListHeadShort != null) && (ListHeadLong != ListHeadShort)) {
ListHeadLong = ListHeadLong.next;
ListHeadShort = ListHeadShort.next;
}
return ListHeadLong;
}
private int getLength(ListNode head) {
int length = 0;
ListNode node = head;
while(node != null) {
++length;
node = node.next;
}
return length;
}
}