窥视迭代器

标签: 设计 数组 迭代器

难度: Medium

请你在设计一个迭代器,在集成现有迭代器拥有的 hasNextnext 操作的基础上,还额外支持 peek 操作。

实现 PeekingIterator 类:

  • PeekingIterator(Iterator<int> nums) 使用指定整数迭代器 nums 初始化迭代器。
  • int next() 返回数组中的下一个元素,并将指针移动到下个元素处。
  • bool hasNext() 如果数组中存在下一个元素,返回 true ;否则,返回 false
  • int peek() 返回数组中的下一个元素,但 移动指针。

注意:每种语言可能有不同的构造函数和迭代器 Iterator,但均支持 int next()boolean hasNext() 函数。

示例 1:

输入:
["PeekingIterator", "next", "peek", "next", "next", "hasNext"]
[[[1, 2, 3]], [], [], [], [], []]
输出:
[null, 1, 2, 2, 3, false]

解释:
PeekingIterator peekingIterator = new PeekingIterator([1, 2, 3]); // [1,2,3]
peekingIterator.next();    // 返回 1 ,指针移动到下一个元素 [1,2,3]
peekingIterator.peek();    // 返回 2 ,指针未发生移动 [1,2,3]
peekingIterator.next();    // 返回 2 ,指针移动到下一个元素 [1,2,3]
peekingIterator.next();    // 返回 3 ,指针移动到下一个元素 [1,2,3]
peekingIterator.hasNext(); // 返回 False

提示:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 1000
  • nextpeek 的调用均有效
  • nexthasNextpeek 最多调用  1000

进阶:你将如何拓展你的设计?使之变得通用化,从而适应所有的类型,而不只是整数型?

Submission

运行时间: 27 ms

内存: 16.1 MB

# Below is the interface for Iterator, which is already defined for you.
#
# class Iterator:
#     def __init__(self, nums):
#         """
#         Initializes an iterator object to the beginning of a list.
#         :type nums: List[int]
#         """
#
#     def hasNext(self):
#         """
#         Returns true if the iteration has more elements.
#         :rtype: bool
#         """
#
#     def next(self):
#         """
#         Returns the next element in the iteration.
#         :rtype: int
#         """

class PeekingIterator:
    def __init__(self, iterator):
        """
        Initialize your data structure here.
        :type iterator: Iterator
        """
        self._iter = iterator
        self._next = self._iter.next()

    def peek(self):
        """
        Returns the next element in the iteration without advancing the iterator.
        :rtype: int
        """
        return self._next

    def next(self):
        """
        :rtype: int
        """
        ret = self._next
        self._next = self._iter.next() if self._iter.hasNext() else None
        return ret

    def hasNext(self):
        """
        :rtype: bool
        """
        return self._next is not None


# Your PeekingIterator object will be instantiated and called as such:
# iter = PeekingIterator(Iterator(nums))
# while iter.hasNext():
#     val = iter.peek()   # Get the next element but not advance the iterator.
#     iter.next()         # Should return the same value as [val].

Explain

此题解通过封装原有的迭代器来实现一个支持`peek`操作的新迭代器。核心思路是在PeekingIterator类中,使用一个额外的变量`_next`来存储下一个元素,从而在调用`peek`时不移动原迭代器的指针。当调用`next`方法时,首先返回`_next`中存储的元素,然后更新`_next`为原迭代器的下一个元素。如果原迭代器没有下一个元素,`_next`设为None。`hasNext`方法则检查`_next`是否为None来决定是否还有后续元素。

时间复杂度: O(1)

空间复杂度: O(1)

# Below is the interface for Iterator, which is already defined for you.
#
# class Iterator:
#     def __init__(self, nums):
#         """
#         Initializes an iterator object to the beginning of a list.
#         :type nums: List[int]
#         """
#
#     def hasNext(self):
#         """
#         Returns true if the iteration has more elements.
#         :rtype: bool
#         """
#
#     def next(self):
#         """
#         Returns the next element in the iteration.
#         :rtype: int
#         """

class PeekingIterator:
    def __init__(self, iterator):
        """
        Initialize your data structure here.
        :type iterator: Iterator
        """
        self._iter = iterator  # 保存原始迭代器的引用
        self._next = self._iter.next()  # 预先读取第一个元素

    def peek(self):
        """
        Returns the next element in the iteration without advancing the iterator.
        :rtype: int
        """
        return self._next  # 返回预存的下一个元素

    def next(self):
        """
        :rtype: int
        """
        ret = self._next  # 保存当前_next的值用于返回
        self._next = self._iter.next() if self._iter.hasNext() else None  # 更新_next为下一个元素,或者为None
        return ret  # 返回之前的_next值

    def hasNext(self):
        """
        :rtype: bool
        """
        return self._next is not None  # 如果_next不为None,则还有元素可迭代

Explore

在类构造函数`PeekingIterator`中,如果初始迭代器为空,即没有元素可以迭代,那么`self._iter.next()`将会抛出异常,因为它尝试获取不存在的元素。为了处理这种情况,我们应该在调用`self._iter.next()`之前检查迭代器是否还有后续元素。如果没有元素,应该将`self._next`设为None,而不是直接调用`next()`方法。

在`next`方法中,如果`_next`为None,表明迭代器已经没有更多的元素可以返回。在这种情况下,继续调用`next()`方法通常应返回一个错误或异常,因为再没有元素可以返回。最佳做法是抛出一个`StopIteration`异常,这与Python的迭代器协议一致,当迭代器中没有更多元素时,应通过抛出`StopIteration`来通知调用者。

在设计`peek`方法时,保证连续调用不影响迭代器状态的关键在于不改变迭代器内部的指针位置。`PeekingIterator`类通过维护一个额外的成员变量`_next`来实现这一点,该变量存储下一个要返回的元素。当调用`peek`方法时,仅返回`_next`变量的值,而不从底层迭代器中提取新的元素,因此迭代器的当前状态不受`peek`调用的影响。