Given a linked list, remove the nth node from the end of list and return its head.
For example, given linked list 1->2->3->4->5 and n = 2, the result is 1->2->3->5.
Java Solution 1 – Naive Two Passes
Calculate the length first, and then remove the nth from the beginning.
public ListNode removeNthFromEnd(ListNode head, int n) { if(head == null) return null; //get length of list ListNode p = head; int len = 0; while(p != null){ len++; p = p.next; } //if remove first node int fromStart = len-n+1; if(fromStart==1) return head.next; //remove non-first node p = head; int i=0; while(p!=null){ i++; if(i==fromStart-1){ p.next = p.next.next; } p=p.next; } return head; } |
Java Solution 2 – One Pass
Use fast and slow pointers. The fast pointer is n steps ahead of the slow pointer. When the fast reaches the end, the slow pointer points at the previous element of the target element.
public ListNode removeNthFromEnd(ListNode head, int n) { if(head == null) return null; ListNode fast = head; ListNode slow = head; for(int i=0; i<n; i++){ fast = fast.next; } //if remove the first node if(fast == null){ head = head.next; return head; } while(fast.next != null){ fast = fast.next; slow = slow.next; } slow.next = slow.next.next; return head; } |
=Use fast and slow pointers.
i would not call fast/slow, they have both same speed. just have distance between.
—
Covers some more cases:
Node removeNthFromLast(Node root, int n)
{
Node f = root; /* f for forward */
for (int i = 1 ; i < n && f != null ; i++, f = f.next);
if (f == null) return root; /* nth not exists - can also throw exception */
Node helper = new Node(0);
helper.next = root;
Node b = helper; /* b for backward */
/* Distance between b and f is n. */
for ( ; f.next != null ; f = f.next, b = b.next);
b.next = b.next.next; /* The actual deletion */
return helper.next;
}
Execution example:
1->2->3, 2
n 2
f 1 2
i 1 2
helper 0
b 0 1
f 2 3
f.next null
0->1->3
res: 1->3
For the solution 1.
I think calculating length can be improved like below.
ListNode fast = head;
int len = 0;
while(fast!=null) {
if(fast.next==null) {
len++;
break;
}
len += 2;
fast = fast.next.next;
}
In solution 2,
//if remove the first node
if(fast == null){
head = head.next;
return head;
}
fast can be null, in cases where N is more than then length of list. Why remove first element in this case?
yes just add fast!=null with i<b and the code will run fine.
Treat it like a circle, but I think two pointers is better.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if (head == null) return head;
ListNode p = head;
int len = 0;
while (p != null) {
len++;
if (p.next != null) {
p = p.next;
} else {
break;
}
}
// delete head case
if (n == len) return head.next;
ListNode end = p;
p.next = head;
int k = len – n;
while (k > 0) {
k–;
p = p.next;
}
end.next = null;
// delete tail case
if (n == 1) {
p.next = null;
} else {
p.next = p.next.next;
}
return head;
}
}
we have to check for null in the for loop. Otherwise it’s going to give us NullPointerException
Both solutions have the same number of walk. There are not much difference