Linked List · 8 of 36
Write a Program to Move the last element to Front in a Linked List
Take the last box of a chain and make it the new first box, by walking with two fingers one box apart and changing three arrows.
- Simple way
- time O(n)
room O(1) - Clever way
- time O(n)
room O(1)
The problem, simply
You get a singly linked list. Unhook the last box and put it at the front, so it becomes the new head. Everything else keeps its order. Give back the new head.
For example 1 2 3 4 5 becomes 5 1 2 3 4. Move the box itself; do not just copy numbers around.
A story to remember it
Picture it
Five boxes. Box 5 will move to the front. Box 4, right before it, will become the new last box.
- looking now
- checking
Examples
A normal case
- In
1 -> 2 -> 3 -> 4 -> 5- Out
5 -> 1 -> 2 -> 3 -> 4
Three arrows change: 4 points to null, 5 points to 1, and the head is now 5.
Two boxes
- In
1 -> 2- Out
2 -> 1
The second to last box is the head itself. It becomes the end.
One box
- In
7- Out
7
The last box is already the first. Nothing to do.
Empty
- In
null- Out
null
Return null without touching anything.
Same numbers
- In
3 -> 3 -> 3- Out
3 -> 3 -> 3
It looks the same, but the box that used to be last is now the head. That is why we move boxes and compare with == in tests, not by value.
Way 1: the simple way
Count first, then walk to the second to last box.
- Walk the chain and count the boxes,
n. - Walk
n - 2steps from the head. You are on the second to last box. - Take its
next(the last box), set the second to last box'snexttonull, point the last box at the old head, and return it.
n is 5, so 3 steps from the head land on box 4, the second to last box.
- n
- 5
- steps
- 3
- looking now
- seen
class Solution {
public ListNode moveToFront(ListNode head) {
if (head == null || head.next == null) return head;
int n = 0;
for (ListNode t = head; t != null; t = t.next) n++; // count the boxes
ListNode curr = head;
for (int i = 0; i < n - 2; i++) curr = curr.next; // second to last box
ListNode last = curr.next;
curr.next = null; // new end of the chain
last.next = head; // last box goes in front
return last;
}
}How long it takes: one walk to count and almost one more to find the box, O(n). Extra room: O(1).
Way 2: the clever way
Do it in one walk with two fingers one box apart. last walks to the end, and secondLast always trails one box behind it.
- If the chain has 0 or 1 boxes, return it.
- Start with
secondLast = nullandlast = head. Whilelast.nextis notnull, movesecondLasttolastandlastforward. - Change three arrows:
secondLast.next = null,last.next = head, and the head becomeslast.
Two fingers walk to the end, then three arrows change
01 / 07
last starts on the head. secondLast is null, one step behind.
- looking now
- checking
- done
- answer
class Solution {
public ListNode moveToFront(ListNode head) {
if (head == null || head.next == null) return head; // 0 or 1 box
ListNode secondLast = null, last = head;
while (last.next != null) { // walk to the end, one box apart
secondLast = last;
last = last.next;
}
secondLast.next = null; // the old second to last is the new end
last.next = head; // the old last box leads now
return last;
}
}How long it takes: one walk, O(n). Extra room: two fingers, O(1). You cannot do better than O(n) on a singly list, because the only way to reach the last box is to walk there.
Watch out for
- Check
head.next == nullfirst. With one box,secondLaststaysnullandsecondLast.nextwould crash. - Return the new head. The caller's old
headvariable still points to box 1, which is now second. - Shifting the numbers instead (copy each number one box to the right and write the last number into the head) prints the same answer, but the boxes did not move. If a box carries more than a number, that is wrong.
What interviewers ask next
- Move the first box to the end instead? Walk to the last box, set
last.next = head, move the head tohead.next, and set the old head'snexttonull. - Move the last
kboxes to the front? That is rotating right byk(LeetCode 61). Use the two finger gap from "nth node from the end" to find the box before the lastk, cut there, and hook the old tail to the old head. - What if the list is doubly linked or keeps a
tailpointer? Then the last box is known right away and the move isO(1):tail.prevbecomes the new tail. - Do it with recursion? Recurse to the second to last box and do the same three changes there. It costs
O(n)stack room for no gain.
Remember this
Grown-up words: the boxes are nodes, the trailing finger is a trailing pointer, and moving the last k boxes to the front is a right rotation of the list.