Linked List · 35 of 36
Program for nth node from the end of a Linked List
Find the box that sits n places from the end of a chain, by sending one finger n steps ahead and then walking both fingers together.
- Simple way
- time O(n)
room O(1) - Clever way
- time O(n)
room O(1)
The problem, simply
You get a linked list: a chain of boxes, each with a number and an arrow to the next box. You also get a number n.
Give back the box that is n places from the end. With n = 1 that is the last box, with n = 2 the one before it, and so on. If the chain is shorter than n, there is no such box, so give back null.
The catch: you can only walk forward from the head. You do not know how long the chain is until you reach the end.
A story to remember it
Picture it
Six boxes. With n = 2 we want the box 2 places from the end, which holds 3. The answer box is green.
- answer
Examples
A normal case
- In
5 -> 9 -> 2 -> 7 -> 3 -> 8, n = 2- Out
3
Counting from the end: 8 is 1st, 3 is 2nd.
n is the whole length
- In
7 -> 8 -> 9, n = 3- Out
7
The 3rd from the end of a chain of 3 is the head itself. The fast finger falls off right after its head start, so slow never moves.
n is 1
- In
4 -> 6 -> 1, n = 1- Out
1
The 1st from the end is the last box.
n is too big
- In
1 -> 2, n = 5- Out
null
There is no 5th box from the end of a chain of 2. The fast finger runs off the chain during its head start, and we stop.
One box
- In
42, n = 1- Out
42
The only box is also the last box.
Way 1: the simple way
Count first, then walk.
- Walk the whole chain and count the boxes. Call the count
len. - If
nis bigger thanlen, give backnull. - The box
nfrom the end is the box at positionlen - nfrom the start (counting from 0). Walk that many steps from the head.
len is 6 and n is 2, so we take 6 - 2 = 4 steps from the head and land on 3.
- len
- 6
- n
- 2
- steps
- 4
- seen
- answer
class Solution {
public ListNode nthFromEnd(ListNode head, int n) {
int len = 0;
for (ListNode cur = head; cur != null; cur = cur.next) len++; // count the boxes
if (n <= 0 || n > len) return null; // no such box
ListNode cur = head;
for (int i = 0; i < len - n; i++) cur = cur.next; // walk len - n steps
return cur;
}
}How long it takes: one walk to count and part of a second walk, so O(n) where n here means the number of boxes. Extra room: one counter and one finger, O(1). This is already fine, but it reads the chain twice, and interviewers usually ask for one walk.
Way 2: the clever way
Use the broom. Two fingers, fast and slow, both start at the head.
- Move
fastforwardnsteps. If it falls off the chain before finishing, the chain is too short, so give backnull. - Now
fastisnboxes ahead ofslow. Move both one step at a time. - When
faststeps off the end (it becomesnull),slowis exactlynboxes from the end. Give backslow.
The broom finds the 2nd box from the end
01 / 07
Both fingers start on the head. n is 2, so fast gets a head start of 2 steps.
- n
- 2
- gap
- 0
- looking now
- checking
- seen
- answer
- path
class Solution {
public ListNode nthFromEnd(ListNode head, int n) {
if (n <= 0) return null;
ListNode fast = head, slow = head;
for (int i = 0; i < n; i++) { // give fast a head start of n steps
if (fast == null) return null; // the chain is shorter than n
fast = fast.next;
}
while (fast != null) { // walk together until fast falls off
fast = fast.next;
slow = slow.next;
}
return slow; // n boxes from the end
}
}How long it takes: fast walks the chain once and slow walks part of it, so O(n). Extra room: two fingers, O(1). The big win is one single walk, which matters when the chain is a stream you can read only once.
Watch out for
nbigger than the length: check fornullduring the head start, not after.nequal to the length:fastbecomesnullright after the head start and the answer is the head. Make sure the code does not treat this as "too big".- An empty chain:
headisnull, the head start loop returnsnullat once. nof 0 or below: there is no 0th box from the end. Returnnull.
What interviewers ask next
- Delete the nth box from the end (LeetCode 19). Put a fake box in front of the head, called a dummy. Run the same broom from the dummy with a gap of
n + 1, soslowstops on the box before the one to delete. Then doslow.next = slow.next.next. The dummy makes deleting the head easy. - Find the middle box. Use two fingers again, but
fastmoves 2 steps for every 1 step ofslow. - Can you do it with recursion? Yes. Go all the way down, then count up on the way back. When the count hits
n, that box is the answer. It usesO(n)stack room though. - What if the list is a stream and you may keep only
nvalues? Keep the lastnvalues in a ring of sizen. When the stream ends, the oldest value in the ring is the answer.
Remember this
Grown-up words: the boxes are nodes, the broom is a fixed gap between two pointers (the two pointer or runner technique), and the fake front box is a dummy node.