Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[剑指 Offer] 52. 两个链表的第一个公共节点 #30

Open
frdmu opened this issue Jul 21, 2021 · 0 comments
Open

[剑指 Offer] 52. 两个链表的第一个公共节点 #30

frdmu opened this issue Jul 21, 2021 · 0 comments

Comments

@frdmu
Copy link
Owner

frdmu commented Jul 21, 2021

输入两个链表,找出它们的第一个公共节点。

如下面的两个链表:
link1
在节点 c1 开始相交。

 

示例 1:
link2

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。 

示例 2:
link3

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:
link4

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。

注意:




解法一:
分别设两个指针,使指针分别指向距离终点相同的位置,再使两个指针一起向后遍历,直到找到交叉点或终点。代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *p1 = headA, *p2 = headB;
        int len1 = 0, len2 = 0;

        while (p1 != NULL) {
            len1++;
            p1 = p1->next;
        }        
        while (p2 != NULL) {
            len2++;
            p2 = p2->next;    
        }
        p1 = headA, p2 = headB;
        if (len1 > len2) {
            int n = len1 - len2;
            for (int i = 0; i < n; i++) {
                p1 = p1->next;    
            }    
        }
        if (len1 < len2) {
            int n = len2 - len1;
            for (int i = 0; i < n; i++) {
                p2 = p2->next;    
            }    
        }
        while (p1 != NULL) {
            if (p1 == p2) {
                return p1;    
            } else {
                p1 = p1->next;
                p2 = p2->next;        
            }    
        }
        
        return NULL;
    }
};

解法二:
哈希表。首先遍历链表A,将结点存入hashtable,再遍历链表B,如果此时某个结点在hashtable中,则此节点就是交点。代码如下:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        map<ListNode*, int> mp;
        
        for (ListNode* p = headA; p != NULL; p = p->next) {
            mp[p] = 1;     
        } 
        for (ListNode* p = headB; p != NULL; p = p->next) {
            if (mp.count(p) != 0) {
                return p;
            }
        }
        
        return NULL;
    }
};

解法三:
双指针。
最巧妙的一种,借用评论里面的一句话:两个跑速一样的人在不同长短的跑道里跑,怎么才能让他们遇见,不断交换他们的跑道,代码如下:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if (headA == NULL || headB == NULL)
            return NULL;
        ListNode *p1 = headA, *p2 = headB;
        
        while (p1 != p2) {
            p1 = p1 == NULL ? headB : p1->next;
            p2 = p2 == NULL ? headA : p2->next; 
        }
        
        return p1;
    }
};

Refer:
两个链表的第一个公共节点

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant