Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You have a browser of one tab where you start on the homepage and you can visit another url, get back in the history number of steps or move forward in the history number of steps.
Implement the BrowserHistory class:
BrowserHistory(string homepage) Initializes the object with the homepage of the browser.void visit(string url) Visits url from the current page. It clears up all the forward history.string back(int steps) Move steps back in history. If you can only return x steps in the history and steps > x, you will return only x steps. Return the current url after moving back in history at most steps.string forward(int steps) Move steps forward in history. If you can only forward x steps in the history and steps > x, you will forward only x steps. Return the current url after forwarding in history at most steps.Example:
Input:
["BrowserHistory","visit","visit","visit","back","back","forward","visit","forward","back","back"]
[["leetcode.com"],["google.com"],["facebook.com"],["youtube.com"],[1],[1],[1],["linkedin.com"],[2],[2],[7]]
Output:
[null,null,null,null,"facebook.com","google.com","facebook.com",null,"linkedin.com","google.com","leetcode.com"]
Explanation:
BrowserHistory browserHistory = new BrowserHistory("leetcode.com");
browserHistory.visit("google.com"); // You are in "leetcode.com". Visit "google.com"
browserHistory.visit("facebook.com"); // You are in "google.com". Visit "facebook.com"
browserHistory.visit("youtube.com"); // You are in "facebook.com". Visit "youtube.com"
browserHistory.back(1); // You are in "youtube.com", move back to "facebook.com" return "facebook.com"
browserHistory.back(1); // You are in "facebook.com", move back to "google.com" return "google.com"
browserHistory.forward(1); // You are in "google.com", move forward to "facebook.com" return "facebook.com"
browserHistory.visit("linkedin.com"); // You are in "facebook.com". Visit "linkedin.com"
browserHistory.forward(2); // You are in "linkedin.com", you cannot move forward any steps.
browserHistory.back(2); // You are in "linkedin.com", move back two steps to "facebook.com" then to "google.com". return "google.com"
browserHistory.back(7); // You are in "google.com", you can move back only one step to "leetcode.com". return "leetcode.com"
Constraints:
1 <= homepage.length <= 201 <= url.length <= 201 <= steps <= 100homepage and url consist of '.' or lower case English letters.5000 calls will be made to visit, back, and forward.Problem summary: You have a browser of one tab where you start on the homepage and you can visit another url, get back in the history number of steps or move forward in the history number of steps. Implement the BrowserHistory class: BrowserHistory(string homepage) Initializes the object with the homepage of the browser. void visit(string url) Visits url from the current page. It clears up all the forward history. string back(int steps) Move steps back in history. If you can only return x steps in the history and steps > x, you will return only x steps. Return the current url after moving back in history at most steps. string forward(int steps) Move steps forward in history. If you can only forward x steps in the history and steps > x, you will forward only x steps. Return the current url after forwarding in history at most steps.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Linked List · Stack · Design
["BrowserHistory","visit","visit","visit","back","back","forward","visit","forward","back","back"] [["leetcode.com"],["google.com"],["facebook.com"],["youtube.com"],[1],[1],[1],["linkedin.com"],[2],[2],[7]]
design-video-sharing-platform)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1472: Design Browser History
class BrowserHistory {
private Deque<String> stk1 = new ArrayDeque<>();
private Deque<String> stk2 = new ArrayDeque<>();
public BrowserHistory(String homepage) {
visit(homepage);
}
public void visit(String url) {
stk1.push(url);
stk2.clear();
}
public String back(int steps) {
for (; steps > 0 && stk1.size() > 1; --steps) {
stk2.push(stk1.pop());
}
return stk1.peek();
}
public String forward(int steps) {
for (; steps > 0 && !stk2.isEmpty(); --steps) {
stk1.push(stk2.pop());
}
return stk1.peek();
}
}
/**
* Your BrowserHistory object will be instantiated and called as such:
* BrowserHistory obj = new BrowserHistory(homepage);
* obj.visit(url);
* String param_2 = obj.back(steps);
* String param_3 = obj.forward(steps);
*/
// Accepted solution for LeetCode #1472: Design Browser History
type BrowserHistory struct {
stk1 []string
stk2 []string
}
func Constructor(homepage string) BrowserHistory {
t := BrowserHistory{[]string{}, []string{}}
t.Visit(homepage)
return t
}
func (this *BrowserHistory) Visit(url string) {
this.stk1 = append(this.stk1, url)
this.stk2 = []string{}
}
func (this *BrowserHistory) Back(steps int) string {
for i := 0; i < steps && len(this.stk1) > 1; i++ {
this.stk2 = append(this.stk2, this.stk1[len(this.stk1)-1])
this.stk1 = this.stk1[:len(this.stk1)-1]
}
return this.stk1[len(this.stk1)-1]
}
func (this *BrowserHistory) Forward(steps int) string {
for i := 0; i < steps && len(this.stk2) > 0; i++ {
this.stk1 = append(this.stk1, this.stk2[len(this.stk2)-1])
this.stk2 = this.stk2[:len(this.stk2)-1]
}
return this.stk1[len(this.stk1)-1]
}
/**
* Your BrowserHistory object will be instantiated and called as such:
* obj := Constructor(homepage);
* obj.Visit(url);
* param_2 := obj.Back(steps);
* param_3 := obj.Forward(steps);
*/
# Accepted solution for LeetCode #1472: Design Browser History
class BrowserHistory:
def __init__(self, homepage: str):
self.stk1 = []
self.stk2 = []
self.visit(homepage)
def visit(self, url: str) -> None:
self.stk1.append(url)
self.stk2.clear()
def back(self, steps: int) -> str:
while steps and len(self.stk1) > 1:
self.stk2.append(self.stk1.pop())
steps -= 1
return self.stk1[-1]
def forward(self, steps: int) -> str:
while steps and self.stk2:
self.stk1.append(self.stk2.pop())
steps -= 1
return self.stk1[-1]
# Your BrowserHistory object will be instantiated and called as such:
# obj = BrowserHistory(homepage)
# obj.visit(url)
# param_2 = obj.back(steps)
# param_3 = obj.forward(steps)
// Accepted solution for LeetCode #1472: Design Browser History
struct BrowserHistory {
history: Vec<String>,
current: usize,
}
impl BrowserHistory {
fn new(homepage: String) -> Self {
Self {
history: vec![homepage],
current: 0,
}
}
fn visit(&mut self, url: String) {
self.current += 1;
self.history.splice(self.current.., std::iter::once(url));
}
fn back(&mut self, steps: i32) -> String {
self.current = self.current.saturating_sub(steps as usize);
self.history[self.current].clone()
}
fn forward(&mut self, steps: i32) -> String {
self.current = (self.current + steps as usize).min(self.history.len() - 1);
self.history[self.current].clone()
}
}
// Accepted solution for LeetCode #1472: Design Browser History
class BrowserHistory {
history: string[];
current: number;
constructor(homepage: string) {
this.history = [homepage];
this.current = 0;
}
visit(url: string): void {
this.history[++this.current] = url;
this.history.length = this.current + 1;
}
back(steps: number): string {
this.current = Math.max(this.current - steps, 0);
return this.history[this.current];
}
forward(steps: number): string {
this.current = Math.min(this.current + steps, this.history.length - 1);
return this.history[this.current];
}
}
Use this to step through a reusable interview workflow for this problem.
Copy all n nodes into an array (O(n) time and space), then use array indexing for random access. Operations like reversal or middle-finding become trivial with indices, but the O(n) extra space defeats the purpose of using a linked list.
Most linked list operations traverse the list once (O(n)) and re-wire pointers in-place (O(1) extra space). The brute force often copies nodes to an array to enable random access, costing O(n) space. In-place pointer manipulation eliminates that.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Pointer updates overwrite references before they are saved.
Usually fails on: List becomes disconnected mid-operation.
Fix: Store next pointers first and use a dummy head for safer joins.
Wrong move: Pushing without popping stale elements invalidates next-greater/next-smaller logic.
Usually fails on: Indices point to blocked elements and outputs shift.
Fix: Pop while invariant is violated before pushing current element.