Last Updated: March 29, 2026
We need to simulate exactly how browser navigation works. You maintain a history of pages you've visited, and you can move backward and forward through that history. The critical behavior is what happens when you visit a new page while you're somewhere in the middle of your history: all the forward history gets wiped out.
Picture it like this. You visit pages A, B, C, D, then go back twice to B. Now you visit E. At this point, C and D are gone forever. Your history is A, B, E, and there's nothing to move forward to. This "clear forward history on visit" behavior is the core design challenge.
The question boils down to: what data structure lets us efficiently append, truncate forward entries, and move a pointer back and forth?
1 <= steps <= 100 -> Steps are small, so even a loop-based pointer adjustment is fine. No need for O(1) jump tricks.5000 calls to visit, back, and forward -> Very small number of operations. Any O(n) approach per call works comfortably.The most natural mental model for browser history is a chain of nodes where you can move forward and backward, exactly like a doubly linked list. Each node stores a URL, and you keep a pointer to your current node. Going back means following the prev pointer, going forward means following the next pointer, and visiting a new page means creating a new node after the current one and severing everything that came after.
This mirrors the real-world metaphor perfectly. But it comes with overhead: creating node objects, managing pointers, and dealing with garbage collection. For a problem like this, it works, but it's heavier than necessary.
url, prev, and next fields.current to this node.visit(url), create a new node, set current.next to the new node and the new node's prev to current. Move current to the new node. This automatically discards all forward history because nothing points to the old next chain anymore.back(steps), move current backward by following prev pointers up to steps times, stopping if prev is null.forward(steps), move current forward by following next pointers up to steps times, stopping if next is null.back and forward, O(1) for visit. Back and forward traverse the linked list one node at a time, up to steps nodes. Visit just creates a node and updates two pointers.The linked list approach works but traverses nodes one at a time during back and forward. What if we could avoid node-by-node traversal using a simpler, contiguous data structure?
Instead of a linked list, use a simple dynamic array (list) and an integer index pointing to the current page. The array stores URLs in visit order, and the index tells us where we are.
The key insight is how to handle "clear forward history." When we visit a new page from the middle of the history, we don't need to actually delete elements from the array. We just place the new URL at position current + 1 and update a boundary variable that marks the last valid index. Anything beyond that boundary is dead history, invisible to back and forward.
This gives us O(1) for all three operations: visit just writes to an index and updates two integers, back and forward just do arithmetic on the current pointer.
The array acts as a "virtual" history where the last variable serves as a soft boundary. Instead of physically removing forward pages (which would require shifting elements or shrinking the array), we just ignore them by capping forward at last. When a new page is visited, it overwrites whatever was at current + 1, and last moves to match. This is essentially the same trick used in array-based stacks where "popping" just decrements a size counter without clearing memory.
The max and min clamping in back and forward elegantly handles the "can only go x steps" requirement without needing any conditional logic or loops. If you request 100 steps back but you're only at index 2, max(0, 2 - 100) = 0 takes you to the homepage.
current = 0 and last = 0 (the index of the last valid page).visit(url), increment current by 1. If current equals the array size, append the URL. Otherwise, overwrite the URL at current. Set last = current to invalidate all forward history.back(steps), set current = max(0, current - steps). Return the URL at the new current.forward(steps), set current = min(last, current + steps). Return the URL at the new current.last, but the total size never exceeds the number of visits plus one.