Sum of Subsequence Widths
HardPrompt
The width of a sequence is the difference between the maximum and minimum elements in the sequence.
Given an array of integers nums, return the sum of the widths of all the non-empty subsequences of nums. Since the answer may be very large, return it modulo 109 + 7.
A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7].
Example 1:
Input: nums = [2,1,3]
Output: 6
Explanation: The subsequences are [1], [2], [3], [2,1], [2,3], [1,3], [2,1,3].
The corresponding widths are 0, 0, 0, 1, 1, 2, 2.
The sum of these widths is 6.Example 2:
Input: nums = [2]
Output: 0
Constraints:
1 <= nums.length <= 1051 <= nums[i] <= 105
Approaches
3 approaches with complexity analysis and trade-offs.
This approach involves generating every possible non-empty subsequence of the given array. For each subsequence, we find its maximum and minimum elements, calculate the width (max - min), and add it to a running total. This is the most straightforward but also the most inefficient method, as the number of subsequences grows exponentially with the size of the input array.
Algorithm
- Initialize a global variable
totalWidthto 0. - Create a recursive function, say
findSubsequences(index, currentSubsequence), to generate all subsequences. - Base Case: When the
indexreaches the end of the array:- If the
currentSubsequenceis not empty, find its minimum and maximum elements. - Calculate the width (
max - min). - Add the width to
totalWidth, taking modulo10^9 + 7. - Return.
- If the
- Recursive Step: For each element
nums[index], make two recursive calls:- One call that excludes
nums[index]from the subsequence:findSubsequences(index + 1, currentSubsequence). - One call that includes
nums[index]: addnums[index]tocurrentSubsequence, callfindSubsequences(index + 1, currentSubsequence), and then remove it to backtrack.
- One call that excludes
- Start the process by calling
findSubsequences(0, new ArrayList<>()). - Return the final
totalWidth.
Walkthrough
The core of this method is a backtracking algorithm to explore all possibilities of forming a subsequence. We can define a recursive helper function that builds subsequences. At each step i in the input array nums, we decide whether to include nums[i] in the current subsequence or not. This creates a decision tree of 2^n paths, where n is the length of nums, with each path corresponding to a unique subsequence. Once a full subsequence is formed (i.e., we've made a decision for every element), we check if it's non-empty. If it is, we iterate through it to find the minimum and maximum values, compute their difference, and add this width to a global sum. All additions are performed modulo 10^9 + 7 to prevent overflow and meet the problem's requirements.
class Solution { long totalWidth = 0; int MOD = 1_000_000_007; public int sumSubsequenceWidths(int[] nums) { // Note: This approach is too slow and will time out. findSubsequences(nums, 0, new java.util.ArrayList<>()); return (int) totalWidth; } private void findSubsequences(int[] nums, int index, java.util.List<Integer> currentSubsequence) { if (index == nums.length) { if (!currentSubsequence.isEmpty()) { int minVal = Integer.MAX_VALUE; int maxVal = Integer.MIN_VALUE; for (int num : currentSubsequence) { minVal = Math.min(minVal, num); maxVal = Math.max(maxVal, num); } totalWidth = (totalWidth + maxVal - minVal) % MOD; } return; } // Decision 1: Exclude nums[index] findSubsequences(nums, index + 1, currentSubsequence); // Decision 2: Include nums[index] currentSubsequence.add(nums[index]); findSubsequences(nums, index + 1, currentSubsequence); currentSubsequence.remove(currentSubsequence.size() - 1); // Backtrack }}Complexity
Time
O(n * 2^n). There are `2^n` subsequences in total. For each subsequence, finding the minimum and maximum can take up to O(n) time. This makes the approach infeasible for `n > 20`.
Space
O(n), where n is the number of elements in `nums`. This space is used by the recursion stack and to store the current subsequence being built, both of which can go up to a depth/size of `n`.
Trade-offs
Pros
Simple to understand and conceptualize.
Cons
Extremely inefficient due to its exponential time complexity.
Will result in a 'Time Limit Exceeded' (TLE) error for the given constraints.
Solutions
Solution
class Solution { private static final int MOD = ( int ) 1 e9 + 7 ; public int sumSubseqWidths ( int [] nums ) { Arrays . sort ( nums ); long ans = 0 , p = 1 ; int n = nums . length ; for ( int i = 0 ; i < n ; ++ i ) { ans = ( ans + ( nums [ i ] - nums [ n - i - 1 ]) * p + MOD ) % MOD ; p = ( p << 1 ) % MOD ; } return ( int ) 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.