Power of Heroes
HardPrompt
You are given a 0-indexed integer array nums representing the strength of some heroes. The power of a group of heroes is defined as follows:
- Let
i0,i1, ... ,ikbe the indices of the heroes in a group. Then, the power of this group ismax(nums[i0], nums[i1], ... ,nums[ik])2 * min(nums[i0], nums[i1], ... ,nums[ik]).
Return the sum of the power of all non-empty groups of heroes possible. Since the sum could be very large, return it modulo 109 + 7.
Example 1:
Input: nums = [2,1,4]
Output: 141
Explanation:
1st group: [2] has power = 22 * 2 = 8.
2nd group: [1] has power = 12 * 1 = 1.
3rd group: [4] has power = 42 * 4 = 64.
4th group: [2,1] has power = 22 * 1 = 4.
5th group: [2,4] has power = 42 * 2 = 32.
6th group: [1,4] has power = 42 * 1 = 16.
7th group: [2,1,4] has power = 42 * 1 = 16.
The sum of powers of all groups is 8 + 1 + 64 + 4 + 32 + 16 + 16 = 141.Example 2:
Input: nums = [1,1,1]
Output: 7
Explanation: A total of 7 groups are possible, and the power of each group will be 1. Therefore, the sum of the powers of all groups is 7.
Constraints:
1 <= nums.length <= 1051 <= nums[i] <= 109
Approaches
3 approaches with complexity analysis and trade-offs.
The most straightforward way to solve the problem is to generate every possible non-empty group (subset) of heroes, calculate the power for each group, and sum them up. This can be achieved by iterating through all 2^n - 1 non-empty subsets.
Algorithm
- Initialize a global variable
totalPowerto 0. - Define a recursive function, say
generateSubsets(index, currentSubset), to generate all subsets. - The function takes the current
indexin thenumsarray and thecurrentSubsetbeing built. - Base Case: When
indexreaches the end of the array, check ifcurrentSubsetis non-empty.- If it is, find its minimum and maximum elements.
- Calculate the power:
power = (max^2 * min) % MOD. - Add this
powertototalPower.
- Recursive Step: For each element
nums[index], make two recursive calls:- One call that excludes
nums[index]from the subset:generateSubsets(index + 1, currentSubset). - One call that includes
nums[index]in the subset: addnums[index]tocurrentSubset, callgenerateSubsets(index + 1, currentSubset), and then removenums[index](backtracking).
- One call that excludes
- Start the process by calling
generateSubsets(0, new ArrayList<>()). - Return
totalPower.
Walkthrough
This approach uses recursion with backtracking to explore all possible combinations of heroes. We define a helper function that builds subsets element by element. For each element in the input array nums, we decide whether to include it in the current subset or not. This creates two branches at each step, leading to 2^n total subsets. Once a complete subset is formed (i.e., we've made a decision for every hero), we check if it's non-empty. If it is, we iterate through the subset to find its minimum and maximum strength values. We then compute its power using the formula max_strength^2 * min_strength and add it to a running total. All additions are performed modulo 10^9 + 7 to prevent overflow.
class Solution { long totalPower = 0; int MOD = 1_000_000_007; public int sumOfPower(int[] nums) { List<Integer> currentSubset = new ArrayList<>(); generateSubsets(nums, 0, currentSubset); return (int) totalPower; } private void generateSubsets(int[] nums, int index, List<Integer> currentSubset) { if (index == nums.length) { if (!currentSubset.isEmpty()) { long minVal = Long.MAX_VALUE; long maxVal = Long.MIN_VALUE; for (int num : currentSubset) { minVal = Math.min(minVal, num); maxVal = Math.max(maxVal, num); } long maxSq = (maxVal * maxVal) % MOD; long power = (maxSq * minVal) % MOD; totalPower = (totalPower + power) % MOD; } return; } // Decision 1: Exclude nums[index] generateSubsets(nums, index + 1, currentSubset); // Decision 2: Include nums[index] currentSubset.add(nums[index]); generateSubsets(nums, index + 1, currentSubset); currentSubset.remove(currentSubset.size() - 1); // Backtrack }}Complexity
Time
O(n * 2^n) There are `2^n` possible subsets. For each subset, we iterate through its elements to find the minimum and maximum, which takes `O(k)` time where `k` is the subset size (up to `n`). This results in an overall time complexity of `O(n * 2^n)`.
Space
O(n) The space complexity is determined by the depth of the recursion stack, which is `O(n)`, and the space required to store the `currentSubset`, which can also be up to `O(n)`.
Trade-offs
Pros
Conceptually simple and easy to understand.
Correct for small input sizes.
Cons
Extremely inefficient due to its exponential time complexity.
Will result in a 'Time Limit Exceeded' error for the constraints specified in the problem.
A significant improvement over the brute-force approach is to first sort the array. After sorting, we can iterate through each element nums[i] and consider it as the maximum element of a subset. Then, for each such nums[i], we can iterate through all elements nums[j] with j <= i and consider them as the minimum. By fixing the minimum and maximum, we can count how many subsets satisfy these conditions and calculate their combined power.
Algorithm
- Sort the input array
numsin non-decreasing order. - Initialize
totalPower = 0. - Optionally, precompute powers of 2 modulo
10^9 + 7and store them in an array forO(1)lookup. - Use a nested loop structure:
- The outer loop iterates from
i = 0ton-1.nums[i]is treated as the maximum element of a set of subsets. - The inner loop iterates from
j = 0toi.nums[j]is treated as the minimum element.
- The outer loop iterates from
- Inside the loops, calculate the contribution for the pair
(min=nums[j], max=nums[i]):- If
j == i, the only subset is{nums[i]}. The power isnums[i]^3. Add this tototalPower. - If
j < i, the subset must containnums[i]andnums[j]. Other elements must be chosen from{nums[j+1], ..., nums[i-1]}. There arei-j-1such elements, so there are2^(i-j-1)ways to form the rest of the subset. - The contribution is
(nums[i]^2 * nums[j]) * 2^(i-j-1). Add this tototalPower.
- If
- Ensure all intermediate calculations are done modulo
10^9 + 7. - Return
totalPower.
Walkthrough
By sorting the array nums, we can systematically determine the contribution of each element. We iterate through the sorted array with an index i, fixing nums[i] as the maximum value in a group of subsets. Then, for each i, we iterate with an index j from 0 to i, fixing nums[j] as the minimum value.
When nums[i] is the max and nums[j] is the min:
- If
j == i, the subset can only be{nums[i]}. Its power isnums[i]^2 * nums[i] = nums[i]^3. - If
j < i, the subset must containnums[i]andnums[j]. The other elements of the subset must be chosen from the elements betweennums[j]andnums[i]in the sorted array, i.e., from{nums[j+1], ..., nums[i-1]}. There arei - j - 1such elements, and any subset of them can be included. This gives2^(i-j-1)possible subsets. Each of these subsets has a power ofnums[i]^2 * nums[j].
Summing these contributions over all possible pairs of i and j gives the final answer.
import java.util.Arrays; class Solution { public int sumOfPower(int[] nums) { int n = nums.length; long MOD = 1_000_000_007; Arrays.sort(nums); long totalPower = 0; // Precomputing powers of 2 is not strictly necessary but can be cleaner. // Here we calculate it on the fly for simplicity. for (int i = 0; i < n; i++) { long maxVal = nums[i]; long maxValSq = (maxVal * maxVal) % MOD; for (int j = 0; j <= i; j++) { long minVal = nums[j]; long contribution; if (i == j) { contribution = (maxValSq * minVal) % MOD; } else { long numIntermediate = i - j - 1; long numSubsets = 1; if (numIntermediate >= 0) { // Simple power calculation numSubsets = power(2, numIntermediate, MOD); } long term = (maxValSq * minVal) % MOD; contribution = (term * numSubsets) % MOD; } totalPower = (totalPower + contribution) % MOD; } } return (int) totalPower; } private long power(long base, long exp, long mod) { long res = 1; base %= mod; while (exp > 0) { if (exp % 2 == 1) res = (res * base) % mod; base = (base * base) % mod; exp /= 2; } return res; }}Complexity
Time
O(n^2) Sorting the array takes `O(n log n)`. The main work is done in the nested loops. The outer loop runs `n` times, and the inner loop runs `i+1` times, leading to a total of `1 + 2 + ... + n = O(n^2)` iterations.
Space
O(log n) or O(n) This depends on the implementation of the sorting algorithm. If an in-place sort like Heapsort is used, it's `O(log n)`. If Mergesort is used, it's `O(n)`. The algorithm itself uses constant extra space.
Trade-offs
Pros
Much more efficient than the brute-force approach.
The logic is based on a clear combinatorial argument of fixing min and max elements.
Cons
The
O(n^2)complexity is too slow for the given constraints (n <= 10^5) and will time out.
The most efficient approach builds upon the sorted array idea but optimizes the calculation using dynamic programming. The O(n^2) approach involves a nested sum that can be computed more efficiently. By identifying a recurrence relation for this inner sum, we can reduce the complexity to a single pass over the sorted array.
Algorithm
- Sort the input array
nums. - Initialize
totalPower = 0and a helper variables = 0. All calculations are modulo10^9 + 7. - Iterate through the sorted
numsarray. For each elementxinnums:- The contribution of all subsets where
xis the maximum element isx^2 * (x + s).- The
x^3part comes from the subset{x}. - The
x^2 * spart comes from the sum of powers of all subsets wherexis the max and the min is some element smaller thanx.
- The
- Add this contribution to
totalPower:totalPower = (totalPower + (x^2 * (x + s))) % MOD. - Update the helper variable
sfor the next iteration. The newsis calculated based on the oldsand the current elementx:s_new = (2 * s + x) % MOD.
- The contribution of all subsets where
- After iterating through all elements, return
totalPower.
Walkthrough
After sorting nums, we can express the total power sum as:
TotalSum = Σ (for each i from 0 to n-1) [Contribution of subsets with nums[i] as max]
The contribution for nums[i] as max is nums[i]^2 * (Σ min(S)) for all subsets S where max(S) = nums[i].
This can be broken down further. From the O(n^2) approach, we found the total sum is Σ_{i=0..n-1} (nums[i]^3 + nums[i]^2 * Σ_{j=0..i-1} (nums[j] * 2^(i-j-1))).
Let's define a DP state s_i = Σ_{j=0..i-1} (nums[j] * 2^(i-1-j)). This s_i represents the weighted sum of previous minimums needed to calculate the contribution for nums[i]. We can find a recurrence for s_i:
s_{i+1} = Σ_{j=0..i} (nums[j] * 2^(i-j)) = 2 * (Σ_{j=0..i-1} (nums[j] * 2^(i-1-j))) + nums[i] = 2 * s_i + nums[i]
This recurrence allows us to compute the necessary sum in O(1) time at each step of our iteration. We can maintain a single variable s that we update in each step.
import java.util.Arrays; class Solution { public int sumOfPower(int[] nums) { long MOD = 1_000_000_007; Arrays.sort(nums); long totalPower = 0; long s = 0; // Represents the running sum s_i for (int x : nums) { long x_long = x; // The contribution of all subsets where x is the maximum is: // (power of {x}) + (sum of powers of other subsets with max x) // This simplifies to x^3 + x^2 * s // which is x^2 * (x + s) long x_sq = (x_long * x_long) % MOD; long term = (x_long + s) % MOD; long contribution = (x_sq * term) % MOD; totalPower = (totalPower + contribution) % MOD; // Update s for the next element. The new s will be s_{i+1}. // s_new = 2 * s_old + x s = (s * 2 + x_long) % MOD; } // Ensure the result is positive return (int) ((totalPower + MOD) % MOD); }}Complexity
Time
O(n log n) Sorting the array takes `O(n log n)`. The subsequent single pass through the array to calculate the total power takes `O(n)` time. Therefore, the overall time complexity is dominated by the sort.
Space
O(log n) or O(n) The space is dominated by the sorting algorithm's requirements. The DP approach itself only uses a few variables, which is `O(1)` auxiliary space.
Trade-offs
Pros
Highly efficient with a linearithmic time complexity.
Passes all test cases within the given constraints.
Uses constant extra space (excluding the space for sorting).
Cons
The derivation of the recurrence relation is not immediately obvious and requires careful mathematical formulation.
Solutions
Solution
class Solution {public int sumOfPower(int[] nums) { final int mod = (int)1 e9 + 7; Arrays.sort(nums); long ans = 0, p = 0; for (int i = nums.length - 1; i >= 0; --i) { long x = nums[i]; ans = (ans + (x * x % mod) * x) % mod; ans = (ans + x * p % mod) % mod; p = (p * 2 + x * x % mod) % mod; } return (int)ans; }}class Solution: def sumOfPower(self, nums: List[int]) -> int: mod = 10 ** 9 + 7 nums . sort() ans = 0 p = 0 for x in nums[:: - 1]: ans = (ans + (x * x % mod) * x) % mod ans = (ans + x * p) % mod p = (p * 2 + x * x) % mod return ansclass Solution {public: int sumOfPower(vector<int> &nums) { const int mod = 1e9 + 7; sort(nums.rbegin(), nums.rend()); long long ans = 0, p = 0; for (long long x : nums) { ans = (ans + (x * x % mod) * x) % mod; ans = (ans + x * p % mod) % mod; p = (p * 2 + x * x % mod) % mod; } return ans; }};Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.