Design an iterator that supports the peek operation on an existing iterator in addition to the hasNext and the next operations.
Implement the PeekingIterator class:
PeekingIterator(Iterator<int> nums) Initializes the object with the given integer iterator iterator.int next() Returns the next element in the array and moves the pointer to the next element.boolean hasNext() Returns true if there are still elements in the array.int peek() Returns the next element in the array without moving the pointer.Note: Each language may have a different implementation of the constructor and Iterator, but they all support the int next() and boolean hasNext() functions.
Example 1:
Input ["PeekingIterator", "next", "peek", "next", "next", "hasNext"] [[[1, 2, 3]], [], [], [], [], []] Output [null, 1, 2, 2, 3, false] Explanation PeekingIterator peekingIterator = new PeekingIterator([1, 2, 3]); // [1,2,3] peekingIterator.next(); // return 1, the pointer moves to the next element [1,2,3]. peekingIterator.peek(); // return 2, the pointer does not move [1,2,3]. peekingIterator.next(); // return 2, the pointer moves to the next element [1,2,3] peekingIterator.next(); // return 3, the pointer moves to the next element [1,2,3] peekingIterator.hasNext(); // return False
Constraints:
1 <= nums.length <= 10001 <= nums[i] <= 1000next and peek are valid.1000 calls will be made to next, hasNext, and peek.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 want to build a special tool that lets us look at the next item in a sequence without actually moving to it. The brute force method simulates this by keeping track of all the items and manually peeking and advancing through them whenever asked.
Here's how the algorithm would work step-by-step:
class PeekingIterator:
def __init__(self, iterator):
# Create a list to hold the iterator's elements.
self.all_elements = list(iterator)
self.current_index = 0
def peek(self):
# Check if there are any more elements.
if self.has_next():
# Return the element at the current index without advancing.
return self.all_elements[self.current_index]
else:
return None
def next(self):
# Check if there are any more elements.
if self.has_next():
# Retrieve the element at the current index and advance the index.
next_element = self.all_elements[self.current_index]
self.current_index += 1
return next_element
else:
return None
def has_next(self):
# Check if the current index is within the bounds of all_elements.
return self.current_index < len(self.all_elements)The Peeking Iterator problem asks us to extend the functionality of a regular iterator. The trick is to store the 'next' element that the iterator would return, so we can 'peek' at it without actually consuming it. We use this stored value strategically to avoid repetitive calls to the underlying iterator.
Here's how the algorithm would work step-by-step:
class PeekingIterator:
def __init__(self, iterator):
self.iterator = iterator
self.next_element = None
# Initialize the next element during instantiation.
if iterator.hasNext():
self.next_element = iterator.next()
def peek(self):
return self.next_element
def next(self):
element_to_return = self.next_element
# Advance the stored element.
if self.iterator.hasNext():
self.next_element = self.iterator.next()
# Set next element to None if iterator is exhausted.
else:
self.next_element = None
return element_to_return
def hasNext(self):
# True if there is a stored next element.
return self.next_element is not None| Case | How to Handle |
|---|---|
| Iterator is initially empty. | peek() should return null or throw an exception, next() should throw an exception or return null, hasNext() should return false. |
| Iterator contains only one element. | peek() should return that element, next() should return that element, hasNext() should return false after the first next(). |
| Calling peek() multiple times in a row. | Subsequent calls to peek() without calling next() should return the same element. |
| Calling next() after calling peek(). | The next() call should return the element that was previously peeked. |
| Calling next() when hasNext() returns false. | next() should return null or throw an exception to signal the end of the iteration. |
| Integer overflow if the iterator returns large numbers | The peeking iterator should be able to store and return large integers without causing an overflow, potentially requiring long data types |
| Large number of peek() calls without calling next(). | The solution should handle a large number of consecutive peek() calls without significant performance degradation, storing the peeked value efficiently. |
| Underlying iterator throws exceptions | The PeekingIterator's methods should gracefully handle exceptions thrown by the underlying iterator's next() or hasNext() methods. |