Facebook Pixel

2640. Find the Score of All Prefixes of an Array

Problem Description

You are given a 0-indexed integer array nums of length n. The problem asks you to understand two concepts and then compute a result based on them.

First, let's understand the conversion array. For any array arr, its conversion array conver is defined such that each element at position i equals:

  • conver[i] = arr[i] + max(arr[0..i])

Where max(arr[0..i]) represents the maximum value among all elements from index 0 to index i (inclusive).

For example, if arr = [2, 1, 3]:

  • conver[0] = 2 + max([2]) = 2 + 2 = 4
  • conver[1] = 1 + max([2, 1]) = 1 + 2 = 3
  • conver[2] = 3 + max([2, 1, 3]) = 3 + 3 = 6

Second, the score of an array is defined as the sum of all values in its conversion array. Using the example above, the score would be 4 + 3 + 6 = 13.

Your task is to return an array ans where each ans[i] represents the score of the prefix nums[0..i]. In other words:

  • ans[0] is the score of the subarray containing just nums[0]
  • ans[1] is the score of the subarray nums[0..1]
  • ans[2] is the score of the subarray nums[0..2]
  • And so on...

Each element in the answer array represents the cumulative score calculation up to that index, where the score at each position considers the conversion array values accumulated so far.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

Let's think about what happens when we compute the score for each prefix. For the prefix ending at index i, we need to calculate the conversion array and then sum it up.

The key observation is that when we move from prefix nums[0..i-1] to prefix nums[0..i], we're adding one more element to our consideration. The score of nums[0..i] equals the score of nums[0..i-1] plus the conversion value at index i.

What's the conversion value at index i? It's nums[i] + max(nums[0..i]).

Now, here's the crucial insight: we don't need to recalculate everything from scratch for each prefix. As we iterate through the array, we can:

  1. Keep track of the maximum value seen so far (let's call it mx)
  2. Calculate the conversion value for the current position as nums[i] + mx
  3. Add this to the running score

This means ans[i] = ans[i-1] + nums[i] + mx, where mx is continuously updated to be the maximum of all elements from index 0 to i.

The beauty of this approach is that we're building our answer incrementally. Each new score is just the previous score plus the new conversion value. We don't need to store the entire conversion array or recalculate sums - we just maintain:

  • The running maximum (mx)
  • The cumulative score up to each position

This transforms what could be an O(n²) problem (recalculating max and sum for each prefix) into an O(n) solution with a single pass through the array.

Learn more about Prefix Sum patterns.

Solution Approach

The solution uses a prefix sum technique with a running maximum to efficiently compute the scores.

Here's the step-by-step implementation:

  1. Initialize variables:

    • Create an answer array ans of length n to store the scores
    • Initialize mx = 0 to track the maximum value seen so far
  2. Single pass iteration: For each element nums[i] in the array:

    a. Update the maximum:

    • mx = max(mx, nums[i])
    • This ensures mx always holds the maximum value from nums[0] to nums[i]

    b. Calculate the current score:

    • The conversion value at position i is nums[i] + mx
    • If i = 0, this is our first element, so ans[0] = nums[0] + mx
    • If i > 0, we add the conversion value to the previous score: ans[i] = nums[i] + mx + ans[i-1]
  3. Return the result:

    • The array ans now contains the scores for all prefixes

The key formula being applied is:

ans[i] = nums[i] + mx + ans[i-1]  (for i > 0)
ans[0] = nums[0] + mx             (for i = 0)

This approach cleverly uses the fact that each prefix score builds upon the previous one, eliminating the need to recalculate the entire conversion array and its sum for each prefix. The time complexity is O(n) with a single pass, and space complexity is O(n) for storing the answer array.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with nums = [1, 4, 2, 3].

We'll track:

  • mx: the running maximum
  • ans[i]: the score for prefix nums[0..i]

Initial state:

  • mx = 0
  • ans = [?, ?, ?, ?]

Step 1: Process nums[0] = 1

  • Update maximum: mx = max(0, 1) = 1
  • Calculate conversion value: 1 + 1 = 2
  • Since this is the first element: ans[0] = 2
  • ans = [2, ?, ?, ?]

Step 2: Process nums[1] = 4

  • Update maximum: mx = max(1, 4) = 4
  • Calculate conversion value: 4 + 4 = 8
  • Add to previous score: ans[1] = ans[0] + 8 = 2 + 8 = 10
  • ans = [2, 10, ?, ?]

Step 3: Process nums[2] = 2

  • Update maximum: mx = max(4, 2) = 4 (no change)
  • Calculate conversion value: 2 + 4 = 6
  • Add to previous score: ans[2] = ans[1] + 6 = 10 + 6 = 16
  • ans = [2, 10, 16, ?]

Step 4: Process nums[3] = 3

  • Update maximum: mx = max(4, 3) = 4 (no change)
  • Calculate conversion value: 3 + 4 = 7
  • Add to previous score: ans[3] = ans[2] + 7 = 16 + 7 = 23
  • ans = [2, 10, 16, 23]

Verification: Let's verify ans[2] = 16 represents the score of prefix [1, 4, 2]:

  • Conversion array: [1+1=2, 4+4=8, 2+4=6]
  • Score: 2 + 8 + 6 = 16

The final answer is [2, 10, 16, 23].

Solution Implementation

1class Solution:
2    def findPrefixScore(self, nums: List[int]) -> List[int]:
3        """
4        Calculate the prefix score array where each element is the sum of:
5        - The current number
6        - The maximum value seen so far
7        - The previous prefix score (cumulative sum)
8      
9        Args:
10            nums: List of integers
11          
12        Returns:
13            List of prefix scores
14        """
15        n = len(nums)
16        result = [0] * n  # Initialize result array with zeros
17        max_so_far = 0    # Track the maximum value seen up to current position
18      
19        for i, current_num in enumerate(nums):
20            # Update the maximum value seen so far
21            max_so_far = max(max_so_far, current_num)
22          
23            # Calculate prefix score for current position:
24            # current_num + max_so_far + previous_prefix_score
25            if i == 0:
26                # First element: no previous prefix score
27                result[i] = current_num + max_so_far
28            else:
29                # Add previous prefix score to current calculation
30                result[i] = current_num + max_so_far + result[i - 1]
31      
32        return result
33
1class Solution {
2    /**
3     * Calculates the prefix score array where each element is the cumulative sum
4     * of conversion values. The conversion value at index i is nums[i] plus
5     * the maximum element seen so far from index 0 to i.
6     * 
7     * @param nums Input integer array
8     * @return Array containing cumulative prefix scores
9     */
10    public long[] findPrefixScore(int[] nums) {
11        int arrayLength = nums.length;
12        long[] prefixScores = new long[arrayLength];
13        int maxValueSoFar = 0;
14      
15        for (int i = 0; i < arrayLength; i++) {
16            // Update the maximum value encountered up to current index
17            maxValueSoFar = Math.max(maxValueSoFar, nums[i]);
18          
19            // Calculate conversion value: current element + max value so far
20            long conversionValue = nums[i] + maxValueSoFar;
21          
22            // Calculate prefix score: add conversion value to previous prefix score
23            if (i == 0) {
24                prefixScores[i] = conversionValue;
25            } else {
26                prefixScores[i] = conversionValue + prefixScores[i - 1];
27            }
28        }
29      
30        return prefixScores;
31    }
32}
33
1class Solution {
2public:
3    vector<long long> findPrefixScore(vector<int>& nums) {
4        int n = nums.size();
5        vector<long long> prefixScores(n);
6        int maxSoFar = 0;
7      
8        // Calculate prefix scores where each element's conversion value is:
9        // nums[i] + max(nums[0...i])
10        // The prefix score at index i is the sum of all conversion values from 0 to i
11        for (int i = 0; i < n; ++i) {
12            // Update the maximum element seen so far
13            maxSoFar = max(maxSoFar, nums[i]);
14          
15            // Calculate conversion value for current element
16            long long conversionValue = nums[i] + maxSoFar;
17          
18            // Calculate prefix score:
19            // - For first element (i == 0): just the conversion value
20            // - For other elements: previous prefix score + current conversion value
21            if (i == 0) {
22                prefixScores[i] = conversionValue;
23            } else {
24                prefixScores[i] = prefixScores[i - 1] + conversionValue;
25            }
26        }
27      
28        return prefixScores;
29    }
30};
31
1/**
2 * Calculates the prefix score array where each element is the sum of:
3 * - The current element
4 * - The maximum element seen so far
5 * - The previous prefix score (cumulative sum)
6 * 
7 * @param nums - Input array of numbers
8 * @returns Array where each element represents the cumulative prefix score
9 */
10function findPrefixScore(nums: number[]): number[] {
11    const arrayLength: number = nums.length;
12    const prefixScores: number[] = new Array(arrayLength);
13    let maxValueSoFar: number = 0;
14  
15    for (let index = 0; index < arrayLength; index++) {
16        // Update the maximum value encountered up to current index
17        maxValueSoFar = Math.max(maxValueSoFar, nums[index]);
18      
19        // Calculate prefix score:
20        // Current element + max value so far + previous cumulative score
21        const previousScore: number = index === 0 ? 0 : prefixScores[index - 1];
22        prefixScores[index] = nums[index] + maxValueSoFar + previousScore;
23    }
24  
25    return prefixScores;
26}
27

Time and Space Complexity

The time complexity is O(n), where n is the length of the array nums. The algorithm iterates through the array exactly once with a single for loop, performing constant-time operations (comparison, addition, and array access) at each iteration.

The space complexity is O(1) if we ignore the space consumption of the answer array ans. The only extra space used is for the variables n, mx, i, and x, which are all constant space. The answer array ans of size n is required for the output and is typically not counted in space complexity analysis for problems that require returning a result array.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrect Maximum Value Initialization

A common mistake is initializing max_so_far with the first element of the array (nums[0]) or with float('-inf'). This can lead to incorrect calculations, especially when dealing with negative numbers.

Incorrect approach:

max_so_far = nums[0]  # Wrong! This skips processing the first element properly
for i in range(len(nums)):
    max_so_far = max(max_so_far, nums[i])
    # ...

Why it's wrong: When processing nums[0], we need max_so_far to be updated after comparing with nums[0]. If we initialize with nums[0], we're essentially pre-computing the maximum for the first element.

Correct approach:

max_so_far = 0  # Start with 0 or handle the first element separately
for i in range(len(nums)):
    max_so_far = max(max_so_far, nums[i])
    # Now max_so_far correctly represents max(nums[0..i])

2. Misunderstanding the Conversion Array Calculation

Some might incorrectly calculate the conversion value by using the maximum before including the current element:

Incorrect approach:

for i in range(len(nums)):
    if i == 0:
        result[i] = nums[i] + nums[i]  # Correct by coincidence
    else:
        result[i] = nums[i] + max_so_far + result[i-1]
    max_so_far = max(max_so_far, nums[i])  # Updated AFTER use - wrong!

Why it's wrong: The conversion array at position i should use max(nums[0..i]) which includes nums[i]. Updating the maximum after using it means we're using max(nums[0..i-1]) instead.

Correct approach:

for i in range(len(nums)):
    max_so_far = max(max_so_far, nums[i])  # Update FIRST
    # Then use the updated max_so_far
    if i == 0:
        result[i] = nums[i] + max_so_far
    else:
        result[i] = nums[i] + max_so_far + result[i-1]

3. Confusion Between Score and Conversion Array

A critical misunderstanding is thinking that ans[i] should be the conversion value at position i rather than the cumulative score up to position i.

Incorrect interpretation:

# Wrong: This just calculates the conversion array, not the prefix scores
for i in range(len(nums)):
    max_so_far = max(max_so_far, nums[i])
    result[i] = nums[i] + max_so_far  # Missing cumulative sum!

Correct interpretation:

# Correct: Each ans[i] is the SUM of all conversion values from 0 to i
for i in range(len(nums)):
    max_so_far = max(max_so_far, nums[i])
    conversion_value = nums[i] + max_so_far
    if i == 0:
        result[i] = conversion_value
    else:
        result[i] = result[i-1] + conversion_value  # Cumulative sum

4. Edge Case Handling with Empty or Single-Element Arrays

While the problem states the array has length n, it's good practice to handle edge cases:

Robust solution:

def findPrefixScore(self, nums: List[int]) -> List[int]:
    if not nums:  # Handle empty array
        return []
  
    n = len(nums)
    result = [0] * n
    max_so_far = 0
  
    for i in range(n):
        max_so_far = max(max_so_far, nums[i])
        if i == 0:
            result[i] = nums[i] + max_so_far
        else:
            result[i] = nums[i] + max_so_far + result[i-1]
  
    return result
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the following is a good use case for backtracking?


Recommended Readings

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

Load More