请你在设计一个迭代器,在集成现有迭代器拥有的 hasNext
和 next
操作的基础上,还额外支持 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
对 next
和 peek
的调用均有效
next
、hasNext
和 peek
最多调用 1000
次
进阶: 你将如何拓展你的设计?使之变得通用化,从而适应所有的类型,而不只是整数型?
方法一:迭代器 最直观的做法是使用一个列表存储迭代器中的每个元素,然后按顺序遍历列表中的元素模拟迭代器,但是该做法没有利用到迭代器的性质,更好的做法是利用迭代器的性质实现顶端迭代器的操作。
顶端迭代器需要实现以下三种操作:
每种编程语言自带的迭代器可能支持上述一种或多种操作,但是不一定支持上述全部操作。如果编程语言自带的迭代器本身就支持上述操作,可以直接使用,否则需要自定义实现。
Java 的 Iterator 接口和 JavaScript 中自定义的 Iterator 接口支持 next 和 hasNext 操作,但是不支持 peek 操作。为了在顶端迭代器中支持 peek 操作,需要使用 $\textit{nextElement 存储迭代器的下一个元素,各项操作的实现如下:
next:首先用 $\textit{ret 存储 $\textit{nextElement 表示返回值,然后将 $\textit{nextElement 向后移动一位,最后返回 $\textit{ret;
hasNext:由于 $\textit{nextElement 为迭代器的下一个元素,因此当 $\textit{nextElement 不为空时返回 $\text{true,否则返回 $\text{false;
peek:由于 peek 操作不改变指针,因此返回 $\textit{nextElement。
C# 的 IEnumerator 接口包含属性 $\textit{Current 和方法 $\textit{MoveNext(该方法的返回值类型是 bool,表示是否成功移动到下一个元素),三种操作都需要自定义实现,需要使用 $\textit{flag 存储迭代器是否还有剩余的元素。
next:首先用 $\textit{ret 存储 $\textit{iterator}.\textit{Current 表示返回值,然后对 $\textit{iterator 调用 $\textit{MoveNext 方法使其向后移动一位并将该方法的结果赋值给 $\textit{flag,最后返回 $\textit{ret;
hasNext:返回 $\text{flag;
peek:由于 peek 操作不改变指针,因此返回 $\textit{iterator}.\textit{Current。
C++ 中 PeekingIterator 继承父类 Iterator,Iterator 已经实现方法 next 和 hasNext,在此我们在 PeekingIterator 中主要实现 peek 方法即可。我们使用 $\textit{flag 标记迭代器是否还有剩余元素,使用 $\textit{nextElement 存储迭代器的下一个元素。
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class PeekingIterator implements Iterator <Integer> { private Iterator<Integer> iterator; private Integer nextElement; public PeekingIterator (Iterator<Integer> iterator) { this .iterator = iterator; nextElement = iterator.next(); } public Integer peek () { return nextElement; } @Override public Integer next () { Integer ret = nextElement; nextElement = iterator.hasNext() ? iterator.next() : null ; return ret; } @Override public boolean hasNext () { return nextElement != null ; } }
[sol1-C#] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class PeekingIterator { private IEnumerator<int > iterator; private bool flag; public PeekingIterator (IEnumerator<int > iterator ) { this .iterator = iterator; flag = true ; } public int Peek () { return iterator.Current; } public int Next () { int ret = iterator.Current; flag = iterator.MoveNext(); return ret; } public bool HasNext () { return flag; } }
[sol1-JavaScript] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var PeekingIterator = function (iterator ) { this .iterator = iterator; this .nextElement = this .iterator .next (); }; PeekingIterator .prototype .peek = function ( ) { return this .nextElement ; }; PeekingIterator .prototype .next = function ( ) { const ret = this .nextElement ; this .nextElement = this .iterator .hasNext () ? this .iterator .next () : null ; return ret; }; PeekingIterator .prototype .hasNext = function ( ) { return this .nextElement != null ; };
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class PeekingIterator : public Iterator {public : PeekingIterator (const vector<int >& nums) : Iterator (nums) { flag = Iterator::hasNext (); if (flag) { nextElement = Iterator::next (); } } int peek () { return nextElement; } int next () { int ret = nextElement; flag = Iterator::hasNext (); if (flag) { nextElement = Iterator::next (); } return ret; } bool hasNext () const { return flag; } private : int nextElement; bool flag; };
[sol1-Golang] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 type PeekingIterator struct { iter *Iterator _hasNext bool _next int } func Constructor (iter *Iterator) *PeekingIterator { return &PeekingIterator{iter, iter.hasNext(), iter.next()} } func (it *PeekingIterator) hasNext() bool { return it._hasNext } func (it *PeekingIterator) next() int { ret := it._next it._hasNext = it.iter.hasNext() if it._hasNext { it._next = it.iter.next() } return ret } func (it *PeekingIterator) peek() int { return it._next }
[sol1-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class PeekingIterator : def __init__ (self, iterator ): self.iterator = iterator self._next = iterator.next () self._hasNext = iterator.hasNext() def peek (self ): return self._next def next (self ): ret = self._next self._hasNext = self.iterator.hasNext() self._next = self.iterator.next () if self._hasNext else 0 return ret def hasNext (self ): return self._hasNext
复杂度分析
进阶问题 进阶问题要求拓展顶端迭代器的设计,使其适用于所有类型,不局限于整数。
对于动态类型语言如 JavaScript 和 Python,不需要拓展上述设计。
对于静态类型语言如 Java、C# 和 C++,可以通过使用泛型的方式拓展设计,在 PeekingIterator 类中定义泛型,使用时可以用任意类型。
[sol2-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class PeekingIterator <E> implements Iterator <E> { private Iterator<E> iterator; private E nextElement; public PeekingIterator (Iterator<E> iterator) { this .iterator = iterator; nextElement = iterator.next(); } public E peek () { return nextElement; } @Override public E next () { E ret = nextElement; nextElement = iterator.hasNext() ? iterator.next() : null ; return ret; } @Override public boolean hasNext () { return nextElement != null ; } }
[sol2-C#] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class PeekingIterator <T > { private IEnumerator<T> iterator; private bool flag; public PeekingIterator (IEnumerator<T> iterator ) { this .iterator = iterator; flag = true ; } public T Peek () { return iterator.Current; } public T Next () { T ret = iterator.Current; flag = iterator.MoveNext(); return ret; } public bool HasNext () { return flag; } }
[sol2-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 template <class T >class PeekingIterator : public Iterator<T> {public : PeekingIterator (const vector<T>& nums) : Iterator <T>(nums) { flag = Iterator<T>::hasNext (); if (flag) { nextElement = Iterator<T>::next (); } } T peek () { return nextElement; } T next () { T ret = nextElement; flag = Iterator<T>::hasNext (); if (flag) { nextElement = Iterator<T>::next (); } return ret; } bool hasNext () const { return flag; } private : T nextElement; bool flag; };