分析:
首先要理解什么是公共节点,并不是两个节点的值相同就是公共节点。
而是在第一链表和第二链表中都存在一个节点,该节点往后的子链表在两个链表中是相同的。
方法一
最直观就是暴力法,在第一链表上顺序遍历每个节点,每遍历到一个节点,就在第二个链表上顺序遍历每个节点。如果在第二个链表上有一个节点和第一个链表上的节点一样,则说明两个链表在这个节点上重合,但是这种方法的复杂度为O(m * nm∗n)(第一个链表长度为m,第二个链表的长度为n)
方法二
如果两个链表存在公共节点,那么公共节点出现在两个链表的尾部。如果我们从两个链表的尾部开始往前比较,那么最后一个相同的节点就是我们要找的节点。但是这两个链表是单向的,要实现尾节点最先比较,我们可以借助两个辅助栈。分别将两个链表的节点放入两个栈中,这样栈顶就是两个链表的尾节点,比较两个栈顶节点是否相同,如果相同,将栈顶弹出比较下一个栈顶,直到找到最后一个相同的栈顶。时间复杂度O(m + n)。
// 思路1
function FindFirstCommonNode(pHead1, pHead2)
{
// write code here
if (!pHead1 || !pHead2) {
return null
}
let arr1 = []
let arr2 = []
while (pHead1) {
arr1.push(pHead1)
pHead1 = pHead1.next
}
while (pHead2) {
arr2.push(pHead2)
pHead2 = pHead2.next
}
let i = arr1.length - 1
let j = arr2.length - 1
let same = null
while (i >= 0 && j >=0) {
if (arr1[i] === arr2[j]) {
same = arr1[i]
}
i--
j--
}
return same
}
方法三
先获得两个链表的长度,然后在较长的链表上先走若干步(两链表长度之差),接着同时在两个链表上遍历,找到的第一个相同的节点就是他们的第一个公共节点。时间复杂度O(m + n)。
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function FindFirstCommonNode(pHead1, pHead2) {
// write code here
if (!pHead1 || !pHead2) {
return null
}
const len1 = getLinkLength(pHead1),
len2 = getLinkLength(pHead2);
let pLong = pHead1,
pShort = pHead2,
lenGap = len1 - len2;
if (len1 < len2) {
pLong = pHead2;
pShort = pHead1;
lenGap = len2 - len1;
}
while (lenGap--) {
pLong = pLong.next;
}
while (pLong !== null) {
// pLong,pShort一起跑
if (pLong.val === pShort.val) {
return pLong;
}
pLong = pLong.next;
pShort = pShort.next;
}
return null;
}
function getLinkLength(pHead) {
let length = 0;
while (pHead !== null) {
pHead = pHead.next;
length++;
}
return length;
}
方法四
用两个指针扫描”两个链表“,最终两个指针到达 null 或者到达公共结点。