Remove nth node from last position in linked list

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
0
down vote
favorite
Description:
Given a linked list, remove the nth node from the end of list and return its head.
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes
1->2->3->5.
Note:
Given n will always be valid.
Try to do this in one pass.
Code:
class Solution
public ListNode removeNthFromEnd(ListNode head, int n)
int total = 0;
ListNode current = head;
while (current != null)
total++;
current = current.next;
// current must be null here
// 1 based index
int indexToRemove = total - n + 1;
if (indexToRemove < 0)
return null;
if (1 == total && n == 1)
return null;
if (indexToRemove == 1)
return head.next;
current = head;
ListNode prev = null;
for (int i = 0; i < indexToRemove - 1; i++)
prev = current;
current = current.next;
// i > indexToRemove
if (current == null) // last
prev.next = null;
else
prev.next = current.next;
return head;
Questions:
I managed to run the code and pass all the tests but I still feel confused while dealing with off-by-one errors and NullPointerException. The question felt quite easy at first but implementation took a lot of time because of above two errors and correcting them, it was like I was shooting in the dark.
I still feel I have written a lot of extra code which could have been avoided.
What mental model or basic rules I can learn to visualise or understand program states and avoid such errors?
java algorithm programming-challenge linked-list interview-questions
add a comment |Â
up vote
0
down vote
favorite
Description:
Given a linked list, remove the nth node from the end of list and return its head.
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes
1->2->3->5.
Note:
Given n will always be valid.
Try to do this in one pass.
Code:
class Solution
public ListNode removeNthFromEnd(ListNode head, int n)
int total = 0;
ListNode current = head;
while (current != null)
total++;
current = current.next;
// current must be null here
// 1 based index
int indexToRemove = total - n + 1;
if (indexToRemove < 0)
return null;
if (1 == total && n == 1)
return null;
if (indexToRemove == 1)
return head.next;
current = head;
ListNode prev = null;
for (int i = 0; i < indexToRemove - 1; i++)
prev = current;
current = current.next;
// i > indexToRemove
if (current == null) // last
prev.next = null;
else
prev.next = current.next;
return head;
Questions:
I managed to run the code and pass all the tests but I still feel confused while dealing with off-by-one errors and NullPointerException. The question felt quite easy at first but implementation took a lot of time because of above two errors and correcting them, it was like I was shooting in the dark.
I still feel I have written a lot of extra code which could have been avoided.
What mental model or basic rules I can learn to visualise or understand program states and avoid such errors?
java algorithm programming-challenge linked-list interview-questions
1
Just to clarify: Do you still get off-by-one errors and NullPointerExceptions, or was that only during development of this code?
â Simon Forsbergâ¦
Apr 7 at 17:54
@SimonForsberg no, its perfectly working code. I was talking about development and I can't understand by this post is down voted?
â CodeYogi
Apr 7 at 18:01
2
@CodeYogi Probably because someone thought that you still have those problems. Can you edit and clarify?
â Simon Forsbergâ¦
Apr 7 at 18:06
Do you only want answers to your, rather vague, questions or a general review? Expressing my mental model in words is harder than saying what I would do different in the code.
â bbnkttp
Apr 7 at 20:00
1
@bbnkttp I am sure that many of the readers would find it very helpful if they find good answers to the questions above, feel free to add more advice. You can try at least.
â CodeYogi
Apr 7 at 20:04
add a comment |Â
up vote
0
down vote
favorite
up vote
0
down vote
favorite
Description:
Given a linked list, remove the nth node from the end of list and return its head.
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes
1->2->3->5.
Note:
Given n will always be valid.
Try to do this in one pass.
Code:
class Solution
public ListNode removeNthFromEnd(ListNode head, int n)
int total = 0;
ListNode current = head;
while (current != null)
total++;
current = current.next;
// current must be null here
// 1 based index
int indexToRemove = total - n + 1;
if (indexToRemove < 0)
return null;
if (1 == total && n == 1)
return null;
if (indexToRemove == 1)
return head.next;
current = head;
ListNode prev = null;
for (int i = 0; i < indexToRemove - 1; i++)
prev = current;
current = current.next;
// i > indexToRemove
if (current == null) // last
prev.next = null;
else
prev.next = current.next;
return head;
Questions:
I managed to run the code and pass all the tests but I still feel confused while dealing with off-by-one errors and NullPointerException. The question felt quite easy at first but implementation took a lot of time because of above two errors and correcting them, it was like I was shooting in the dark.
I still feel I have written a lot of extra code which could have been avoided.
What mental model or basic rules I can learn to visualise or understand program states and avoid such errors?
java algorithm programming-challenge linked-list interview-questions
Description:
Given a linked list, remove the nth node from the end of list and return its head.
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes
1->2->3->5.
Note:
Given n will always be valid.
Try to do this in one pass.
Code:
class Solution
public ListNode removeNthFromEnd(ListNode head, int n)
int total = 0;
ListNode current = head;
while (current != null)
total++;
current = current.next;
// current must be null here
// 1 based index
int indexToRemove = total - n + 1;
if (indexToRemove < 0)
return null;
if (1 == total && n == 1)
return null;
if (indexToRemove == 1)
return head.next;
current = head;
ListNode prev = null;
for (int i = 0; i < indexToRemove - 1; i++)
prev = current;
current = current.next;
// i > indexToRemove
if (current == null) // last
prev.next = null;
else
prev.next = current.next;
return head;
Questions:
I managed to run the code and pass all the tests but I still feel confused while dealing with off-by-one errors and NullPointerException. The question felt quite easy at first but implementation took a lot of time because of above two errors and correcting them, it was like I was shooting in the dark.
I still feel I have written a lot of extra code which could have been avoided.
What mental model or basic rules I can learn to visualise or understand program states and avoid such errors?
java algorithm programming-challenge linked-list interview-questions
edited Apr 7 at 20:01
asked Apr 7 at 17:38
CodeYogi
2,00432061
2,00432061
1
Just to clarify: Do you still get off-by-one errors and NullPointerExceptions, or was that only during development of this code?
â Simon Forsbergâ¦
Apr 7 at 17:54
@SimonForsberg no, its perfectly working code. I was talking about development and I can't understand by this post is down voted?
â CodeYogi
Apr 7 at 18:01
2
@CodeYogi Probably because someone thought that you still have those problems. Can you edit and clarify?
â Simon Forsbergâ¦
Apr 7 at 18:06
Do you only want answers to your, rather vague, questions or a general review? Expressing my mental model in words is harder than saying what I would do different in the code.
â bbnkttp
Apr 7 at 20:00
1
@bbnkttp I am sure that many of the readers would find it very helpful if they find good answers to the questions above, feel free to add more advice. You can try at least.
â CodeYogi
Apr 7 at 20:04
add a comment |Â
1
Just to clarify: Do you still get off-by-one errors and NullPointerExceptions, or was that only during development of this code?
â Simon Forsbergâ¦
Apr 7 at 17:54
@SimonForsberg no, its perfectly working code. I was talking about development and I can't understand by this post is down voted?
â CodeYogi
Apr 7 at 18:01
2
@CodeYogi Probably because someone thought that you still have those problems. Can you edit and clarify?
â Simon Forsbergâ¦
Apr 7 at 18:06
Do you only want answers to your, rather vague, questions or a general review? Expressing my mental model in words is harder than saying what I would do different in the code.
â bbnkttp
Apr 7 at 20:00
1
@bbnkttp I am sure that many of the readers would find it very helpful if they find good answers to the questions above, feel free to add more advice. You can try at least.
â CodeYogi
Apr 7 at 20:04
1
1
Just to clarify: Do you still get off-by-one errors and NullPointerExceptions, or was that only during development of this code?
â Simon Forsbergâ¦
Apr 7 at 17:54
Just to clarify: Do you still get off-by-one errors and NullPointerExceptions, or was that only during development of this code?
â Simon Forsbergâ¦
Apr 7 at 17:54
@SimonForsberg no, its perfectly working code. I was talking about development and I can't understand by this post is down voted?
â CodeYogi
Apr 7 at 18:01
@SimonForsberg no, its perfectly working code. I was talking about development and I can't understand by this post is down voted?
â CodeYogi
Apr 7 at 18:01
2
2
@CodeYogi Probably because someone thought that you still have those problems. Can you edit and clarify?
â Simon Forsbergâ¦
Apr 7 at 18:06
@CodeYogi Probably because someone thought that you still have those problems. Can you edit and clarify?
â Simon Forsbergâ¦
Apr 7 at 18:06
Do you only want answers to your, rather vague, questions or a general review? Expressing my mental model in words is harder than saying what I would do different in the code.
â bbnkttp
Apr 7 at 20:00
Do you only want answers to your, rather vague, questions or a general review? Expressing my mental model in words is harder than saying what I would do different in the code.
â bbnkttp
Apr 7 at 20:00
1
1
@bbnkttp I am sure that many of the readers would find it very helpful if they find good answers to the questions above, feel free to add more advice. You can try at least.
â CodeYogi
Apr 7 at 20:04
@bbnkttp I am sure that many of the readers would find it very helpful if they find good answers to the questions above, feel free to add more advice. You can try at least.
â CodeYogi
Apr 7 at 20:04
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
3
down vote
accepted
You failed to solve the "try to do this in one pass" part, as you iterate through the list once to find the total size and a second time to find the nth element from the start.
The algorithmic idea is, to use two pointers into the list:
- Initialize poiner1 to head, advance n times (if n is the distance from the tail you seek)
- Then, initialize pointer2 to head, advance both pointers, until pointer1 is null, i.e. reached the end of the list.
- Now, pointer2 should point to the end-nth element
Removal as usual.
add a comment |Â
up vote
1
down vote
I will structure my answer in the following way:
- General (java) nitpicks
- Direct remarks about your implementation
- Improvements
- How it could look like
General nitpicks:
First thing you always should do is check your arguments for any invalid input. What if
head==null? What ifn<0? Make the assumptions on your arguments explicit and get that out of the way immediately, it will make it easier to think about the rest, because these edge cases are eliminated.Make your method static if there are no instance (non-static) fields you are using.
There are several things going on here that could be extracted in dedicated methods, which would improve readability and make it possible for reuse. Candidates: getting the length of linked list and removing some element in linked list by index.
Never reuse any variables, it costs nothing to create a new one and it makes it clearer. Even if the two variables have the same purpose, like walking over a linked list. It just adds mental load, because potentially some state could be shared between them if you forget to initialize it properly the second time.
Implementation remarks:
I will assume that n being valid means 1 < n <= total+1 and that head!=null.
If head==null or invalid n everything breaks.
I will give my remarks by going over the code piece by piece
- Find length of linked list.
- Use the previous length to flip
nto get an index, still with
1-indexing, from the front. you create three branches and return early. The second is redundant, because
n==1&&total==1 => indexToRemove==1 && head!=null && head.next==null.Isn't indexToRemove 1-indexed? Doesn't that mean it is at least 1?
Are you protecting against invalidnhere? You only protect againstn>total+1.you walk over the list till you hit the node that should be removed,
remembering the previous node because you have to change the pointer
there.- As long as
n>=0you are guaranteed that you will not
have a NPE withcurrent.next, because of the first loop.
This is a not very clear to see though, because you count the length in the first loop and then do some arithmetic operations on this length and some argument and then you try to loop over the list again with the outcome. Some better ways are make it clear when calculating indexToReturn by adding amax(.., total+1)or usetotalto loop the second time and break when you are at the right node. - After the second loop
i>indexToRemove -1so since you increment by 1 we havei==indexToRemove. What you wrote in the comment is wrong. This makes the first if block unnecessary and dead code. - Now you are at the node you want to delete, so you set the pointer of the previous node to null and you are done.
Improvements:
All the things I said under general nitpicks.
Change the unnatural 1-indexing into the super common 0-indexing. This will improve readability and decrease the chance of off-by-one errors.
How I would do it:
I choose to check for n that is too big in both methods because I like self-contained methods. In principle I could remove it from removeItemFromEnd and remove the call to size to save time. It will not help the time complexity and it makes the methods more coupled, so here I pick structure over speed.
class Solution
public int size(ListNode head)
int total = 0;
ListNode current = head;
while (current != null)
total++;
return total;
public removeItem(ListNode head, int index)
if (index < 0)
throw new IndexOutOfBoundsException("Index " + index + " is too small.");
if (head == null)
return null;
if (index == 0)
return head.next;
ListNode current = head;
ListNode prev = null;
for (int i = 0; i < index && current != null; i++)
prev = current;
current = current.next;
if (current == null)
throw new IndexOutOfBoundsException("Index " + index + " is too big.");
prev.next = current.next;
return head;
public ListNode removeItemFromEnd(ListNode head, int n)
if (head == null)
return null;
if (n<1)
throw new IndexOutOfBoundsException("Index " + n + " is too small.");
int size = size(head);
if (n > size)
throw new IndexOutOfBoundsException("Index " + n " is too big.");
return removeItem(head, size - n); // size - n is zero indexed
Great advice but there is a small bug in your code,return removeItem(head, size - zero_indexed_n);
â CodeYogi
Apr 7 at 22:25
Fixed the error and removedzero_indexed_ncompletely. I will try to answer your questions directly tomorrow.
â bbnkttp
Apr 7 at 22:33
add a comment |Â
up vote
0
down vote
The part below seems unnecessary and incorrect to me:
if (indexToRemove < 0)
return null;
If I get it correctly, you say n is always valid. Based on the example, I understand it means n is not less than 1 and not greater than the list's length. Hence the indexToRemove can't be negative and the whole if() is void.
Anyway, even if you consider invalid n, you can't remove a non-existing item, but the head of the list stays untouched in such case, so I'd expect return head; here. However, then the condition should be indexToRemove <= 0.
Also the next conditional branch is unnecessary:
if (1 == total && n == 1)
return null;
because that case is perfectly handled by the statement following it:
if (indexToRemove == 1)
return head.next;
The comment you left after the last loop seems misleading:
for (int i = 0; i < indexToRemove - 1; i++)
prev = current;
current = current.next;
// i > indexToRemove
The loop loops as long as the condition i < indexToRemove - 1 is satisfied.
As i grows by one on each iteration, the condition gets broken when i becomes equal indexToRemove - 1, hence it is less than indexToRemove, opposite to what the comment says!
Finally, this part is also useless:
if (current == null) // last
prev.next = null;
else ...
If n == 1 you want to remove the last item from the list.
Actually, indexToRemove is set to total - n + 1 which results in total, i.e. an index of the last item.
However, the loop's invariant is:
pre:
currentis a(i+1)-st item
post:currentis a(i+2)-nd item
(Verify: on entry, i == 0 and current == head.)
So when the loop terminates at i = indexToRemove - 1 after i++, the last value of i processed was indexToRemove - 2, and current was set to the item at position i+2, i.e. indexToRemove. As a result it can't be null!
All you need to do after the loop is:
prev.next = current.next;
return head;
(with current.next being null iff n==1).
add a comment |Â
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
accepted
You failed to solve the "try to do this in one pass" part, as you iterate through the list once to find the total size and a second time to find the nth element from the start.
The algorithmic idea is, to use two pointers into the list:
- Initialize poiner1 to head, advance n times (if n is the distance from the tail you seek)
- Then, initialize pointer2 to head, advance both pointers, until pointer1 is null, i.e. reached the end of the list.
- Now, pointer2 should point to the end-nth element
Removal as usual.
add a comment |Â
up vote
3
down vote
accepted
You failed to solve the "try to do this in one pass" part, as you iterate through the list once to find the total size and a second time to find the nth element from the start.
The algorithmic idea is, to use two pointers into the list:
- Initialize poiner1 to head, advance n times (if n is the distance from the tail you seek)
- Then, initialize pointer2 to head, advance both pointers, until pointer1 is null, i.e. reached the end of the list.
- Now, pointer2 should point to the end-nth element
Removal as usual.
add a comment |Â
up vote
3
down vote
accepted
up vote
3
down vote
accepted
You failed to solve the "try to do this in one pass" part, as you iterate through the list once to find the total size and a second time to find the nth element from the start.
The algorithmic idea is, to use two pointers into the list:
- Initialize poiner1 to head, advance n times (if n is the distance from the tail you seek)
- Then, initialize pointer2 to head, advance both pointers, until pointer1 is null, i.e. reached the end of the list.
- Now, pointer2 should point to the end-nth element
Removal as usual.
You failed to solve the "try to do this in one pass" part, as you iterate through the list once to find the total size and a second time to find the nth element from the start.
The algorithmic idea is, to use two pointers into the list:
- Initialize poiner1 to head, advance n times (if n is the distance from the tail you seek)
- Then, initialize pointer2 to head, advance both pointers, until pointer1 is null, i.e. reached the end of the list.
- Now, pointer2 should point to the end-nth element
Removal as usual.
answered Apr 9 at 6:10
mtj
2,675212
2,675212
add a comment |Â
add a comment |Â
up vote
1
down vote
I will structure my answer in the following way:
- General (java) nitpicks
- Direct remarks about your implementation
- Improvements
- How it could look like
General nitpicks:
First thing you always should do is check your arguments for any invalid input. What if
head==null? What ifn<0? Make the assumptions on your arguments explicit and get that out of the way immediately, it will make it easier to think about the rest, because these edge cases are eliminated.Make your method static if there are no instance (non-static) fields you are using.
There are several things going on here that could be extracted in dedicated methods, which would improve readability and make it possible for reuse. Candidates: getting the length of linked list and removing some element in linked list by index.
Never reuse any variables, it costs nothing to create a new one and it makes it clearer. Even if the two variables have the same purpose, like walking over a linked list. It just adds mental load, because potentially some state could be shared between them if you forget to initialize it properly the second time.
Implementation remarks:
I will assume that n being valid means 1 < n <= total+1 and that head!=null.
If head==null or invalid n everything breaks.
I will give my remarks by going over the code piece by piece
- Find length of linked list.
- Use the previous length to flip
nto get an index, still with
1-indexing, from the front. you create three branches and return early. The second is redundant, because
n==1&&total==1 => indexToRemove==1 && head!=null && head.next==null.Isn't indexToRemove 1-indexed? Doesn't that mean it is at least 1?
Are you protecting against invalidnhere? You only protect againstn>total+1.you walk over the list till you hit the node that should be removed,
remembering the previous node because you have to change the pointer
there.- As long as
n>=0you are guaranteed that you will not
have a NPE withcurrent.next, because of the first loop.
This is a not very clear to see though, because you count the length in the first loop and then do some arithmetic operations on this length and some argument and then you try to loop over the list again with the outcome. Some better ways are make it clear when calculating indexToReturn by adding amax(.., total+1)or usetotalto loop the second time and break when you are at the right node. - After the second loop
i>indexToRemove -1so since you increment by 1 we havei==indexToRemove. What you wrote in the comment is wrong. This makes the first if block unnecessary and dead code. - Now you are at the node you want to delete, so you set the pointer of the previous node to null and you are done.
Improvements:
All the things I said under general nitpicks.
Change the unnatural 1-indexing into the super common 0-indexing. This will improve readability and decrease the chance of off-by-one errors.
How I would do it:
I choose to check for n that is too big in both methods because I like self-contained methods. In principle I could remove it from removeItemFromEnd and remove the call to size to save time. It will not help the time complexity and it makes the methods more coupled, so here I pick structure over speed.
class Solution
public int size(ListNode head)
int total = 0;
ListNode current = head;
while (current != null)
total++;
return total;
public removeItem(ListNode head, int index)
if (index < 0)
throw new IndexOutOfBoundsException("Index " + index + " is too small.");
if (head == null)
return null;
if (index == 0)
return head.next;
ListNode current = head;
ListNode prev = null;
for (int i = 0; i < index && current != null; i++)
prev = current;
current = current.next;
if (current == null)
throw new IndexOutOfBoundsException("Index " + index + " is too big.");
prev.next = current.next;
return head;
public ListNode removeItemFromEnd(ListNode head, int n)
if (head == null)
return null;
if (n<1)
throw new IndexOutOfBoundsException("Index " + n + " is too small.");
int size = size(head);
if (n > size)
throw new IndexOutOfBoundsException("Index " + n " is too big.");
return removeItem(head, size - n); // size - n is zero indexed
Great advice but there is a small bug in your code,return removeItem(head, size - zero_indexed_n);
â CodeYogi
Apr 7 at 22:25
Fixed the error and removedzero_indexed_ncompletely. I will try to answer your questions directly tomorrow.
â bbnkttp
Apr 7 at 22:33
add a comment |Â
up vote
1
down vote
I will structure my answer in the following way:
- General (java) nitpicks
- Direct remarks about your implementation
- Improvements
- How it could look like
General nitpicks:
First thing you always should do is check your arguments for any invalid input. What if
head==null? What ifn<0? Make the assumptions on your arguments explicit and get that out of the way immediately, it will make it easier to think about the rest, because these edge cases are eliminated.Make your method static if there are no instance (non-static) fields you are using.
There are several things going on here that could be extracted in dedicated methods, which would improve readability and make it possible for reuse. Candidates: getting the length of linked list and removing some element in linked list by index.
Never reuse any variables, it costs nothing to create a new one and it makes it clearer. Even if the two variables have the same purpose, like walking over a linked list. It just adds mental load, because potentially some state could be shared between them if you forget to initialize it properly the second time.
Implementation remarks:
I will assume that n being valid means 1 < n <= total+1 and that head!=null.
If head==null or invalid n everything breaks.
I will give my remarks by going over the code piece by piece
- Find length of linked list.
- Use the previous length to flip
nto get an index, still with
1-indexing, from the front. you create three branches and return early. The second is redundant, because
n==1&&total==1 => indexToRemove==1 && head!=null && head.next==null.Isn't indexToRemove 1-indexed? Doesn't that mean it is at least 1?
Are you protecting against invalidnhere? You only protect againstn>total+1.you walk over the list till you hit the node that should be removed,
remembering the previous node because you have to change the pointer
there.- As long as
n>=0you are guaranteed that you will not
have a NPE withcurrent.next, because of the first loop.
This is a not very clear to see though, because you count the length in the first loop and then do some arithmetic operations on this length and some argument and then you try to loop over the list again with the outcome. Some better ways are make it clear when calculating indexToReturn by adding amax(.., total+1)or usetotalto loop the second time and break when you are at the right node. - After the second loop
i>indexToRemove -1so since you increment by 1 we havei==indexToRemove. What you wrote in the comment is wrong. This makes the first if block unnecessary and dead code. - Now you are at the node you want to delete, so you set the pointer of the previous node to null and you are done.
Improvements:
All the things I said under general nitpicks.
Change the unnatural 1-indexing into the super common 0-indexing. This will improve readability and decrease the chance of off-by-one errors.
How I would do it:
I choose to check for n that is too big in both methods because I like self-contained methods. In principle I could remove it from removeItemFromEnd and remove the call to size to save time. It will not help the time complexity and it makes the methods more coupled, so here I pick structure over speed.
class Solution
public int size(ListNode head)
int total = 0;
ListNode current = head;
while (current != null)
total++;
return total;
public removeItem(ListNode head, int index)
if (index < 0)
throw new IndexOutOfBoundsException("Index " + index + " is too small.");
if (head == null)
return null;
if (index == 0)
return head.next;
ListNode current = head;
ListNode prev = null;
for (int i = 0; i < index && current != null; i++)
prev = current;
current = current.next;
if (current == null)
throw new IndexOutOfBoundsException("Index " + index + " is too big.");
prev.next = current.next;
return head;
public ListNode removeItemFromEnd(ListNode head, int n)
if (head == null)
return null;
if (n<1)
throw new IndexOutOfBoundsException("Index " + n + " is too small.");
int size = size(head);
if (n > size)
throw new IndexOutOfBoundsException("Index " + n " is too big.");
return removeItem(head, size - n); // size - n is zero indexed
Great advice but there is a small bug in your code,return removeItem(head, size - zero_indexed_n);
â CodeYogi
Apr 7 at 22:25
Fixed the error and removedzero_indexed_ncompletely. I will try to answer your questions directly tomorrow.
â bbnkttp
Apr 7 at 22:33
add a comment |Â
up vote
1
down vote
up vote
1
down vote
I will structure my answer in the following way:
- General (java) nitpicks
- Direct remarks about your implementation
- Improvements
- How it could look like
General nitpicks:
First thing you always should do is check your arguments for any invalid input. What if
head==null? What ifn<0? Make the assumptions on your arguments explicit and get that out of the way immediately, it will make it easier to think about the rest, because these edge cases are eliminated.Make your method static if there are no instance (non-static) fields you are using.
There are several things going on here that could be extracted in dedicated methods, which would improve readability and make it possible for reuse. Candidates: getting the length of linked list and removing some element in linked list by index.
Never reuse any variables, it costs nothing to create a new one and it makes it clearer. Even if the two variables have the same purpose, like walking over a linked list. It just adds mental load, because potentially some state could be shared between them if you forget to initialize it properly the second time.
Implementation remarks:
I will assume that n being valid means 1 < n <= total+1 and that head!=null.
If head==null or invalid n everything breaks.
I will give my remarks by going over the code piece by piece
- Find length of linked list.
- Use the previous length to flip
nto get an index, still with
1-indexing, from the front. you create three branches and return early. The second is redundant, because
n==1&&total==1 => indexToRemove==1 && head!=null && head.next==null.Isn't indexToRemove 1-indexed? Doesn't that mean it is at least 1?
Are you protecting against invalidnhere? You only protect againstn>total+1.you walk over the list till you hit the node that should be removed,
remembering the previous node because you have to change the pointer
there.- As long as
n>=0you are guaranteed that you will not
have a NPE withcurrent.next, because of the first loop.
This is a not very clear to see though, because you count the length in the first loop and then do some arithmetic operations on this length and some argument and then you try to loop over the list again with the outcome. Some better ways are make it clear when calculating indexToReturn by adding amax(.., total+1)or usetotalto loop the second time and break when you are at the right node. - After the second loop
i>indexToRemove -1so since you increment by 1 we havei==indexToRemove. What you wrote in the comment is wrong. This makes the first if block unnecessary and dead code. - Now you are at the node you want to delete, so you set the pointer of the previous node to null and you are done.
Improvements:
All the things I said under general nitpicks.
Change the unnatural 1-indexing into the super common 0-indexing. This will improve readability and decrease the chance of off-by-one errors.
How I would do it:
I choose to check for n that is too big in both methods because I like self-contained methods. In principle I could remove it from removeItemFromEnd and remove the call to size to save time. It will not help the time complexity and it makes the methods more coupled, so here I pick structure over speed.
class Solution
public int size(ListNode head)
int total = 0;
ListNode current = head;
while (current != null)
total++;
return total;
public removeItem(ListNode head, int index)
if (index < 0)
throw new IndexOutOfBoundsException("Index " + index + " is too small.");
if (head == null)
return null;
if (index == 0)
return head.next;
ListNode current = head;
ListNode prev = null;
for (int i = 0; i < index && current != null; i++)
prev = current;
current = current.next;
if (current == null)
throw new IndexOutOfBoundsException("Index " + index + " is too big.");
prev.next = current.next;
return head;
public ListNode removeItemFromEnd(ListNode head, int n)
if (head == null)
return null;
if (n<1)
throw new IndexOutOfBoundsException("Index " + n + " is too small.");
int size = size(head);
if (n > size)
throw new IndexOutOfBoundsException("Index " + n " is too big.");
return removeItem(head, size - n); // size - n is zero indexed
I will structure my answer in the following way:
- General (java) nitpicks
- Direct remarks about your implementation
- Improvements
- How it could look like
General nitpicks:
First thing you always should do is check your arguments for any invalid input. What if
head==null? What ifn<0? Make the assumptions on your arguments explicit and get that out of the way immediately, it will make it easier to think about the rest, because these edge cases are eliminated.Make your method static if there are no instance (non-static) fields you are using.
There are several things going on here that could be extracted in dedicated methods, which would improve readability and make it possible for reuse. Candidates: getting the length of linked list and removing some element in linked list by index.
Never reuse any variables, it costs nothing to create a new one and it makes it clearer. Even if the two variables have the same purpose, like walking over a linked list. It just adds mental load, because potentially some state could be shared between them if you forget to initialize it properly the second time.
Implementation remarks:
I will assume that n being valid means 1 < n <= total+1 and that head!=null.
If head==null or invalid n everything breaks.
I will give my remarks by going over the code piece by piece
- Find length of linked list.
- Use the previous length to flip
nto get an index, still with
1-indexing, from the front. you create three branches and return early. The second is redundant, because
n==1&&total==1 => indexToRemove==1 && head!=null && head.next==null.Isn't indexToRemove 1-indexed? Doesn't that mean it is at least 1?
Are you protecting against invalidnhere? You only protect againstn>total+1.you walk over the list till you hit the node that should be removed,
remembering the previous node because you have to change the pointer
there.- As long as
n>=0you are guaranteed that you will not
have a NPE withcurrent.next, because of the first loop.
This is a not very clear to see though, because you count the length in the first loop and then do some arithmetic operations on this length and some argument and then you try to loop over the list again with the outcome. Some better ways are make it clear when calculating indexToReturn by adding amax(.., total+1)or usetotalto loop the second time and break when you are at the right node. - After the second loop
i>indexToRemove -1so since you increment by 1 we havei==indexToRemove. What you wrote in the comment is wrong. This makes the first if block unnecessary and dead code. - Now you are at the node you want to delete, so you set the pointer of the previous node to null and you are done.
Improvements:
All the things I said under general nitpicks.
Change the unnatural 1-indexing into the super common 0-indexing. This will improve readability and decrease the chance of off-by-one errors.
How I would do it:
I choose to check for n that is too big in both methods because I like self-contained methods. In principle I could remove it from removeItemFromEnd and remove the call to size to save time. It will not help the time complexity and it makes the methods more coupled, so here I pick structure over speed.
class Solution
public int size(ListNode head)
int total = 0;
ListNode current = head;
while (current != null)
total++;
return total;
public removeItem(ListNode head, int index)
if (index < 0)
throw new IndexOutOfBoundsException("Index " + index + " is too small.");
if (head == null)
return null;
if (index == 0)
return head.next;
ListNode current = head;
ListNode prev = null;
for (int i = 0; i < index && current != null; i++)
prev = current;
current = current.next;
if (current == null)
throw new IndexOutOfBoundsException("Index " + index + " is too big.");
prev.next = current.next;
return head;
public ListNode removeItemFromEnd(ListNode head, int n)
if (head == null)
return null;
if (n<1)
throw new IndexOutOfBoundsException("Index " + n + " is too small.");
int size = size(head);
if (n > size)
throw new IndexOutOfBoundsException("Index " + n " is too big.");
return removeItem(head, size - n); // size - n is zero indexed
edited Apr 7 at 22:38
answered Apr 7 at 22:02
bbnkttp
29515
29515
Great advice but there is a small bug in your code,return removeItem(head, size - zero_indexed_n);
â CodeYogi
Apr 7 at 22:25
Fixed the error and removedzero_indexed_ncompletely. I will try to answer your questions directly tomorrow.
â bbnkttp
Apr 7 at 22:33
add a comment |Â
Great advice but there is a small bug in your code,return removeItem(head, size - zero_indexed_n);
â CodeYogi
Apr 7 at 22:25
Fixed the error and removedzero_indexed_ncompletely. I will try to answer your questions directly tomorrow.
â bbnkttp
Apr 7 at 22:33
Great advice but there is a small bug in your code,
return removeItem(head, size - zero_indexed_n);â CodeYogi
Apr 7 at 22:25
Great advice but there is a small bug in your code,
return removeItem(head, size - zero_indexed_n);â CodeYogi
Apr 7 at 22:25
Fixed the error and removed
zero_indexed_n completely. I will try to answer your questions directly tomorrow.â bbnkttp
Apr 7 at 22:33
Fixed the error and removed
zero_indexed_n completely. I will try to answer your questions directly tomorrow.â bbnkttp
Apr 7 at 22:33
add a comment |Â
up vote
0
down vote
The part below seems unnecessary and incorrect to me:
if (indexToRemove < 0)
return null;
If I get it correctly, you say n is always valid. Based on the example, I understand it means n is not less than 1 and not greater than the list's length. Hence the indexToRemove can't be negative and the whole if() is void.
Anyway, even if you consider invalid n, you can't remove a non-existing item, but the head of the list stays untouched in such case, so I'd expect return head; here. However, then the condition should be indexToRemove <= 0.
Also the next conditional branch is unnecessary:
if (1 == total && n == 1)
return null;
because that case is perfectly handled by the statement following it:
if (indexToRemove == 1)
return head.next;
The comment you left after the last loop seems misleading:
for (int i = 0; i < indexToRemove - 1; i++)
prev = current;
current = current.next;
// i > indexToRemove
The loop loops as long as the condition i < indexToRemove - 1 is satisfied.
As i grows by one on each iteration, the condition gets broken when i becomes equal indexToRemove - 1, hence it is less than indexToRemove, opposite to what the comment says!
Finally, this part is also useless:
if (current == null) // last
prev.next = null;
else ...
If n == 1 you want to remove the last item from the list.
Actually, indexToRemove is set to total - n + 1 which results in total, i.e. an index of the last item.
However, the loop's invariant is:
pre:
currentis a(i+1)-st item
post:currentis a(i+2)-nd item
(Verify: on entry, i == 0 and current == head.)
So when the loop terminates at i = indexToRemove - 1 after i++, the last value of i processed was indexToRemove - 2, and current was set to the item at position i+2, i.e. indexToRemove. As a result it can't be null!
All you need to do after the loop is:
prev.next = current.next;
return head;
(with current.next being null iff n==1).
add a comment |Â
up vote
0
down vote
The part below seems unnecessary and incorrect to me:
if (indexToRemove < 0)
return null;
If I get it correctly, you say n is always valid. Based on the example, I understand it means n is not less than 1 and not greater than the list's length. Hence the indexToRemove can't be negative and the whole if() is void.
Anyway, even if you consider invalid n, you can't remove a non-existing item, but the head of the list stays untouched in such case, so I'd expect return head; here. However, then the condition should be indexToRemove <= 0.
Also the next conditional branch is unnecessary:
if (1 == total && n == 1)
return null;
because that case is perfectly handled by the statement following it:
if (indexToRemove == 1)
return head.next;
The comment you left after the last loop seems misleading:
for (int i = 0; i < indexToRemove - 1; i++)
prev = current;
current = current.next;
// i > indexToRemove
The loop loops as long as the condition i < indexToRemove - 1 is satisfied.
As i grows by one on each iteration, the condition gets broken when i becomes equal indexToRemove - 1, hence it is less than indexToRemove, opposite to what the comment says!
Finally, this part is also useless:
if (current == null) // last
prev.next = null;
else ...
If n == 1 you want to remove the last item from the list.
Actually, indexToRemove is set to total - n + 1 which results in total, i.e. an index of the last item.
However, the loop's invariant is:
pre:
currentis a(i+1)-st item
post:currentis a(i+2)-nd item
(Verify: on entry, i == 0 and current == head.)
So when the loop terminates at i = indexToRemove - 1 after i++, the last value of i processed was indexToRemove - 2, and current was set to the item at position i+2, i.e. indexToRemove. As a result it can't be null!
All you need to do after the loop is:
prev.next = current.next;
return head;
(with current.next being null iff n==1).
add a comment |Â
up vote
0
down vote
up vote
0
down vote
The part below seems unnecessary and incorrect to me:
if (indexToRemove < 0)
return null;
If I get it correctly, you say n is always valid. Based on the example, I understand it means n is not less than 1 and not greater than the list's length. Hence the indexToRemove can't be negative and the whole if() is void.
Anyway, even if you consider invalid n, you can't remove a non-existing item, but the head of the list stays untouched in such case, so I'd expect return head; here. However, then the condition should be indexToRemove <= 0.
Also the next conditional branch is unnecessary:
if (1 == total && n == 1)
return null;
because that case is perfectly handled by the statement following it:
if (indexToRemove == 1)
return head.next;
The comment you left after the last loop seems misleading:
for (int i = 0; i < indexToRemove - 1; i++)
prev = current;
current = current.next;
// i > indexToRemove
The loop loops as long as the condition i < indexToRemove - 1 is satisfied.
As i grows by one on each iteration, the condition gets broken when i becomes equal indexToRemove - 1, hence it is less than indexToRemove, opposite to what the comment says!
Finally, this part is also useless:
if (current == null) // last
prev.next = null;
else ...
If n == 1 you want to remove the last item from the list.
Actually, indexToRemove is set to total - n + 1 which results in total, i.e. an index of the last item.
However, the loop's invariant is:
pre:
currentis a(i+1)-st item
post:currentis a(i+2)-nd item
(Verify: on entry, i == 0 and current == head.)
So when the loop terminates at i = indexToRemove - 1 after i++, the last value of i processed was indexToRemove - 2, and current was set to the item at position i+2, i.e. indexToRemove. As a result it can't be null!
All you need to do after the loop is:
prev.next = current.next;
return head;
(with current.next being null iff n==1).
The part below seems unnecessary and incorrect to me:
if (indexToRemove < 0)
return null;
If I get it correctly, you say n is always valid. Based on the example, I understand it means n is not less than 1 and not greater than the list's length. Hence the indexToRemove can't be negative and the whole if() is void.
Anyway, even if you consider invalid n, you can't remove a non-existing item, but the head of the list stays untouched in such case, so I'd expect return head; here. However, then the condition should be indexToRemove <= 0.
Also the next conditional branch is unnecessary:
if (1 == total && n == 1)
return null;
because that case is perfectly handled by the statement following it:
if (indexToRemove == 1)
return head.next;
The comment you left after the last loop seems misleading:
for (int i = 0; i < indexToRemove - 1; i++)
prev = current;
current = current.next;
// i > indexToRemove
The loop loops as long as the condition i < indexToRemove - 1 is satisfied.
As i grows by one on each iteration, the condition gets broken when i becomes equal indexToRemove - 1, hence it is less than indexToRemove, opposite to what the comment says!
Finally, this part is also useless:
if (current == null) // last
prev.next = null;
else ...
If n == 1 you want to remove the last item from the list.
Actually, indexToRemove is set to total - n + 1 which results in total, i.e. an index of the last item.
However, the loop's invariant is:
pre:
currentis a(i+1)-st item
post:currentis a(i+2)-nd item
(Verify: on entry, i == 0 and current == head.)
So when the loop terminates at i = indexToRemove - 1 after i++, the last value of i processed was indexToRemove - 2, and current was set to the item at position i+2, i.e. indexToRemove. As a result it can't be null!
All you need to do after the loop is:
prev.next = current.next;
return head;
(with current.next being null iff n==1).
edited Apr 7 at 20:46
answered Apr 7 at 20:37
CiaPan
1,1371311
1,1371311
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f191484%2fremove-nth-node-from-last-position-in-linked-list%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
Just to clarify: Do you still get off-by-one errors and NullPointerExceptions, or was that only during development of this code?
â Simon Forsbergâ¦
Apr 7 at 17:54
@SimonForsberg no, its perfectly working code. I was talking about development and I can't understand by this post is down voted?
â CodeYogi
Apr 7 at 18:01
2
@CodeYogi Probably because someone thought that you still have those problems. Can you edit and clarify?
â Simon Forsbergâ¦
Apr 7 at 18:06
Do you only want answers to your, rather vague, questions or a general review? Expressing my mental model in words is harder than saying what I would do different in the code.
â bbnkttp
Apr 7 at 20:00
1
@bbnkttp I am sure that many of the readers would find it very helpful if they find good answers to the questions above, feel free to add more advice. You can try at least.
â CodeYogi
Apr 7 at 20:04