The following function is trying to find the nth
to last element of a singly linked list.
For example:
If the elements are
my approach, what i think is simple and has time complexity O(n).
Step 1: First get the count of number of nodes. Run a for loop starting from first node to the last node
Step 2: Once you have the count, apply simple math, for example if we have find 7th node to the last node and the count of all nodes is 12, then (count - index)- 1 will give some kth node, upto which you will have to traverse and it will be the nth node to the last node. In this case (12 -7)-1 = 4
If the elements are 8->10->5->7->2->1->5->4->10->10 then the result is 7th to last node is 7, which is nothing but 4th node from the beginning.
Nobody here noticed that Jonathan's version will throw a NullPinterException if the n is larger that the length of LinkedList. Here is my version:
public Node nth(int n){
if(head == null || n < 1) return null;
Node n1 = head;
Node n2 = head;
for(int i = 1; i < n; i++){
if(n1.next == null) return null;
n1 = n1.next;
}
while (n1.next != null){
n1 = n1.next;
n2 = n2.next;
}
return n2;
}
I just make little change here: when node n1 step forward, instead of checking if n1 is null, I check weather n1.next is null, or else in while loop n1.next will throw a NullPinterException.
//this is the recursive solution
//initial call
find(HEAD,k);
// main function
void find(struct link *temp,int k)
{
if( temp->next != NULL)
find( temp->next, k);
if((c++) == k) // c is initially declared as 1 and k is the node to find from last.
cout<<temp->num<<' ';
}
There are lots of answers here already, but they all walk the list twice (either sequentially or in parallel) or use a lot of extra storage.
You can do this while walking the list just once (plus a little bit) using constant extra space:
Node *getNthFromEnd(Node *list, int n) {
if (list == null || n<1) {
return null; //no such element
}
Node *mark1 = list, *mark2 = list, *markend = list;
int pos1 = 0, pos2 = 0, posend = 0;
while (markend!=null) {
if ((posend-pos2)>=(n-1)) {
mark1=mark2;
pos1=pos2;
mark2=markend;
pos2=posend;
}
markend=markend->next;
++posend;
}
if (posend<n) {
return null; //not enough elements in the list
}
//mark1 and mark2 are n-1 elements apart, and the end is at least
//1 element after mark2, so mark1 is at least n elements from the end
while((posend - pos1) > n) {
mark1 = mark1->next;
++pos1;
}
return mark1;
}
This version uses 2 extra pointers does less than N+n
traversals, where N
is the length of the list and n
is the argument.
If you use M
extra pointers, you can get that down to N+ceil(n/(M-1))
(and you should store them in a circular buffer)