题目:输入两个链表,找出它们的第一个公共结点。
思路:
- 蛮力法:遍历第一个链表的结点,每到一个结点,就在第二个链表上遍历每个结点,判断是否相等。时间复杂度为O(m*n),效率低,注意新一轮循环要将链表指向头部;
- 使用栈:由于公共结点出现在尾部,所以用两个栈分别放入两个链表中的结点,从尾结点开始出栈比较。时间复杂度O(m+n),空间复杂度O(m+n)。
- 利用长度关系:计算两个链表的长度之差,长链表先走相差的步数,之后长短链表同时遍历,找到的第一个相同的结点就是第一个公共结点。
实现:
//蛮力法
public ListNode FindFirstCommonNode1(ListNode pHead1, ListNode pHead2) {
ListNode init = pHead2;
while(pHead1!=null){
while(pHead2!=null) {
System.out.println(pHead1.val+" "+pHead2.val);
if(pHead1 == pHead2) {
System.out.println("yes");
return pHead1;
}
pHead2 = pHead2.next;
}
pHead1 = pHead1.next;
pHead2 = init;
}
return null;
}
//栈
public ListNode FindFirstCommonNode2(ListNode pHead1, ListNode pHead2) {
Stack<ListNode> s1 = new Stack<>();
Stack<ListNode> s2 = new Stack<>();
while(pHead1!=null){
s1.push(pHead1);
pHead1 = pHead1.next;
}
while(pHead2!=null){
s2.push(pHead2);
pHead2 = pHead2.next;
}
ListNode res = null;
while(s1.size()!=0&&s2.size()!=0&&s1.peek() == s2.peek()){
res = s1.peek();
s1.pop();
s2.pop();
}
return res;
}
//长度关系
public ListNode FindFirstCommonNode3(ListNode pHead1, ListNode pHead2) {
int len1 = getLen(pHead1);
int len2 = getLen(pHead2);
ListNode longList = pHead1;
ListNode shortList = pHead2;
int pre = len1 -len2;
if(len1<len2){
longList = pHead2;
shortList = pHead1;
pre = len2 -len1;
}
while((pre--)>0){
longList =longList.next;
}
while(longList!=null&&shortList!=null&&longList!=shortList){
longList=longList.next;
shortList=shortList.next;
}
return longList;
}
public int getLen(ListNode head){
int len=0;
while(head!=null){
len++;
head = head.next;
}
return len;
}
收获:
由于有共同结点时,后面的链表是重合的,所以这道题关键是要保证最后同时遍历到达尾结点,因此就有了后面的方法:
利用栈的先进后出实现同时到达;
利用长度关系,长链表先行几步,实现同时到达;