Chapter 2 Linked Lists - 2.5

来源:互联网 发布:淘宝上开店 编辑:程序博客网 时间:2024/06/05 02:41
Problem 2.5: Given a circular linked list, implment an algorithm which returns node at the beginning of the loop.
DEFINITION
Circular linked list: A (corrupt) linked list in which a node's next pointer points to an earlier node, so as to make a loop in the linked list.
EXAMPLE
input: A->B->C->D->E->C[the same C as earlier]
output: C


The only solution I can come up with is the most intuitive one, marking visited node with a hash table.
class node:    def __init__(self, data=None):        self.data = data        self.next = Nonedef find_beginning(head):    hash_table = {}    while head != None:        if hash_table.has_key(head.data):            return head        else:            hash_table[head.data] = 1        head = head.next    return Falseif __name__ == "__main__":    n1 = node(1)    n2 = node(2)    n3 = node(3)    n4 = node(4)    n5 = node(5)    n1.next = n2    n2.next = n3    n3.next = n4    n4.next = n5    n5.next = n3    print find_beginning(n1).data

However, when I turned to the answer page, I found a solution which is so tricky that it takes several minutes to understand:
def find_beginning(head):    p1 = head.next    p2 = head.next.next    while p1.data != p2.data:        p1 = p1.next        p2 = p2.next.next    p3 = head    while p1.data != p3.data:        p1 = p1.next        p3 = p3.next    return p3

Let me explain the code above in detail:
First of all, there are two pointers pointing to the head of linked list. We move pointer p1 one step each time, while moving p2 two steps each time. Let the number of steps from head to the start of loop be k. Then, when p1 comes to the start of the loop in linked list, p2 is k (which is unknown) steps ahead in the loop.
Let the number of nodes in the loop is n. If we keep moving p1 by one step each time and moving p2 by two steps, it will take (n-k) steps before p2 meet p1. Now, let us calculate how many steps is needed to move p1 to the start of loop: it is n-(n-k)=k.
Although k is now known, we can measure it in another way: let a pointer p3 move by one step each time from the head of linked list, while moving p1 at the same speed. When p1 and p3 meet, they are at the start of loop.
What a tricky solution! I learned that we can not only use more than onepointers, but also moving different pointers at different speed.