[LeetCode] Peeking Iterator 頂端迭代器


 

Given an Iterator class interface with methods: next() and hasNext(), design and implement a PeekingIterator that support the peek() operation -- it essentially peek() at the element that will be returned by the next call to next().

Example:

Assume that the iterator is initialized to the beginning of the list: [1,2,3].

Call next() gets you 1, the first element in the list.
Now you call peek() and it returns 2, the next element. Calling next() after that still return 2. 
You call next() the final time and it returns 3, the last element. 
Calling hasNext() after that should return false.

Hint:

  1. Think of "looking ahead". You want to cache the next element.
  2. Is one variable sufficient? Why or why not?
  3. Test your design with call order of peek() before next() vs next() before peek().
  4. For a clean implementation, check out Google's guava library source code.

Follow up: How would you extend your design to be generic and work with all types, not just integer?

 

這道題讓我們實現一個頂端迭代器,在普通的迭代器類Iterator的基礎上增加了peek的功能,就是返回查看下一個值的功能,但是不移動指針,next()函數才會移動指針,那我們可以定義一個變量專門來保存下一個值,再用一個bool型變量標記是否保存了下一個值,再調用原來的一些成員函數,就可以實現這個頂端迭代器了,參見代碼如下:

 

解法一:

class Iterator {
    struct Data;
    Data* data;
public:
    Iterator(const vector<int>& nums);
    Iterator(const Iterator& iter);
    virtual ~Iterator();
    // Returns the next element in the iteration.
    int next();
    // Returns true if the iteration has more elements.
    bool hasNext() const;
};

class PeekingIterator : public Iterator {
public:
    PeekingIterator(const vector<int>& nums) : Iterator(nums) {
        _flag = false;
    }

    int peek() {
        if (!_flag) _value = Iterator::next();
        _flag = true;
        return _value;
    }

    int next() {
        if (!_flag) return Iterator::next();
        _flag = false;
        return _value;
    }

    bool hasNext() const {
        return _flag || Iterator::hasNext();
    }

private:
    int _value;
    bool _flag;
};

 

這道題主要的考點就是peek函數,因為這個是默認的迭代器不具備的功能。我們其實可以使用一個小trick來實現peek功能,由於peek是要暗中觀察一下下一個元素,但是迭代器並不真正移動到下一個,那么我們其實是可以創建一個副本,然后讓副本移動到下一個,並返回,由於是局部變量,副本在調用結束后也會被銷毀,所以並沒有任何內存問題,可以說是一種相當聰明的解法了,參見代碼如下:

 

解法二:

class Iterator {
    struct Data;
    Data* data;
public:
    Iterator(const vector<int>& nums);
    Iterator(const Iterator& iter);
    virtual ~Iterator();
    // Returns the next element in the iteration.
    int next();
    // Returns true if the iteration has more elements.
    bool hasNext() const;
};

class PeekingIterator : public Iterator {
public:
    PeekingIterator(const vector<int>& nums) : Iterator(nums) {}

    int peek() {
        return Iterator(*this).next();
    }

    int next() {
        return Iterator::next();
    }

    bool hasNext() const {
        return Iterator::hasNext();
    }
};

 

類似題目:

Binary Search Tree Iterator

Flatten 2D Vector

Zigzag Iterator

 

參考資料:

https://leetcode.com/problems/peeking-iterator/

https://leetcode.com/problems/peeking-iterator/discuss/72650/10-line-C%2B%2B-and-14-line-Java-Implementation

https://leetcode.com/problems/peeking-iterator/discuss/72554/Simple-C%2B%2B-solution-(1-line-per-method)-without-extra-member-variables

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM