打题目来源 相交链表
题目描述
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null
。
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
输入两个链表,找出它们的第一个公共结点。
解法1
利用A,B两个表头节点同时往前走,如其中一个走到末尾则将节点指向另一个链表的表头,设链表A长度为m,链表B长度为n 1. 若链表A,B没有相交 A走到表尾后,指向链表B的头节点,接着走完链表B,指向null,共走长度 m+n B走到表尾后,指向链表A的头节点,接着走完链表A,指向null,共走长度 m+n 因此A,B会同时指向null,返回null 2. 若链表A,B会相交,重复第1点中的操作,仍会相遇,走到相交节点时可能会重复多次更换表头动作,若是有缘总会相聚 时间复杂度:O(m+n) 空间复杂度:O(1)
JAVA代码示例
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == headB) {
return headA;
}
ListNode nodeA = headA;
ListNode nodeB = headB;
while (nodeA != nodeB) {
nodeA = nodeA == null ? headB : nodeA.next;
nodeB = nodeB == null ? headA : nodeB.next;
}
return nodeA;
}
方法2:
使用hashmap记录一个链表节点,便利第2个链表,一次判断是否存在hashmap中,如存在则就是相交节点 时间复杂度:O(m+n) 空间复杂度:O(m) A长度为m,链表B长度为n
JAVA代码示例
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Map<ListNode, Integer> listMap = new HashMap<>();
if (headA == null || headB == null) return null;
ListNode p1 = headA;
ListNode p2 = headB;
while (p1 != null) {
listMap.put(p1, p1.val);
p1 = p1.next;
}
while (p2 != null) {
if (listMap.containsKey(p2)) {
return p2;
}
p2 = p2.next != null ? p2.next : null;
}
return null;
}
C++代码示例
class Solution{
public:
ListNode *FindFirstCommonNode(ListNode *pHead1,ListNode *pHead2)
{
map<ListNode*,int > M;
ListNode *pNode = pHead1;
while(pNode!=NULL)
{
M[pNode] =1;
pNode = pNode->next;
}
pNode = pHead2;
while(pNode!=NULL)
{
if(M[pNode])
{
return pNode;
}
pNode = pNode->next;
}
return NULL;
}
};
解法3:
利用快慢指针,较长的表头节点先走,设链表A长度为m,链表B长度为n 且m>n A表头先走(m-n)步后,A,B再同时走,只到节点相同 时间复杂度:O(2m+2n) 空间复杂度:O(1)
JAVA代码示例
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == headB) {
return headA;
}
ListNode nodeA = headA;
ListNode nodeB = headB;
//找出较长的链表
int lenA = 0, lenB = 0;
while (nodeA != null && nodeB != null) {
lenA++;
lenB++;
nodeA = nodeA.next;
nodeB = nodeB.next;
}
while (nodeA != null) {
lenA++;
nodeA = nodeA.next;
}
while (nodeB != null) {
lenB++;
nodeB = nodeB.next;
}
int sub = lenA - lenB;
ListNode fast = headA;
ListNode slow = headB;
if (sub < 0) {
fast = headB;
slow = headA;
sub = -sub;
}
//较长的链表先走m-n步
while (sub > 0) {
fast = fast.next;
sub--;
}
//两个链表同时走
while (fast != null && slow != null) {
if (fast == slow) return fast;
fast = fast.next;
slow = slow.next;
}
return null;
}
C++代码示例
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
};
class Solution{
public:
ListNode* FindFirstCommonNode(ListNode *pHead1,ListNode *pHead2)
{
int length1 = GetListLength(pHead1);
int length2 = GetListLength(pHead2);
int lengthDif =0;
ListNode *pListHeadLong =NULL;
ListNode *pListHeadShort =NULL;
//得到两个链表的长度差,并用连个结点标记长短链表
if(length1>length2)
{
pListHeadLong = pHead1;
pListHeadShort =pHead2;
lengthDif = length1-length2;
}
else
{
pListHeadLong = pHead2;
pListHeadShort = pHead1;
lengthDif = length2-length1;
}
//较长的链表先走几步
for(int i=0;i<lengthDif;i++)
pListHeadLong = pListHeadLong->next;
//此时两个链表同时遍历
while((pListHeadLong!=NULL)&&(pListHeadShort!=NULL)&&(pListHeadShort!=pListHeadLong))
{
pListHeadShort=pListHeadShort->next;
pListHeadLong = pListHeadLong->next;
}
return pListHeadShort;
}
int GetListLength(ListNode *pHead)
{
int length =0;
ListNode *pNode =pHead;
while(pNode!=NULL)
{
pNode= pNode->next;
length++;
}
return length;
}
};