284. Peeking Iterator
On LeetCode ->Problem¶
Wrap an iterator with peek(), which returns the next value without consuming it; preserve next() and hasNext() behavior. Calls to peek() and next() are guaranteed valid.
# Below is the interface for Iterator, which is already defined for you.
#
# class Iterator:
# def __init__(self, nums):
#
# def hasNext(self):
#
# def next(self):
class PeekingIterator:
def __init__(self, iterator):
pass
def peek(self):
pass
def next(self):
pass
def hasNext(self):
pass
Key trick¶
Cache one value and track whether it is buffered; peek() fills the cache, and next() consumes it.
Trap¶
Do not use the cached value's truthiness or None to detect availability: generic iterators may contain 0, False, or None.
Why is it interesting?¶
It adds lookahead to a forward-only interface using constant space, a technique useful in parsers and streaming algorithms.
Python solution¶
class PeekingIterator:
def __init__(self, iterator):
self.it = iterator
self.ready = False
self.val = None
def peek(self):
if not self.ready:
if not self.it.hasNext():
raise StopIteration
self.val = self.it.next()
self.ready = True
return self.val
def next(self):
val = self.peek()
self.ready = False
self.val = None # Release the consumed value's reference.
return val
def hasNext(self):
return self.ready or self.it.hasNext()
Time: \(O(1)\) per operation, assuming constant-time underlying operations.
Extra space: \(O(1)\).
Comment on my solution¶
Your solution is correct, uses \(O(1)\) time per operation and \(O(1)\) extra space, and already supports arbitrary value types through ready.
Your hasNext() performs lookahead and may advance the underlying iterator, but preserves the wrapper's logical position by caching the value; this is valid. The version above delays that read until peek() or next().
# WORKS
class PeekingIterator:
def __init__(self, iterator):
self.it = iterator
self.ready = False
self.val = None
def peek(self):
if not self.hasNext():
raise StopIteration
return self.val
def next(self):
if not self.hasNext():
raise StopIteration
self.ready = False
return self.val
def hasNext(self):
if self.ready:
return True
if not self.it.hasNext():
return False
self.ready = True
self.val = self.it.next()
return True