views:

1203

answers:

4

Here is the problem, it is from Sedgwick's excellent Algorithms in Java (q 3.54)

Given a link to a node in a singly linked list that contains no null links (i.e. each node either links to itself or another node in the list) determine the number of different nodes without modifying any of the nodes and using no more than constant memory space.

How do you do it? scan through the list once using the hare and tortoise algorithm to work out whether it is circular in any way, and then scan through again to work out where the list becomes circular, then scan through again counting the number of nodes to this position? sounds a bit brute-force to me, I guess there is much more elegant solution.

A: 

just remenber where have you been and if you came at same node it is over.

Try storing entries in binary tree and you have O(N*log(N)) time and O(N) space comlexity

EDIT

You can use Log(N) space comlexity if you do not store every but in exponetial order link. That mean that you store 1st, 2nd, 4th, 8th, 16th and then if you get hit you have to continue from that point. Time comlexity for this one is N*Log(n)^2

ralu
but you can only use constant space
Tom
log(N) is almost constant space 100 entries should be enough for every disk/ram in world :D
ralu
@ralu: Sorry, but `O(log N)` is not close to `O(1)` space. Not by a long shot.
Jason
+1  A: 

Check out this: Puzzle: Loop in a Linked List

Pointer Marking: In practice, linked lists are implemented using C structs with at least a pointer; such a struct in C shall be 4-byte aligned. So the least significant two bits are zeros. While traversing the list, you may ‘mark’ a pointer as traversed by flipping the least significant bit. A second traversal is for clearing these bits.

Nick D
The question states that you should "determine the number of different nodes without modifying any of the nodes." Even if this weren't a requirement, this solutions smells because it relies too much on an implementation detail and is not language agnostic.
Jason
@Jason: Who cares? I'd prefer a *fast* algorithm (which suits my environment) to one that works in more languages. I'm not saying that this answer describes a fast algorithm, just that in general, performance of an algorithm is more important than portability.
Artelius
@Jason, yes it modifies temporary the nodes. Anyway, I know it's not the best solution but I think it's an interesting one.
Nick D
Yes. we used those bottom two bits to implement a deferred load on demand pointers! but that's another story.
Tony Lambert
+6  A: 

The tortoise and hare algorithm can give you both the cycle length and the number of nodes before the cycle begins (λ and μ respectively).

Artelius
Haha, I was in the middle of devising an elaborate answer based on my insight that the number of steps it would take for a tortoise and hare to meet gives information about the cycle length, when I should've just looked it up.
Joren
Me too. :( Google is my friend, Google is my friend, Google is my friend...
TonyOssa
+1. But what is the time complexity of your algorithm? Find cycle O(lambda + u), find cycle length O(lambda), find neck length O(lambda * u). Overall it is still O(N^2) assuming N = min(lambda,u). Is there a better way than quadratic?
Akusete
@Akusete: What? The algorithm gives you λ and μ in O(λ+μ) time, and the answer is λ+μ.
Artelius
+1  A: 

The most elegant solution is Floyd's cycle-finding algorithm: http://en.wikipedia.org/wiki/Cycle%5Fdetection#Tortoise%5Fand%5Fhare

It runs in O(N) time, and only constant amount of memory is required.

Igor ostrovsky