用 memo(hashset) 去紀錄 headA 所有走過的節。再換 headB 走,如果該節在 memo 裡,就是第一個交會點。
class Solution: def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode: memo = set() PointerA, PointerB = headA, headB while PointerA: memo.add(PointerA) PointerA = PointerA.next while PointerB: if PointerB in memo: return PointerB PointerB = PointerB.next return None有效歸有效,不過會消耗掉大量記憶體,在一個提示空間複雜度 O(1) 之下,這方法似乎不是最好的。
思考一下,如果要第一個交會,那麼兩者行走距離應該是最短的。但是這樣怎麼寫?
[左1右1]、[左1右2, 左2右1]、....。這樣的安排,太沒有效率了。
我一開始本來想用 traceback,這樣空間複雜度會超出 O(1),就沒有把它寫完了。
看了一下前段班,共同點就是 headA跑完換到headB、headB跑完換到headA。
為什麼可以這樣做?
如果有交會,headA = A part + C part、headB = B part + C part。
兩者一起往下跑,跑完換別的跑,會變成 headA->headB = A part + C part + B part + C part、headB->headA = B part + C part + A part + C part。
A part + C part + B part = B part + C part + A part,於是兩者將會在 C part 交會。
這是一個循環的技巧應用,如果有想到,就會快很多。
class Solution: def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode: PointerA, PointerB = headA, headB for _ in range(2): while PointerA and PointerB: PointerA = PointerA.next PointerB = PointerB.next if PointerA: PointerB = headA else: PointerA = headB while PointerA and PointerB: if PointerA == PointerB: return PointerA PointerA = PointerA.next PointerB = PointerB.next return None