{x}
blog image

Zigzag Iterator

Solution Explanation

This problem requires designing an iterator that traverses two input vectors (v1 and v2) in a zigzag manner. The solution uses a simple approach for two vectors, and the follow-up question hints at a more generalized solution for k vectors. Let's break down the solution for two vectors:

Approach:

The core idea is to maintain two pointers (index1 and index2), one for each vector, and a boolean flag to alternate between the vectors. Each call to next() returns the next element from the currently selected vector and advances its corresponding pointer. The hasNext() method checks if there are any remaining elements in either vector.

Time Complexity Analysis:

  • __init__ / constructor: O(1) - Initialization takes constant time regardless of the input vector sizes.
  • next(): O(1) - Accessing and returning an element from a list is a constant time operation.
  • hasNext(): O(1) - In the worst case, it checks both vectors once to determine if any elements remain.

Space Complexity Analysis:

The space complexity is O(1) because the solution uses a constant amount of extra space to store the pointers, flags, and the current vector index. The space used by the input vectors is not considered in the space complexity analysis.

Code Explanation (Python):

The Python solution uses a class ZigzagIterator to encapsulate the iterator's state.

class ZigzagIterator:
    def __init__(self, v1: List[int], v2: List[int]):
        self.cur = 0  # Index to switch between v1 and v2
        self.size = 2 # Number of vectors
        self.indexes = [0] * self.size # Keeps track of current index in each vector
        self.vectors = [v1, v2] # Stores both vectors
 
    def next(self) -> int:
        vector = self.vectors[self.cur] #Selects current vector
        index = self.indexes[self.cur] #Selects current index
        res = vector[index] #Gets the element at index
        self.indexes[self.cur] = index + 1 #Updates the index
        self.cur = (self.cur + 1) % self.size #Switch to next vector
        return res
 
    def hasNext(self) -> bool:
        start = self.cur #Stores the initial vector
        while self.indexes[self.cur] == len(self.vectors[self.cur]): #Checks if current vector is empty
            self.cur = (self.cur + 1) % self.size # Switch to next vector
            if self.cur == start: #Checks if it went through all vectors once.
                return False #if it did, no more elements left
        return True # otherwise there are elements left

Java Code Explanation:

The Java code mirrors the Python implementation closely, using an ArrayList to manage the vectors and indices. The logic for next() and hasNext() remains the same.

Rust Code Explanation:

The Rust code utilizes a struct ZigzagIterator to manage the vectors. Instead of maintaining separate indices, it directly uses the .remove(0) method to pop the elements from the vectors. This simplifies the logic somewhat but might be slightly less efficient than maintaining explicit indices. A boolean flag is used to switch between the two vectors.

Follow-up (k vectors):

For the follow-up question (k vectors), a more robust approach would be to use a priority queue or a similar data structure to efficiently track the next element from each vector. The priority queue would need to be ordered based on the index of the next element in each vector, ensuring a cyclical traversal across all k vectors. This solution's complexity would be slightly higher but generalizes better.