Design an algorithm that accepts a stream of integers and retrieves the product of the last k
integers of the stream.
Implement the ProductOfNumbers
class:
ProductOfNumbers()
Initializes the object with an empty stream.void add(int num)
Appends the integer num
to the stream.int getProduct(int k)
Returns the product of the last k
numbers in the current list. You can assume that always the current list has at least k
numbers.The test cases are generated so that, at any time, the product of any contiguous sequence of numbers will fit into a single 32-bit integer without overflowing.
Example:
Input ["ProductOfNumbers","add","add","add","add","add","getProduct","getProduct","getProduct","add","getProduct"] [[],[3],[0],[2],[5],[4],[2],[3],[4],[8],[2]] Output [null,null,null,null,null,null,20,40,0,null,32] Explanation ProductOfNumbers productOfNumbers = new ProductOfNumbers(); productOfNumbers.add(3); // [3] productOfNumbers.add(0); // [3,0] productOfNumbers.add(2); // [3,0,2] productOfNumbers.add(5); // [3,0,2,5] productOfNumbers.add(4); // [3,0,2,5,4] productOfNumbers.getProduct(2); // return 20. The product of the last 2 numbers is 5 * 4 = 20 productOfNumbers.getProduct(3); // return 40. The product of the last 3 numbers is 2 * 5 * 4 = 40 productOfNumbers.getProduct(4); // return 0. The product of the last 4 numbers is 0 * 2 * 5 * 4 = 0 productOfNumbers.add(8); // [3,0,2,5,4,8] productOfNumbers.getProduct(2); // return 32. The product of the last 2 numbers is 4 * 8 = 32
Constraints:
0 <= num <= 100
1 <= k <= 4 * 104
4 * 104
calls will be made to add
and getProduct
.Follow-up: Can you implement both
GetProduct
and Add
to work in O(1)
time complexity instead of O(k)
time complexity?This problem requires designing a data structure that efficiently handles adding numbers to a stream and retrieving the product of the last k
numbers. A naive approach using a list and iterating for each getProduct
call would result in a time complexity of O(k) for getProduct
, which is inefficient for large k
values. The optimal solution leverages prefix products to achieve O(1) time complexity for both add
and getProduct
operations.
The core idea is to maintain a prefix product array. This array, let's call it prefix_products
, stores the cumulative product of numbers added to the stream so far. prefix_products[i]
will represent the product of all numbers from index 0 up to index i
.
Initialization: The prefix_products
array is initialized with 1
.
add(num)
:
num
is 0, we reset prefix_products
to [1]
because any product involving 0 will be 0.prefix_products
and num
to the array. This efficiently updates the prefix product.getProduct(k)
:
prefix_products
is less than or equal to k
, it means there are not enough numbers in the stream to calculate the product of the last k
numbers; we return 0.k
numbers can be calculated using the prefix products: prefix_products[-1] / prefix_products[-k-1]
. This is because prefix_products[-1]
contains the product of all numbers up to the current last number and prefix_products[-k-1]
contains the product of all numbers up to the k+1
th number from the end. Dividing them gives the product of the last k numbers.add(num)
: O(1) - Constant time operation; appending to the array and multiplication are constant time.getProduct(k)
: O(1) - Constant time operation; array access and division are constant time.The provided code examples in various languages implement this prefix product approach. Each example demonstrates the ProductOfNumbers
class with the add
and getProduct
methods. The comments within the code further explain the logic. Note the handling of the zero case and efficient calculation of the product using prefix product array.