Katkat

Design compressed vector and compute dot product

GoogleSoftware Engineer · Onsite

Last updated

This problem tests your ability to design a memory-efficient data structure for sparse or repetitive vector data and implement an arithmetic operation without fully decompressing the representation.

Compressed Vector Dot Product

Many real-world vectors are sparse or contain long sequences of identical values. Instead of storing a full array of size N, we can represent a vector as a list of pairs (value, count), where count is the number of times value repeats consecutively.

Task

Design a class CompressedVector that stores a vector in this format. Then, implement a method dot_product(vec1, vec2) that computes the dot product of two CompressedVector objects.

Interface

class CompressedVector:
    def __init__(self, data: list[tuple[int, int]]):
        # data is a list of (value, count) pairs
        self.data = data

def dot_product(vec1: CompressedVector, vec2: CompressedVector) -> int:
    # Returns the dot product of the two vectors

Constraints

  • Each vector may contain up to 10^6 elements, but the number of (value, count) pairs is significantly smaller (e.g., 10^3).
  • Values are integers.
  • Ensure your solution handles cases where the runs in vec1 and vec2 have different boundaries.

Examples

Example 1:

  • vec1: [(1, 2), (3, 1)] (represents [1, 1, 3])
  • vec2: [(2, 1), (1, 2)] (represents [2, 1, 1])
  • Result: (1*2) + (1*1) + (3*1) = 6

Example 2:

  • vec1: [(5, 10)] (represents 10 fives)
  • vec2: [(2, 5), (3, 5)] (represents 5 twos followed by 5 threes)
  • Result: (5*2)*5 + (5*3)*5 = 50 + 75 = 125

Hints

Hint 1

Use two pointers to traverse the runs of both vectors simultaneously, keeping track of the current position or remaining count in each run.

Hint 2

In each step of the iteration, identify the 'min' of the remaining counts of the current runs to process a overlapping segment of length `k`.

Hint 3

Multiply the two current values and multiply by the overlapping segment length `k`, then update the remaining counts and move to the next run if a count hits zero.

Follow-up questions

  • How would you modify the data structure if you needed to support efficient random access (e.g., get element at index i)?
  • What is the time complexity of your dot product algorithm in terms of the number of compressed segments (M and K) rather than the original vector length (N)?
  • How would you handle potential integer overflows if the dot product exceeds the capacity of a 32-bit integer?