C++實現LeetCode(160.求兩個鏈表的交點)

[LeetCode] 160.Intersection of Two Linked Lists 求兩個鏈表的交點

Write a program to find the node at which the intersection of two singly linked lists begins.

For example, the following two linked lists:

A:          a1 → a2

c1 → c2 → c3
↗           
B:     b1 → b2 → b3

begin to intersect at node c1.

Notes:

  • If the two linked lists have no intersection at all, return null.
  • The linked lists must retain their original structure after the function returns.
  • You may assume there are no cycles anywhere in the entire linked structure.
  • Your code should preferably run in O(n) time and use only O(1) memory.

Credits:
Special thanks to @stellari for adding this problem and creating all test cases.

我還以為以後在不能免費做OJ的題瞭呢,想不到 OJ 又放出瞭不需要買書就能做的題,業界良心啊,哈哈^_^。這道求兩個鏈表的交點題要求執行時間為 O(n),則不能利用類似冒泡法原理去暴力查找相同點,事實證明如果鏈表很長的話,那樣的方法效率很低。我也想到會不會是像之前刪除重復元素的題一樣需要用兩個指針來遍歷,可是想瞭好久也沒想出來怎麼弄。無奈上網搜大神們的解法,發覺其實解法很簡單,因為如果兩個鏈長度相同的話,那麼對應的一個個比下去就能找到,所以隻需要把長鏈表變短即可。具體算法為:分別遍歷兩個鏈表,得到分別對應的長度。然後求長度的差值,把較長的那個鏈表向後移動這個差值的個數,然後一一比較即可。代碼如下: 

C++ 解法一:

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if (!headA || !headB) return NULL;
        int lenA = getLength(headA), lenB = getLength(headB);
        if (lenA < lenB) {
            for (int i = 0; i < lenB - lenA; ++i) headB = headB->next;
        } else {
            for (int i = 0; i < lenA - lenB; ++i) headA = headA->next;
        }
        while (headA && headB && headA != headB) {
            headA = headA->next;
            headB = headB->next;
        }
        return (headA && headB) ? headA : NULL;
    }
    int getLength(ListNode* head) {
        int cnt = 0;
        while (head) {
            ++cnt;
            head = head->next;
        }
        return cnt;
    }
};

Java 解法一:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return null;
        int lenA = getLength(headA), lenB = getLength(headB);
        if (lenA > lenB) {
            for (int i = 0; i < lenA - lenB; ++i) headA = headA.next;
        } else {
            for (int i = 0; i < lenB - lenA; ++i) headB = headB.next;
        }
        while (headA != null && headB != null && headA != headB) {
            headA = headA.next;
            headB = headB.next;
        }
        return (headA != null && headB != null) ? headA : null;
    }
    public int getLength(ListNode head) {
        int cnt = 0;
        while (head != null) {
            ++cnt;
            head = head.next;
        }
        return cnt;
    }
}

這道題還有一種特別巧妙的方法,雖然題目中強調瞭鏈表中不存在環,但是我們可以用環的思想來做,我們讓兩條鏈表分別從各自的開頭開始往後遍歷,當其中一條遍歷到末尾時,我們跳到另一個條鏈表的開頭繼續遍歷。兩個指針最終會相等,而且隻有兩種情況,一種情況是在交點處相遇,另一種情況是在各自的末尾的空節點處相等。為什麼一定會相等呢,因為兩個指針走過的路程相同,是兩個鏈表的長度之和,所以一定會相等。這個思路真的很巧妙,而且更重要的是代碼寫起來特別的簡潔,參見代碼如下:

C++ 解法二:

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

Java 解法二:

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return null;
        ListNode a = headA, b = headB;
        while (a != b) {
            a = (a != null) ? a.next : headB;
            b = (b != null) ? b.next : headA;
        }
        return a;
    }
}

類似題目:

Minimum Index Sum of Two Lists

參考資料:

https://leetcode.com/problems/intersection-of-two-linked-lists/

https://leetcode.com/problems/intersection-of-two-linked-lists/discuss/49792/Concise-JAVA-solution-O(1)-memory-O(n)-time

https://leetcode.com/problems/intersection-of-two-linked-lists/discuss/49785/Java-solution-without-knowing-the-difference-in-len!

到此這篇關於C++實現LeetCode(160.求兩個鏈表的交點)的文章就介紹到這瞭,更多相關C++實現求兩個鏈表的交點內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: