Design Browser History
Problem
Implement a browser history system that supports visiting new URLs, moving back in history by a given number of steps, and moving forward in history by a given number of steps, returning the current URL after each operation.
- 1 ≤ steps ≤ 100
- 1 ≤ url.length ≤ 20
- url consists of lowercase English letters and '.'
- At most 5000 calls will be made to visit, back, and forward.
Example
BrowserHistory browserHistory = new BrowserHistory("leetcode.com");
browserHistory.visit("google.com");
browserHistory.visit("facebook.com");
browserHistory.visit("youtube.com");
browserHistory.back(1);
browserHistory.back(1);
browserHistory.forward(1);
browserHistory.visit("linkedin.com");
browserHistory.forward(2);
browserHistory.back(2);
browserHistory.back(7);[null,null,null,null,"facebook.com","google.com","facebook.com",null,"linkedin.com","google.com","leetcode.com"]Start at 'leetcode.com'. Visit 'google.com', 'facebook.com', and 'youtube.com' sequentially, building back history. Back(1) moves from 'youtube.com' to 'facebook.com'. Back(1) moves to 'google.com'. Forward(1) moves to 'facebook.com'. Visit('linkedin.com') clears forward history and sets current to 'linkedin.com'. Forward(2) has no effect since forward history is empty. Back(2) moves back to 'google.com'. Back(7) moves back as far as possible to 'leetcode.com'.
Approach
Straightforward Solution
One could store the entire history in a list and maintain an index pointer for the current page. Moving back or forward would adjust the index accordingly. However, clearing forward history on visit requires slicing or resetting the list, which can be inefficient.
Core Observation
Browser navigation can be modeled as a linear history with a current position, where moving back and forward corresponds to moving along this history. Using two stacks to represent backward and forward history allows efficient simulation of these movements.
Path to Optimal
PreviewUsing two stacks cleanly separates backward and forward history. The back stack holds pages visited before the current one, and the forward stack holds pages ahead…
Full step-by-step walkthrough on Pro →
Optimal Approach
PreviewMaintain three variables: back_stack, forward_stack, and curr (current page). On visit, push curr to back_stack, update curr, and clear forward_stack…
Full step-by-step walkthrough on Pro →
Want the full reasoning chain?
Unlock the complete walkthrough, line-by-line analysis, and recall drill.
Unlock ProTime
O(steps) per back or forward call, O(1) per visit call
Each back or forward operation moves pages between stacks up to the number of steps requested, resulting in O(steps) time. Visit operations perform constant-time stack operations.
Space
O(n)
The space used is proportional to the number of visited pages stored in the back and forward stacks, which can grow linearly with the number of visit calls.
Pattern Spotlight
Simulation (Stateful Stack-Based History Management)
Model bidirectional navigation by maintaining two stacks representing backward and forward history, pushing and popping pages to simulate user navigation efficiently and cleanly.
Solution
| 1 | class BrowserHistory: |
| 2 | |
| 3 | def __init__(self, homepage: str): |
| 4 | self.back_stack = [] |
| 5 | self.forward_stack = [] |
| 6 | self.curr = homepage |
| 7 | |
| 8 | def visit(self, url: str) -> None: |
| 9 | self.back_stack.append(self.curr) |
| 10 | self.curr = url |
| 11 | self.forward_stack = [] |
| 12 | |
| 13 | def back(self, steps: int) -> str: |
| 14 | while steps > 0 and self.back_stack: |
| 15 | self.forward_stack.append(self.curr) |
| 16 | self.curr = self.back_stack.pop() |
| 17 | steps -= 1 |
| 18 | return self.curr |
| 19 | |
| 20 | def forward(self, steps: int) -> str: |
| 21 | while steps > 0 and self.forward_stack: |
| 22 | self.back_stack.append(self.curr) |
| 23 | self.curr = self.forward_stack.pop() |
| 24 | steps -= 1 |
| 25 | return self.curr |
Step-by-Step Solution
Initialize Browser History State with Homepage
| 4 | self.back_stack = [] |
| 5 | self.forward_stack = [] |
| 6 | self.curr = homepage |
Objective
To set up the initial browser state with empty back and forward stacks and the current page set to the homepage.
Key Insight
Starting with empty stacks ensures no backward or forward history exists initially. Setting the current page to the homepage reflects the browser's starting point. This clean separation of state variables simplifies subsequent navigation operations.
Interview Quick-Check
Core Logic
The back and forward stacks represent navigation history before and after the current page, respectively.
State & Boundaries
The current page is stored separately to allow O(1) access and updates during navigation.
Visit a New URL and Reset Forward History
To record the current page in back history, update the current page to the new URL, and clear forward history.
Move Backward in History Up to Steps
To move back in history by popping pages from the back stack to the current page and pushing the previous current page onto the forward stack, up to the requested number of steps.
Move Forward in History Up to Steps
To move forward in history by popping pages from the forward stack to the current page and pushing the previous current page onto the back stack, up to the requested number of steps.
3 more steps with full analysis available on Pro.
Line Analysis
This solution has 4 Critical lines interviewers watch for.
self.back_stack.append(self.curr)
Push the current page onto the back stack before visiting a new URL.
Preserving the current page in back history allows the user to return to it after visiting a new page, maintaining correct navigation order.
self.forward_stack = []
Clear the forward stack to discard forward history after visiting a new page.
Visiting a new page invalidates any forward history, so clearing the forward stack prevents incorrect forward navigation.
self.curr = self.back_stack.pop()
Pop the most recent page from the back stack and set it as the current page.
This updates the current page to the previous page in history, simulating the back button behavior.
Full line-by-line criticality + rationale for all 16 lines available on Pro.
Test Your Understanding
Why does using two stacks to represent backward and forward history correctly simulate browser navigation?
See the answer with Pro.
Related Problems
Simulation pattern
Don't just read it. Drill it.
Reconstruct Design Browser History from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.
Unlock the Design Browser History drill