Facebook Pixel

1589. Maximum Sum Obtained of Any Permutation

Problem Description

You are given an array of integers nums and an array of requests. Each request requests[i] = [start_i, end_i] asks for the sum of elements from index start_i to end_i (inclusive) in the nums array. Both indices are 0-indexed.

Your task is to rearrange the elements in nums in any order (find a permutation) such that when you calculate the sum for each request and add all these sums together, you get the maximum possible total sum.

For example, if nums = [1, 2, 3] and requests = [[0, 1], [1, 2]]:

  • Request [0, 1] calculates nums[0] + nums[1]
  • Request [1, 2] calculates nums[1] + nums[2]
  • The total sum would be (nums[0] + nums[1]) + (nums[1] + nums[2])

Notice that nums[1] appears in both requests, so it contributes twice to the total sum. To maximize the result, you'd want to place the largest available number at index 1.

The key insight is that indices that appear in more requests should be assigned larger values from nums to maximize the total sum. The solution uses a difference array to count how many times each index appears across all requests, then pairs the most frequently requested indices with the largest values in nums.

Return the maximum total sum modulo 10^9 + 7.

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

Intuition

The core observation is that each index in the array contributes to the total sum based on how many requests include it. If an index appears in multiple requests, its value gets added multiple times to the final result.

Think of it this way: if index i appears in 5 different requests, then nums[i] will be added 5 times to our total sum. If another index j appears in only 1 request, then nums[j] contributes only once.

This leads to a greedy strategy: we should assign the largest values from nums to the indices that appear most frequently in requests. By pairing high-frequency indices with large values, we maximize the contribution to the total sum.

To count how many times each index appears across all requests, we can use a difference array technique. For each request [l, r], all indices from l to r appear once. Instead of incrementing each index individually (which would be inefficient), we mark +1 at the start position l and -1 at position r+1. After processing all requests, a prefix sum gives us the frequency count for each index.

Once we have the frequency counts and sort both the nums array and frequency array in ascending order, we can pair them up: the smallest frequency with the smallest value, the second smallest frequency with the second smallest value, and so on. This ensures that the indices with highest frequencies get the largest values, maximizing our total sum.

The final answer is the sum of nums[i] * frequency[i] for all indices, taken modulo 10^9 + 7.

Learn more about Greedy, Prefix Sum and Sorting patterns.

Solution Approach

The implementation follows these key steps:

Step 1: Build the Difference Array

We create a difference array d of size n (same as nums) initialized with zeros. For each request [l, r]:

  • Increment d[l] by 1 (marking the start of the range)
  • Decrement d[r + 1] by 1 if r + 1 < n (marking the end of the range)
d = [0] * n
for l, r in requests:
    d[l] += 1
    if r + 1 < n:
        d[r + 1] -= 1

Step 2: Convert Difference Array to Frequency Counts

Apply prefix sum to transform the difference array into actual frequency counts. After this step, d[i] represents how many times index i appears across all requests.

for i in range(1, n):
    d[i] += d[i - 1]

Step 3: Sort Both Arrays

Sort both nums and the frequency array d in ascending order. This prepares them for optimal pairing.

nums.sort()
d.sort()

Step 4: Calculate Maximum Sum

Pair up the sorted arrays element by element. The smallest frequency gets paired with the smallest value, ensuring the largest frequencies get the largest values. Multiply each pair and sum them up.

return sum(a * b for a, b in zip(nums, d)) % mod

The time complexity is O(n log n + m) where n is the length of nums and m is the number of requests. The sorting operations dominate the complexity. The space complexity is O(n) for the difference array.

The modulo operation 10^9 + 7 is applied at the end to prevent integer overflow and meet the problem's requirements.

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 a concrete example to understand the solution approach.

Given:

  • nums = [3, 5, 1, 2]
  • requests = [[0, 2], [1, 3], [1, 1]]

Step 1: Build the Difference Array

We start with a difference array d = [0, 0, 0, 0] (same size as nums).

Processing each request:

  • Request [0, 2]: Mark start at index 0 and end after index 2

    • d[0] += 1d = [1, 0, 0, 0]
    • d[3] -= 1d = [1, 0, 0, -1]
  • Request [1, 3]: Mark start at index 1 and end after index 3

    • d[1] += 1d = [1, 1, 0, -1]
    • Since 3 + 1 = 4 is out of bounds, we skip the decrement
  • Request [1, 1]: Mark start at index 1 and end after index 1

    • d[1] += 1d = [1, 2, 0, -1]
    • d[2] -= 1d = [1, 2, -1, -1]

Step 2: Convert to Frequency Counts via Prefix Sum

Apply prefix sum to get actual frequencies:

  • d[0] = 1 (stays the same)
  • d[1] = d[0] + d[1] = 1 + 2 = 3
  • d[2] = d[1] + d[2] = 3 + (-1) = 2
  • d[3] = d[2] + d[3] = 2 + (-1) = 1

Result: d = [1, 3, 2, 1]

This means:

  • Index 0 appears in 1 request
  • Index 1 appears in 3 requests
  • Index 2 appears in 2 requests
  • Index 3 appears in 1 request

Step 3: Sort Both Arrays

  • Sort nums: [1, 2, 3, 5]
  • Sort d: [1, 1, 2, 3]

Step 4: Calculate Maximum Sum

Pair up sorted arrays (smallest with smallest, largest with largest):

  • 1 × 1 = 1
  • 2 × 1 = 2
  • 3 × 2 = 6
  • 5 × 3 = 15

Total sum = 1 + 2 + 6 + 15 = 24

Verification: The optimal arrangement would place values as: nums = [2, 5, 3, 1]

  • Request [0, 2]: sum = 2 + 5 + 3 = 10
  • Request [1, 3]: sum = 5 + 3 + 1 = 9
  • Request [1, 1]: sum = 5

Total = 10 + 9 + 5 = 24 ✓

Solution Implementation

1class Solution:
2    def maxSumRangeQuery(self, nums: List[int], requests: List[List[int]]) -> int:
3        """
4        Calculate maximum sum after applying all range sum queries.
5        Strategy: Match highest frequency positions with largest numbers.
6      
7        Args:
8            nums: List of integers to query
9            requests: List of [left, right] range queries
10          
11        Returns:
12            Maximum possible sum modulo 10^9 + 7
13        """
14        n = len(nums)
15      
16        # Create difference array to track frequency of each index
17        # Using difference array technique for efficient range updates
18        frequency = [0] * n
19      
20        # Mark range boundaries in difference array
21        # Increment at start, decrement after end
22        for left, right in requests:
23            frequency[left] += 1
24            if right + 1 < n:
25                frequency[right + 1] -= 1
26      
27        # Convert difference array to actual frequencies using prefix sum
28        for i in range(1, n):
29            frequency[i] += frequency[i - 1]
30      
31        # Sort both arrays to match highest frequencies with largest numbers
32        nums.sort()
33        frequency.sort()
34      
35        # Calculate maximum sum by pairing sorted values
36        # Multiply each number by its frequency and sum all products
37        MOD = 10**9 + 7
38        max_sum = sum(num * freq for num, freq in zip(nums, frequency)) % MOD
39      
40        return max_sum
41
1class Solution {
2    public int maxSumRangeQuery(int[] nums, int[][] requests) {
3        int n = nums.length;
4      
5        // Create a difference array to track frequency of each index
6        int[] frequency = new int[n];
7      
8        // Apply difference array technique for each request
9        // Increment at start of range, decrement after end of range
10        for (int[] request : requests) {
11            int left = request[0];
12            int right = request[1];
13          
14            frequency[left]++;
15            if (right + 1 < n) {
16                frequency[right + 1]--;
17            }
18        }
19      
20        // Convert difference array to actual frequency counts using prefix sum
21        for (int i = 1; i < n; i++) {
22            frequency[i] += frequency[i - 1];
23        }
24      
25        // Sort both arrays to pair largest numbers with highest frequencies
26        Arrays.sort(nums);
27        Arrays.sort(frequency);
28      
29        // Calculate maximum sum by pairing sorted values
30        final int MOD = (int) 1e9 + 7;
31        long totalSum = 0;
32      
33        for (int i = 0; i < n; i++) {
34            // Multiply each number by its corresponding frequency and add to sum
35            totalSum = (totalSum + (long) nums[i] * frequency[i]) % MOD;
36        }
37      
38        return (int) totalSum;
39    }
40}
41
1class Solution {
2public:
3    int maxSumRangeQuery(vector<int>& nums, vector<vector<int>>& requests) {
4        int n = nums.size();
5      
6        // Create difference array to track frequency of each index
7        vector<int> frequency(n, 0);
8      
9        // Apply difference array technique to efficiently count overlapping ranges
10        // For each request [left, right], increment at left and decrement at right+1
11        for (const auto& request : requests) {
12            int left = request[0];
13            int right = request[1];
14            frequency[left]++;
15            if (right + 1 < n) {
16                frequency[right + 1]--;
17            }
18        }
19      
20        // Convert difference array to actual frequency count using prefix sum
21        for (int i = 1; i < n; ++i) {
22            frequency[i] += frequency[i - 1];
23        }
24      
25        // Sort nums array in ascending order
26        sort(nums.begin(), nums.end());
27      
28        // Sort frequency array in ascending order
29        sort(frequency.begin(), frequency.end());
30      
31        // Calculate maximum sum by pairing largest numbers with highest frequencies
32        long long maxSum = 0;
33        const int MOD = 1e9 + 7;
34      
35        for (int i = 0; i < n; ++i) {
36            // Multiply each number with its corresponding frequency and add to sum
37            maxSum = (maxSum + 1LL * nums[i] * frequency[i]) % MOD;
38        }
39      
40        return maxSum;
41    }
42};
43
1/**
2 * Calculates the maximum sum of all requests after optimally arranging numbers
3 * @param nums - Array of numbers to be arranged
4 * @param requests - Array of [left, right] index pairs representing query ranges
5 * @returns Maximum sum modulo 10^9 + 7
6 */
7function maxSumRangeQuery(nums: number[], requests: number[][]): number {
8    const n: number = nums.length;
9  
10    // Create frequency array to track how many times each index is queried
11    const frequency: number[] = new Array(n).fill(0);
12  
13    // Use difference array technique to efficiently count query frequencies
14    for (const [left, right] of requests) {
15        frequency[left]++;
16        if (right + 1 < n) {
17            frequency[right + 1]--;
18        }
19    }
20  
21    // Convert difference array to actual frequency counts using prefix sum
22    for (let i = 1; i < n; i++) {
23        frequency[i] += frequency[i - 1];
24    }
25  
26    // Sort numbers in ascending order
27    nums.sort((a: number, b: number) => a - b);
28  
29    // Sort frequencies in ascending order
30    frequency.sort((a: number, b: number) => a - b);
31  
32    // Calculate maximum sum by pairing largest numbers with highest frequencies
33    let maxSum: number = 0;
34    const MOD: number = 10 ** 9 + 7;
35  
36    for (let i = 0; i < n; i++) {
37        maxSum = (maxSum + nums[i] * frequency[i]) % MOD;
38    }
39  
40    return maxSum;
41}
42

Time and Space Complexity

Time Complexity: O(n × log n), where n is the length of the array nums.

The time complexity is dominated by the sorting operations:

  • Building the difference array d with requests takes O(m) time, where m is the number of requests
  • Computing the prefix sum of the difference array takes O(n) time
  • Sorting nums takes O(n × log n) time
  • Sorting the frequency array d takes O(n × log n) time
  • Computing the final sum with zip takes O(n) time

Since O(n × log n) is the largest term, the overall time complexity is O(n × log n).

Space Complexity: O(n), where n is the length of the array nums.

The space complexity comes from:

  • The difference array d of size n, which requires O(n) space
  • The sorting operations on nums and d may use O(n) additional space depending on the implementation (Python's Timsort uses up to O(n) auxiliary space)
  • The zip operation creates an iterator which uses O(1) space

Therefore, the overall space complexity is O(n).

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

Common Pitfalls

1. Forgetting to Apply Modulo Operation

Pitfall: The sum can become extremely large, potentially exceeding integer limits. Forgetting to apply the modulo operation can lead to incorrect results or overflow issues.

Wrong approach:

# Missing modulo operation
return sum(num * freq for num, freq in zip(nums, frequency))

Correct approach:

MOD = 10**9 + 7
return sum(num * freq for num, freq in zip(nums, frequency)) % MOD

2. Incorrect Difference Array Boundary Handling

Pitfall: When building the difference array, it's crucial to check if right + 1 is within bounds before decrementing. Blindly accessing frequency[right + 1] can cause an IndexError.

Wrong approach:

for left, right in requests:
    frequency[left] += 1
    frequency[right + 1] -= 1  # IndexError when right == n-1

Correct approach:

for left, right in requests:
    frequency[left] += 1
    if right + 1 < n:  # Boundary check
        frequency[right + 1] -= 1

3. Misunderstanding the Difference Array Technique

Pitfall: Some might try to increment every index in the range directly, which is inefficient and defeats the purpose of using a difference array.

Wrong approach (O(n*m) complexity):

frequency = [0] * n
for left, right in requests:
    for i in range(left, right + 1):
        frequency[i] += 1  # Inefficient

Correct approach (O(m) for updates):

frequency = [0] * n
for left, right in requests:
    frequency[left] += 1
    if right + 1 < n:
        frequency[right + 1] -= 1
# Then apply prefix sum once

4. Forgetting to Convert Difference Array to Actual Frequencies

Pitfall: After marking the boundaries in the difference array, you must apply prefix sum to get the actual frequency counts. Skipping this step will give incorrect frequencies.

Wrong approach:

# Build difference array
for left, right in requests:
    frequency[left] += 1
    if right + 1 < n:
        frequency[right + 1] -= 1

# Forgot to apply prefix sum!
nums.sort()
frequency.sort()  # This sorts the difference array, not frequencies

Correct approach:

# Build difference array
for left, right in requests:
    frequency[left] += 1
    if right + 1 < n:
        frequency[right + 1] -= 1

# Convert to actual frequencies
for i in range(1, n):
    frequency[i] += frequency[i - 1]

nums.sort()
frequency.sort()

5. Modifying Original Input Array

Pitfall: Sorting nums in-place modifies the original array, which might not be desired in some contexts or could affect test cases if the array is reused.

Solution if preserving original is needed:

nums_copy = nums.copy()  # Create a copy
nums_copy.sort()
# Use nums_copy for calculation
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Is the following code DFS or BFS?

void search(Node root) {
  if (!root) return;
  visit(root);
  root.visited = true;
  for (Node node in root.adjacent) {
    if (!node.visited) {
      search(node);
    }
  }
}

Recommended Readings

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

Load More