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 <= 20
1 <= url.length <= 20
1 <= steps <= 100
homepage
and url
consist of '.' or lower case English letters.5000
calls will be made to visit
, back
, and forward
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We need to simulate how a browser's history works when you visit websites, go back, and go forward. A brute force approach means we'll keep a simple record of all the visited websites and directly manipulate it as needed.
Here's how the algorithm would work step-by-step:
class BrowserHistory:
def __init__(self, homepage: str):
self.history = [homepage]
self.current_index = 0
def visit(self, url: str) -> None:
# When visiting, clear future history
self.history = self.history[:self.current_index + 1]
self.history.append(url)
self.current_index += 1
def back(self, steps: int) -> str:
# Move back, but not past the beginning
self.current_index = max(0, self.current_index - steps)
return self.history[self.current_index]
def forward(self, steps: int) -> str:
# Move forward, but not past the end.
self.current_index = min(len(self.history) - 1, self.current_index + steps)
return self.history[self.current_index]
We can efficiently simulate browser history navigation using two separate stacks. One stack stores the past URLs, and another stores the future URLs. This allows us to easily move back and forth through the history.
Here's how the algorithm would work step-by-step:
class BrowserHistory:
def __init__(self, homepage: str):
self.back_stack = []
self.forward_stack = []
self.current_page = homepage
def visit(self, url: str) -> None:
# When visiting a new page, clear future history.
self.back_stack.append(self.current_page)
self.forward_stack = []
self.current_page = url
def back(self, steps: int) -> str:
# Move back in history, or stay if no history exists.
while steps > 0 and self.back_stack:
self.forward_stack.append(self.current_page)
self.current_page = self.back_stack.pop()
steps -= 1
return self.current_page
def forward(self, steps: int) -> str:
# Move forward in history, or stay if no history exists.
while steps > 0 and self.forward_stack:
self.back_stack.append(self.current_page)
self.current_page = self.forward_stack.pop()
steps -= 1
return self.current_page
# Your BrowserHistory object will be instantiated and called as such:
# browser_history = BrowserHistory(homepage)
# browser_history.visit(url)
# browser_history.back(steps)
# browser_history.forward(steps)
Case | How to Handle |
---|---|
Initial URL is null or empty string | Treat null/empty string as a valid, albeit potentially nonsensical, starting point, defaulting to an empty history state. |
visit() called with null or empty string | Handle null/empty URL in visit() as a valid operation, perhaps resulting in an empty URL entry in the history. |
back() or forward() called with 0 steps | If steps is 0 in back() or forward(), return the current URL without modifying the history. |
back() called with steps larger than the current history size | Cap the back movement to the maximum possible distance, going to the oldest entry available. |
forward() called with steps larger than the available forward history | Cap the forward movement to the maximum possible distance, going to the newest entry available. |
Repeated calls to visit() creating a long history | Ensure the data structure used for the history (e.g., array, linked list) can efficiently handle a large number of visited URLs without excessive memory usage or slowdown. |
Concurrent access to BrowserHistory object (multithreading) | If multithreading is a concern, use appropriate locking mechanisms to protect the internal state of the BrowserHistory object and prevent race conditions. |
Very long URLs | The URL strings might be very long; confirm that your chosen data structure (e.g. String or StringBuilder) can handle them without performance issues. |