Google Interview Question
SDE1sTeam: GFS
Country: United States
Interview Type: Phone Interview
Since tmp refers the same object, calling CPeekIterator.Peek causes advancing in currIt and correspondingly it works as a regular Next().
A right solution for this is to have an internal var that contains current element:
private CIterator iter;
private int current;
public CPeekIterator(CIterator inputIter)
{
this.iter = inputIter;
this.current = int.MinValue;
}
public int Next()
{
return this.current = this.iter.Next();
}
public int Peek()
{
return this.current;
}
as it was a phone interview, I think the interviewer wanted to hear that to implement Peek() method we should just take Next() method and eliminate the line "counter++;" from it.
No I am sure the answer is to copy the CIterator to another instance, use it's Next() method and then discard it.
No. We have get peek by using only HasNext and Next function only. We don't have control on CIterator class
If we could modify the existing code in Iterator, we wouldn't need the 2nd class :-)
What the interviewer is expecting is that for you to put a 'wrapper' class on top of CIterator. E.g. you can read the 'next' and 'peek' element on initialization, and then advance them both on each 'next()' request, or you can have two CIterator classes inside, and advance one ahead of the other (ugly, but easier to implement) etc...
but the variant «to read the 'next' and 'peek' element on initialization, and then advance them both on each 'next()' request» is bad.
Imagine, you have 1 billion elements in collection. When your iterator will point to last element, the Peek() method will work as follows:
1) invoke Next() method;
2) invoke First() method;
3) in loop invoke Next() method (1 billion - 1) times.
Moreover, in the initial task there is no method "First()", so if it is really is not allowed then the variant with copying constructor in CIterator is the only one variant.
If it is possible to augment all methods in CPeekIterator , CIterator could be wrapped in the follwowing way.
public class CPeekIterator {
CIterator it;
int peekVal ;
boolean hasNext;
public CPeekIterator(CIterator it) {
this.it = it;
hasNext = it.hasNext();
peekVal = it.next();
}
int next() {
int temp = peekVal;
peekVal = next;
return temp;
}
int peek() {
return peekVal;
}
boolean hasNext() {
int temp = hasNext;
hasNext = it.next();
return temp;
}
}
Added some correction on code:
public class CPeekIterator {
CIterator it;
int peekVal ;
boolean hasNext;
public CPeekIterator(CIterator it) {
this.it = it;
hasNext = it.hasNext();
peekVal = it.next();
}
int next() {
int temp = peekVal;
peekVal = it.next();
return temp;
}
int peek() {
return peekVal;
}
boolean hasNext() {
boolean temp = hasNext;
hasNext = it.hasNext();
return temp;
}
}
Provided before executing Next() or Peek(), you will check HasNext()
class CPeekIterator : CIterator
{
public:
CPeekIterator() : nextVal(false)
{
}
virtual int Next()
{
if(hasNext)
{
hasNext = false;
return nextVal;
}
return CIterator::Next();
}
virtual int peek()
{
if(!hasNext)
{
hasNext = true;
nextVal = CIterator::next();
}
return nextVal;
}
virtual int HasNext() const
{
return hasNext ? true : CIterator::HasNext();
}
private:
int nextVal;
bool hasNext;
};
public class CIterator
{
int[] items;
int index = 0;
public CIterator(int[] items)
{
this.items = items;
}
public int Next()
{
if (!HasNext())
throw new InvalidOperationException();
return items[index++];
}
public bool HasNext()
{
return index < items.Length;
}
}
public class CPeekIterator
{
private CIterator iterator;
private bool prevAdvanced = false;
private int peek;
private bool hasNext;
public CPeekIterator(CIterator iterator)
{
this.iterator = iterator;
}
public int Next()
{
if (prevAdvanced)
{
prevAdvanced = false;
return this.peek;
}
return iterator.Next();
}
public bool HasNext()
{
if (prevAdvanced)
return this.hasNext;
return iterator.HasNext();
}
public int Peek()
{
if (prevAdvanced)
return this.peek;
this.hasNext = iterator.HasNext();
this.prevAdvanced = true;
this.peek = iterator.Next();
return this.peek;
}
}
Class Citerator {
Int Next();
Boolean hasNext();
}
Class CPeekIterator {
Int Next();
Boolean hasNext();
Int Peek();
Citerator it;
Int curr;
int lastCall = -1; // 0 for peek, 1 for next
Boolean hasNext() {
If (it.hasNext())
Return true;
Else {
If (lastCall == 1)
Return false;
If (lastCall == 0)
Return true;
If (lastCall == -1)
Return false;
}
}
Int Peek() {
If (lastCall == -1) {
If (it.hasNext())
Curr = it.next();
Else
Curr = -1;
lastCall = 0;
Return curr;
}
Else If (lastCall == 0)
Return curr;
Else {
If (it.hasNext())
Curr = it.next();
Else
Curr = -1;
lastCall = 0;
Return curr;
}
}
Int Next() {
If (lastCall == -1) {
lastCall = 1;
If (it.hasNext())
Return it.next();
Return -1;
}
Else If (lastCall == 0) {
lastCall = 1;
Return Curr;
}
Else {
If (it.hasNext())
Return it.next();
Return -1;
}
}
}
// Time: O(1) per peek(), next(), hasNext()
// Space: O(1)
// Below is the interface for Iterator, which is already defined for you.
// **DO NOT** modify the interface for Iterator.
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), has_next_(Iterator::hasNext()) {
// Initialize any member here.
// **DO NOT** save a copy of nums and manipulate it directly.
// You should only use the Iterator interface methods.
}
// Returns the next element in the iteration without advancing the iterator.
int peek() {
if (!has_peeked_) {
has_peeked_ = true;
val_ = Iterator::next();
}
return val_;
}
// hasNext() and next() should behave the same as in the Iterator interface.
// Override them if needed.
int next() {
val_ = peek();
has_peeked_ = false;
has_next_ = Iterator::hasNext();
return val_;
}
bool hasNext() const {
return has_next_;
}
private:
int val_;
bool has_next_;
bool has_peeked_ = false;
};
Since Next() and HasNext() methods are exactly the same for CPeekIterator as for CIterator, we just duplicate them without any changes.
The only difference in CPeekIterator is that Peek() needs to return next value without advancing the iterator. Solution is to store CIterator inside CPeekIterator and in case of Peek() create a temporary iterator. It will return next value, but advancing is not important, since it's temporary value.
- marut December 08, 2015