Skip to content

Latest commit

 

History

History
143 lines (129 loc) · 4.52 KB

File metadata and controls

143 lines (129 loc) · 4.52 KB

题目描述:编写一个程序,找到两个单链表相交的起始节点。

如下面的两个链表**:**

img

在节点 c1 开始相交。

eg:

示例 1输入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输入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输入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

思路描述:最简单的方法莫过于把两个单链表都存一下,然后遍历一遍是否有相同的节点即可。时间复杂度O(n^2),但是会超时。

/**
 * 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) {
        vector<ListNode*> nodesA, nodesB;
        while(headA){
            nodesA.push_back(headA);
            headA = headA->next;
        }
        while(headB){
            nodesB.push_back(headB);
            headB = headB->next;
        }
        for(int i = 0; i < nodesA.size(); i ++)
            for(int j = 0; j < nodesB.size(); j ++){
                if(nodesA[i] == nodesB[j])
                    return nodesA[i];
            }
        return 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) {
        vector<ListNode*> nodesA, nodesB;
        while(headA){
            nodesA.push_back(headA);
            headA = headA->next;
        }
        while(headB){
            nodesB.push_back(headB);
            headB = headB->next;
        }
        if(nodesA.size() == 0 || nodesB.size() == 0) return NULL;
        int i = nodesA.size() - 1, j = nodesB.size() - 1;
        if(nodesA[i] != nodesB[j]) return NULL;
        while(i >= 0 && j >= 0){
            cout << nodesA[i]->val;
            if(nodesA[i] != nodesB[j]){
                return nodesA[i + 1];
            }
            i --; j --;
        }
        return nodesA[i + 1];
    }
};

双指针法

创建两个指针 pA 和 pB,分别初始化为链表 AB 的头结点。然后让它们向后逐结点遍历。

当 pA到达链表的尾部时,将它重定位到链表 B 的头结点 (你没看错,就是链表 B); 类似的,当 pB到达链表的尾部时,将它重定位到链表 A 的头结点。

若在某一时刻 pA 和 pB 相遇,则 pA/pB 为相交结点。

不得不说想不到,nb

/**
 * 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* pA = headA, *pB = headB;
        int circle = 0;
        while(1){
            if(pA == pB) return pA;
            if(pA) pA =pA->next;
            else if(circle == 0) {
                pA = headB; circle = 1;
            } else return NULL;
            if(pB) pB = pB->next;
            else pB = headA;
        }
        return NULL;
    }
};