一、题目描述
请你在设计一个迭代器,在集成现有迭代器拥有的 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 <= 10001 <= nums[i] <= 1000- 对
next和peek的调用均有效 next、hasNext和peek最多调用1000次
二、解题思路
为了实现PeekingIterator类,我们需要在内部维护一个迭代器的状态,并在每次调用next和peek时更新这个状态。以下是具体的实现步骤:
-
在构造函数中,我们需要接收一个整数迭代器
nums,并初始化内部状态。我们可以定义一个变量nextElement来存储下一个元素,并在构造函数中立即调用一次next()来填充这个变量。 -
实现
peek()方法时,我们只需要返回nextElement,而不需要更新迭代器的状态。 -
实现
next()方法时,我们需要返回nextElement,并在返回之前调用迭代器的next()方法来更新nextElement。 -
实现
hasNext()方法时,我们只需要检查nextElement是否为null,如果是null,则说明没有下一个元素了。
三、具体代码
class PeekingIterator implements Iterator<Integer> {
private Integer nextElement = null;
private Iterator<Integer> iterator;
public PeekingIterator(Iterator<Integer> iterator) {
// Initialize any member here.
this.iterator = iterator;
if (this.iterator.hasNext()) {
nextElement = this.iterator.next();
}
}
// Returns the next element in the iteration without advancing the iterator.
public Integer peek() {
return nextElement;
}
// hasNext() and next() should behave the same as in the Iterator interface.
// Override them if needed.
@Override
public Integer next() {
Integer current = nextElement;
nextElement = iterator.hasNext() ? iterator.next() : null;
return current;
}
@Override
public boolean hasNext() {
return nextElement != null;
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
-
PeekingIterator(Iterator<Integer> iterator):构造函数中调用了hasNext()和next()方法,这两个操作的时间复杂度都是O(1),因此构造函数的时间复杂度是O(1)。 -
peek():该方法直接返回nextElement变量,不涉及任何循环或递归调用,因此时间复杂度是O(1)。 -
next():该方法首先保存nextElement的值,然后检查迭代器是否有下一个元素,如果有,则调用next()方法。由于每次调用next()时,迭代器都会移动到下一个元素,这个操作的时间复杂度是O(1)。因此,next()方法的时间复杂度也是O(1)。 -
hasNext():该方法检查nextElement是否为null,这是一个直接的变量访问操作,时间复杂度是O(1)。
综上所述,PeekingIterator类中所有方法的时间复杂度都是O(1)。
2. 空间复杂度
-
PeekingIterator(Iterator<Integer> iterator):构造函数中,我们声明了一个nextElement变量和一个iterator变量。这两个变量的大小不依赖于输入数据的大小,因此空间复杂度是O(1)。 -
peek():该方法没有使用额外的空间,所以空间复杂度是O(1)。 -
next():该方法在执行过程中没有使用额外的空间,除了更新nextElement,所以空间复杂度是O(1)。 -
hasNext():该方法没有使用额外的空间,所以空间复杂度是O(1)。
因此,PeekingIterator类的空间复杂度也是O(1),即常数空间复杂度。这意味着无论输入数据的大小如何,PeekingIterator类使用的空间量保持不变。
五、总结知识点
-
接口实现(Interface Implementation):
PeekingIterator类实现了Iterator<Integer>接口,这意味着它必须提供next(),hasNext(), 和remove()方法(尽管在这个类中,remove()方法没有被重写)。
-
成员变量(Member Variables):
nextElement:一个Integer类型的成员变量,用于存储下一次调用next()时将返回的元素。iterator:一个Iterator<Integer>类型的成员变量,用于存储传入的迭代器实例。
-
构造函数(Constructor):
- 构造函数接收一个
Iterator<Integer>类型的参数,并在内部初始化成员变量。
- 构造函数接收一个
-
方法重写(Method Overriding):
next():重写了Iterator接口中的next()方法。hasNext():重写了Iterator接口中的hasNext()方法。
-
条件判断(Conditional Statements):
- 在构造函数和
next()方法中使用了if语句来判断迭代器是否有下一个元素。
- 在构造函数和
-
三目运算符(Ternary Operator):
- 在
next()方法中使用三目运算符来简洁地决定nextElement的值。
- 在
-
方法调用(Method Calls):
- 调用传入迭代器的
hasNext()和next()方法。
- 调用传入迭代器的
-
封装(Encapsulation):
nextElement被封装在类内部,外部无法直接访问,只能通过peek()方法来查看下一个元素。
-
返回值(Return Values):
peek()方法返回nextElement,但不修改它。next()方法返回nextElement,并更新nextElement为迭代器的下一个元素。hasNext()方法返回一个布尔值,表示是否还有更多的元素。
-
异常处理(Exception Handling):
- 虽然在这个类中没有显式地处理异常,但实现迭代器时应该考虑可能抛出的
NoSuchElementException(当没有更多元素时调用next())。
- 虽然在这个类中没有显式地处理异常,但实现迭代器时应该考虑可能抛出的
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。



















