Facebook Pixel

3574. Maximize Subarray GCD Score

HardArrayMathEnumerationNumber Theory
Leetcode Link

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.
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 2s 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 by 2 and store these counts. This tells us how many factors of 2 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 to k, it means we can double all such elements and thus increase the GCD of the entire subarray by a factor of 2. Otherwise, the GCD stays the same.

  • For each subarray, calculate the score: either GCD * length (if can't double enough numbers) or GCD * 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 Evaluator

Example 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.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement recursion?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More