1. The simplest method is to use a pointer to a traversal table. Every time a node is encountered, its memory address (in Java, objects can be used. put hashcode () as a key in a hashtable. in this case, when duplicate keys appear in hashtable, it indicates that the linked list has loops. the time complexity of this method is O (n), and the space is also O (n ).
2. Use the reverse pointer method to reverse the pointer of a node every time a node exists:
Boolean reverse(Node *head) { Node *curr = head; Node *next = head->next; curr->next = NULL; while(next!=NULL) { if(next == head) { /* go back to the head of the list, so there is a loop */ next->next = curr; return TRUE; } Node *temp = curr; curr = next; next = next->next; curr->next = temp; } /* at the end of list, so there is no loop, let‘s reverse the list back */ next = curr->next; curr ->next = NULL; while(next!=NULL) { Node *temp = curr; curr = next; next = next->next; curr->next = temp; } return FALSE;}
It seems that this is a strange method: when there is a ring, the next pointer will eventually go to the head of the linked list; when there is no ring, the next pointer will reverse the structure of the linked list (reverse the linked list ), so we need to reverse the linked list again. the spatial complexity of this method is O (1). In fact, we use three additional pointers, while the time complexity is O (n ), we can traverse the entire linked list at most two times (when there is no ring in the linked list ).
The biggest disadvantage of this method is that it is not safe in the case of multithreading. When multiple threads are reading the linked list, the check loop thread will change the state of the linked list, although we finally restored the structure of the linked list itself, other threads cannot guarantee correct results.
3. This is what the average interviewer expects: Fast pointer and slow pointer.
Boolean has_loop(Node *head) { Node *pf = head; /* fast pointer */ Node *ps = head; /* slow pointer */ while(true) { if(pf && pf->next) pf = pf->next->next; else return FALSE; ps = ps->next; if(ps == pf) return TRUE; }}
It should be noted that when the slow pointer (PS) enters the ring, it will take up to n-1 steps to meet the fast pointer (PF), where N is the length of the ring. that is to say, the fast pointer can not skip the slow pointer in the ring, which can be proved simply by induction.
(1) When PS in the ring position I, and PF in the ring position I-1, in the next iteration, PS will meet PF in I + 1.
(2) When PS in the ring position I, and PF in the ring position I-2, in the next iteration, PS in I + 1, PF in I, so the next iteration PS and PF will meet at the I + 2 position.
(3) similar to the above reasoning process, when PS is in I and PF is in I + 1, they will pass through n-1 iteration and encounter at I + n-1. therefore, the number of slow pointer steps does not exceed n-1.
Extension:
There are still some extensions to this question. For example, how can we find the starting node of the ring? How to unlock this ring? The essence of these problems is how to find the node with "edge.
We can solve this problem by using a deformation in method 3:
Boolean has_loop(Node *head) { Node *pf = head; /* fast pointer */ Node *ps = head; /* slow pointer */ while(true) { /* step 1, is there a loop? */ if(pf && pf->next) pf = pf->next->next; else return FALSE; ps = ps->next; if(ps == pf) break; } /* step 2, how long is the loop */ int i = 0; do { ps = ps->next; pf = pf->next->next; i++; } while(ps!=pf) /* step 3, use 2 addtional pointers with distance i to break the loop */ ps = head; pf = head; int j; for(j=0; j<i; j++) { pf = pf->next; } j = 0; while(ps!=pf) { ps = ps->next; pf = pf->next; j++; } printf("loop begins at position %d, node address is %x", j, ps); /*step 4, break the loop*/ for(j=0; j<=i; j++) { ps = ps->next; } //step i-1 in the loop from loop beginning ps->next = NULL; // break the loop return TRUE;}
How do I check whether a link exists on a one-way linked list?