3574. Maximize Subarray GCD Score
Problem Description
You are given an array of positive integers nums
and an integer k
.
You may perform at most k
operations. In each operation, you can choose one element in the array and double its value. Each element can be doubled at most once.
The score of a contiguous subarray is defined as the product of its length and the greatest common divisor (GCD) of all its elements.
Your task is to return the maximum score that can be achieved by selecting a contiguous subarray from the modified array.
Note:
- The greatest common divisor (GCD) of an array is the largest integer that evenly divides all the array elements.
Intuition
Since the score depends on both the GCD of a subarray and its length, we want to find the subarray where the product of these two is maximized. Doubling an element can at most double the GCD of the subarray if that element is limiting the number of factors of 2
in the GCD. Given that each element can only be doubled once, and you can do this operation at most k
times, it's helpful to analyze the factors of 2
in each number.
By observing that the GCD can only increase by a factor of 2
based on the minimum number of 2
s that evenly divide every element, we realize that doubling elements with the lowest count of 2
factors may boost the GCD. Since the array is small, we can check every subarray, track its GCD, and see if doubling some elements will allow the GCD to increase. This guides us to consider each subarray, maintain counts of factors of 2
, and decide based on k
how to maximize the score.
Solution Approach
The solution uses enumeration and some math observation. Since n
(the array length) is up to 1500, it's feasible to check every possible contiguous subarray.
Here’s how the approach works:
-
First, for each number in
nums
, count how many times it is divisible by2
and store these counts. This tells us how many factors of2
are in each number. -
For each possible subarray
[l, r]
, calculate:- The GCD of the elements in this subarray.
- The minimum count of
2
factors among the elements within the subarray. - The number of times this minimum occurs in the subarray (how many numbers have exactly this many
2
factors).
-
If the number of elements with the minimum factor of
2
is less than or equal tok
, it means we can double all such elements and thus increase the GCD of the entire subarray by a factor of2
. Otherwise, the GCD stays the same. -
For each subarray, calculate the score: either
GCD * length
(if can't double enough numbers) orGCD * 2 * length
(if possible to double the minimum-factor numbers). -
Keep track of the highest such score as the answer.
The algorithm makes use of:
- Preprocessing to count factors of
2
in each number for quick access. - A nested loop to enumerate all subarrays.
- The built-in
gcd
function to maintain the current GCD while extending subarrays.
This way, by leveraging both mathematics (about factors of 2
and GCD) and brute-force enumeration (since the constraints are small), the solution efficiently finds the maximum achievable score.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's use the given method on a small example to see how it works in practice.
Suppose
nums = [6, 4, 10]
, k = 1
Step 1: Count factors of 2 for each element
- 6 = 2 × 3 → 1 factor of 2
- 4 = 2 × 2 → 2 factors of 2
- 10 = 2 × 5 → 1 factor of 2
So powers = [1, 2, 1]
Step 2: Enumerate all contiguous subarrays and compute their scores
Let's go through each possible subarray (for a small array):
Subarray [0,0]: [6]
- GCD = 6, Length = 1, min2 = 1, count_min2 = 1
- We can double the only element (needs 1 operation, ≤ k).
- New GCD = 12, Score = 12 × 1 = 12
Subarray [0,1]: [6,4]
- GCD = gcd(6,4) = 2, Length = 2
- min2 = min(1,2) = 1, count_min2 = 1 (just the 6)
- Number of elements with min2 (1) is 1, which is ≤ k
- If we double 6 (from 6 to 12), new GCD = gcd(12,4) = 4
- Score = 4 × 2 = 8
- Without doubling, score = 2 × 2 = 4
Subarray [1,1]: [4]
- GCD = 4, min2 = 2, count_min2 = 1
- Length = 1
- We can double 4 → 8, new GCD = 8
- Score = 8 × 1 = 8
Subarray [1,2]: [4,10]
- GCD = gcd(4,10) = 2, Length = 2
- min2 = min(2,1) = 1, count_min2 = 1 (just the 10)
- Can double 10 (from 10 to 20): gcd(4,20) = 4
- Score = 4 × 2 = 8
- Without doubling, score = 2 × 2 = 4
Subarray [2,2]: [10]
- GCD = 10, min2 = 1, count_min2 = 1
- Length = 1
- Can double 10 → 20, new GCD = 20 × 1 = 20
Subarray [0,2]: [6,4,10]
- GCD = gcd(6,4,10) = 2, Length = 3
- min2 = min(1,2,1) = 1, count_min2 = 2 (6 and 10)
- Need to double both 6 and 10 to raise all numbers to at least 2 factors of 2, but only k = 1 operation allowed.
- Cannot double enough numbers, so GCD stays at 2.
- Score = 2 × 3 = 6
Step 3: Final answer
Look for the maximal score from all options: Options: 12, 8, 8, 8, 20, 6 Maximum score = 20 (by picking [10], doubling once: 20 × 1)
This demonstrates the process in a manageable scenario.
Solution Implementation
1from math import gcd, inf
2from typing import List
3
4class Solution:
5 def maxGCDScore(self, nums: List[int], k: int) -> int:
6 n = len(nums)
7 # cnt[i] records the number of times nums[i] can be divided by 2
8 cnt = [0] * n
9 for i, num in enumerate(nums):
10 x = num
11 while x % 2 == 0:
12 cnt[i] += 1
13 x //= 2
14
15 max_score = 0
16 # Iterate all subarrays [l, r]
17 for left in range(n):
18 current_gcd = 0
19 min_cnt = inf
20 min_cnt_freq = 0
21 for right in range(left, n):
22 # Update the GCD with the new element included
23 current_gcd = gcd(current_gcd, nums[right])
24
25 # Track the minimum cnt value in the current subarray and its frequency
26 if cnt[right] < min_cnt:
27 min_cnt = cnt[right]
28 min_cnt_freq = 1
29 elif cnt[right] == min_cnt:
30 min_cnt_freq += 1
31
32 # Calculate the score based on the problem's condition
33 if min_cnt_freq > k:
34 score = current_gcd * (right - left + 1)
35 else:
36 score = current_gcd * 2 * (right - left + 1)
37 max_score = max(max_score, score)
38 return max_score
39
1class Solution {
2 public long maxGCDScore(int[] nums, int k) {
3 int n = nums.length;
4 int[] twosCount = new int[n];
5
6 // Count the number of factors of 2 for each number in nums
7 for (int i = 0; i < n; ++i) {
8 int value = nums[i];
9 while (value % 2 == 0) {
10 ++twosCount[i];
11 value /= 2;
12 }
13 }
14
15 long maxScore = 0;
16
17 // Consider all subarrays nums[l..r]
18 for (int left = 0; left < n; ++left) {
19 int currentGCD = 0;
20 int minTwosCount = Integer.MAX_VALUE;
21 int minTwosCountFrequency = 0;
22
23 for (int right = left; right < n; ++right) {
24 // Update the GCD for the current subarray
25 currentGCD = gcd(currentGCD, nums[right]);
26
27 // Track the minimum number of factors of 2 in the current window
28 if (twosCount[right] < minTwosCount) {
29 minTwosCount = twosCount[right];
30 minTwosCountFrequency = 1;
31 } else if (twosCount[right] == minTwosCount) {
32 ++minTwosCountFrequency;
33 }
34
35 // Compute score according to the problem's rule
36 // If the minimum count frequency > k, use GCD as is, else multiply by 2
37 long windowLength = right - left + 1L;
38 long currentScore = windowLength * (minTwosCountFrequency > k ? currentGCD : currentGCD * 2L);
39
40 // Track the maximum score found
41 maxScore = Math.max(maxScore, currentScore);
42 }
43 }
44 return maxScore;
45 }
46
47 // Helper method to compute greatest common divisor (GCD) via Euclidean algorithm
48 private int gcd(int a, int b) {
49 return b == 0 ? a : gcd(b, a % b);
50 }
51}
52
1#include <vector>
2#include <algorithm>
3#include <numeric>
4#include <climits>
5using namespace std;
6
7class Solution {
8public:
9 long long maxGCDScore(vector<int>& nums, int k) {
10 int n = nums.size();
11 vector<int> twosCount(n);
12
13 // Count number of factors of 2 for each element in nums.
14 for (int i = 0; i < n; ++i) {
15 int x = nums[i];
16 while (x % 2 == 0) {
17 ++twosCount[i];
18 x /= 2;
19 }
20 }
21
22 long long result = 0; // Stores the maximum score found.
23
24 // Iterate through all subarrays.
25 for (int left = 0; left < n; ++left) {
26 int currentGCD = 0; // GCD of current subarray.
27 int minTwos = INT_MAX; // Minimal count of 2's in the subarray.
28 int minCount = 0; // Frequency of the minimal count.
29
30 for (int right = left; right < n; ++right) {
31 // Update GCD of the current subarray.
32 currentGCD = gcd(currentGCD, nums[right]);
33
34 // Update minimum twos count and its frequency.
35 if (twosCount[right] < minTwos) {
36 minTwos = twosCount[right];
37 minCount = 1;
38 } else if (twosCount[right] == minTwos) {
39 ++minCount;
40 }
41
42 // Calculate score for current subarray based on rules.
43 long long length = right - left + 1;
44 long long score = (minCount > k)
45 ? length * currentGCD
46 : length * currentGCD * 2;
47
48 result = max(result, score); // Update max score found
49 }
50 }
51
52 return result;
53 }
54};
55
1/**
2 * Calculates the greatest common divisor of two numbers.
3 * @param a First number
4 * @param b Second number
5 * @returns The greatest common divisor of a and b
6 */
7function gcd(a: number, b: number): number {
8 while (b !== 0) {
9 const temp = b;
10 b = a % b;
11 a = temp;
12 }
13 return a;
14}
15
16/**
17 * Finds the maximum score based on GCD and a constraint on the count of 2's in factorization.
18 * @param nums Array of numbers
19 * @param k Integer constraint
20 * @returns The maximum score satisfying the problem requirements
21 */
22function maxGCDScore(nums: number[], k: number): number {
23 const n: number = nums.length;
24 // cnt[i] holds the number of times 2 divides nums[i]
25 const cnt: number[] = Array(n).fill(0);
26
27 // Calculate the exponent of 2 in each number's factorization
28 for (let i = 0; i < n; ++i) {
29 let x: number = nums[i];
30 while (x % 2 === 0) {
31 cnt[i]++;
32 x /= 2;
33 }
34 }
35
36 let ans: number = 0;
37
38 // Try all subarrays [l, r] and keep track for each
39 for (let l = 0; l < n; ++l) {
40 let g: number = 0; // Current GCD of subarray [l, r]
41 let minExponent: number = Number.MAX_SAFE_INTEGER; // Minimum exponent of 2 in the current subarray
42 let minCount: number = 0; // Occurrence count of minExponent in [l, r]
43 for (let r = l; r < n; ++r) {
44 g = gcd(g, nums[r]);
45 // Update the minimum exponent and its occurrence count
46 if (cnt[r] < minExponent) {
47 minExponent = cnt[r];
48 minCount = 1;
49 } else if (cnt[r] === minExponent) {
50 minCount++;
51 }
52 const len: number = r - l + 1;
53 // If the number of elements with minExponent of 2 exceeds k, use g; otherwise, use g * 2
54 const score: number = (minCount > k ? g : g * 2) * len;
55 ans = Math.max(ans, score);
56 }
57 }
58
59 return ans;
60}
61
Time and Space Complexity
The time complexity of the code is O(n^2 * log(max(nums)))
, where n
is the length of the array nums
. This arises because there are two nested loops over the range [0, n)
and [l, n)
, and within the inner loop, the greatest common divisor (gcd
) is computed, which takes O(log(max(nums)))
time per call. The outer loop for factor counting runs in O(n log(max(nums)))
time, but the quadratic nested loops with gcd
dominate.
The space complexity is O(n)
, primarily due to the auxiliary array cnt
of size n
used to count the powers of two in each number of nums
.
Which data structure is used to implement recursion?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!