Peeking Iterator - Problem
Design a Peeking Iterator - Create an enhanced iterator that extends the functionality of a standard iterator by adding a peek() operation.

You're given a basic iterator that supports next() and hasNext() operations. Your task is to implement a PeekingIterator class that adds the ability to look ahead at the next element without consuming it.

Key Requirements:
  • next() - Returns the next element and advances the iterator
  • hasNext() - Returns true if more elements exist
  • peek() - Returns the next element without advancing the iterator

The challenge is maintaining the iterator's state while supporting the peek functionality efficiently. This pattern is commonly used in parsers, tokenizers, and streaming data processors where you need to make decisions based on upcoming elements.

Input & Output

example_1.py โ€” Basic Usage
$ Input: Iterator: [1, 2, 3] Operations: ["peek", "next", "peek", "next", "hasNext"]
โ€บ Output: [1, 1, 2, 2, true]
๐Ÿ’ก Note: peek() returns 1 without advancing, next() returns 1 and advances, peek() returns 2, next() returns 2 and advances, hasNext() returns true since 3 remains
example_2.py โ€” Multiple Peeks
$ Input: Iterator: [1, 2] Operations: ["peek", "peek", "next", "peek", "next", "hasNext"]
โ€บ Output: [1, 1, 1, 2, 2, false]
๐Ÿ’ก Note: Multiple consecutive peeks return the same value without advancing. After consuming all elements, hasNext() returns false
example_3.py โ€” Single Element
$ Input: Iterator: [42] Operations: ["hasNext", "peek", "hasNext", "next", "hasNext"]
โ€บ Output: [true, 42, true, 42, false]
๐Ÿ’ก Note: Single element case - peek doesn't affect hasNext() result until element is consumed via next()

Visualization

Tap to expand
PeekingIterator State ManagementInitial StatehasPeeked: falsecache: emptyAfter peek()hasPeeked: truecache: valueMultiple peek()hasPeeked: truereturn cachedAfter next()hasPeeked: falsecache: clearedpeek()peek()next()Memory Efficiency ComparisonBrute ForceSpace: O(n)Store all elementsOptimalSpace: O(1)Cache 1 elementBetter!๐ŸŽฏ Key Insight: Lazy evaluation with minimal cachingOnly fetch next element when peek() is called
Understanding the Visualization
1
Initial State
Iterator is ready, no element cached yet
2
First Peek
Cache the next element from underlying iterator
3
Multiple Peeks
Return cached element without re-fetching
4
Next Operation
Return cached element and clear cache
5
Direct Next
If no cache, directly get from underlying iterator
Key Takeaway
๐ŸŽฏ Key Insight: The optimal solution balances memory efficiency with functionality by caching only what's needed, when it's needed - a perfect example of lazy evaluation in iterator design.

Time & Space Complexity

Time Complexity
โฑ๏ธ
O(1)

All operations (peek, next, hasNext) are constant time

n
2n
โœ“ Linear Growth
Space Complexity
O(1)

Only stores one cached element and iterator reference

n
2n
โœ“ Linear Space

Constraints

  • 1 โ‰ค nums.length โ‰ค 1000
  • -1000 โ‰ค nums[i] โ‰ค 1000
  • At most 1000 calls will be made to next(), hasNext(), and peek()
  • Follow up: How would you extend this to support multiple peek() calls ahead?
Asked in
Google 45 Amazon 38 Apple 32 Microsoft 28
78.2K Views
Medium-High Frequency
~15 min Avg. Time
1.9K Likes
Ln 1, Col 1
Smart Actions
๐Ÿ’ก Explanation
AI Ready
๐Ÿ’ก Suggestion Tab to accept Esc to dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen