LeetCode题练习与总结:窥视迭代器--284
一、题目描述
请你在设计一个迭代器,在集成现有迭代器拥有的 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
次
二、解题思路
为了实现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.@Overridepublic Integer next() {Integer current = nextElement;nextElement = iterator.hasNext() ? iterator.next() : null;return current;}@Overridepublic 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()
)。
- 虽然在这个类中没有显式地处理异常,但实现迭代器时应该考虑可能抛出的
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。