Skip to main content

Find Product Of Element Of Big Array (LeetCode)

Problem Statement:​

A powerful array for an integer x is the shortest sorted array of powers of two that sum up to x. For example, the powerful array for 11 is [1, 2, 8].

The array big_nums is created by concatenating the powerful arrays for every positive integer i in ascending order: 1, 2, 3, and so forth. Thus, big_nums starts as [1, 2, 1, 2, 4, 1, 4, 2, 4, 1, 2, 4, 8, ...].

You are given a 2D integer matrix queries, where for queries[i] = [fromi, toi, modi] you should calculate (big_nums[fromi] * big_nums[fromi + 1] * ... * big_nums[toi]) % modi.

Return an integer array answer such that answer[i] is the answer to the ith query.

Example 1:

Input: queries = [[1,3,7]] Output: [4]

Explanation: There is one query. big_nums[1..3] = [2,1,2]. The product of them is 4. The remainder of 4 under 7 is 4.

Example 2:

Input: queries = [[2,5,3],[7,7,4]] Output: [2,2]

Explanation: There are two queries. First query: big_nums[2..5] = [1,2,4,1]. The product of them is 8. The remainder of 8 under 3 is 2. Second query: big_nums[7] = 2. The remainder of 2 under 4 is 2.

Constraints:

  • 1 <= queries.length <= 500
  • queries[i].length == 3
  • 0 <= queries[i][0] <= queries[i][1] <= 1015
  • 1 <= queries[i][2] <= 105

Solutions:​

Intuition​

The problem requires finding products of elements within a certain range modulo a given number. To efficiently solve this problem, we can use dynamic programming to calculate the number of bits required to represent a number, perform binary search to find the maximum number within a given range, and calculate the summation of bits within the range.

Approach​

Dynamic Programming for Number of Bits:

Utilize dynamic programming to calculate the number of bits required to represent a number. Store the calculated number of bits for each number in a map to avoid redundant computations.

Binary Search for Maximum Number:

Perform a binary search to find the maximum number within a given range. Utilize the previously calculated number of bits to determine if a number falls within the range.

Summation of Bits:

Calculate the summation of bits within a given range. Iterate through each bit position, calculating the contribution of ones in complete blocks and any remaining bits.

Main Function to Compute Result:

Combine the above calculations to compute the final result for a given range. Calculate the sum of bits within the range and adjust for any remaining bits.

Power Function and Modular Arithmetic:

Compute the result for each query using the previously defined functions. Utilize a power function to efficiently compute powers modulo the given number.

code:​

Written by @Ajay-Dhangar
#include <vector>
#include <unordered_map>
using namespace std;

class Solution {
private:
unordered_map<long long, long long> dp;

long long power(long long n, long long expo, long long mod) {
long long ans = 1;
while (expo) {
if (expo % 2)
ans = ans * n % mod;
n = n * n % mod;
expo /= 2;
}
return ans;
}

long long getNumBits(long long n) {
if (n == 0)
return 0;

if (dp.count(n))
return dp[n];

long long ans = 0, num = n + 1;
for (int i = 60; i >= 0; i--)
if ((1LL << i) < num) {
ans = getNumBits((1LL << i) - 1);
long long rem = num - (1LL << i);
ans += getNumBits(rem - 1) + rem;
break;
}
return dp[n] = ans;
}

long long getMaxNum(long long n) {
long long left = 1, right = 1e15, ans = 0;
while (left <= right) {
long long mid = (left + right) / 2;
long long placesOccupied = getNumBits(mid);
if (placesOccupied <= n)
ans = mid, left = mid + 1;
else
right = mid - 1;
}
return ans;
}

long long getSum(long long n) {
long long res = 0;
for (int i = 1; i < 50; i++) {
long long blockSize = (1LL << (i + 1));
long long onesInBlock = blockSize / 2;
long long completeBlocks = n / blockSize;
res += completeBlocks * onesInBlock * i;
long long rem = n % blockSize;
res += max(0LL, rem + 1 - onesInBlock) * i;
}
return res;
}

long long func(long long n) {
if (n == 0)
return 0;

long long maxNum = getMaxNum(n);
long long placesOccupied = getNumBits(maxNum);
long long ans = getSum(maxNum);
maxNum++;
long long rem = n - placesOccupied;
for (int i = 0; rem > 0; i++)
if (maxNum & (1LL << i)) {
rem--;
ans += i;
}
return ans;
}

int solve(vector<long long> &query) {
long long L = query[0], R = query[1], mod = query[2];
return power(2, func(R + 1) - func(L), mod) % mod;
}
public:
vector<int> findProductsOfElements(vector<vector<long long>>& queries) {
vector<int> res;
for (auto q: queries)
res.push_back(solve(q));
return res;
}
};

Complexity:​

Time complexity: O(QlogN)O(QlogN), where Q is the number of queries and N is the maximum number in the queries.

Space complexity: O(logN)O(logN), due to dynamic programming and additional space for storing intermediate results.

Video lecture​