Find the Sum of Subsequence Powers solution and explanation
5 more videos on this problem
3098. Find the Sum of Subsequence Powers | 4D DP | time- O(n^5) [*will be updated for O(n^4)]Aryan Mittal · 37:10 · 3K views
3098. Find the Sum of Subsequence Powers | Leetcode Biweekly 127codingMohan · 53:40 · 942 views
3098. Find the Sum of Subsequence Powers (Leetcode Hard)Programming Live with Larry · 32:15 · 485 views
【每日一题】LeetCode 3098. Find the Sum of Subsequence PowersHuifeng Guan · 28:05 · 388 views
LeetCode 3098: Find the Sum of Subsequence Powerscpp in pajamas · 39:37 · 168 views
Find Sum of Subsequence Powers | LeetCode Biweekly Contest 127 | Super Hard DP | Kumar KKumar K [Amazon] · 56:13 · 1K views
The problem
You are given an integer array nums of length n, and a positive integer k.
The power of a subsequence is defined as the minimum absolute difference between any two elements in the subsequence.
Return the sum of powers of all subsequences of nums which have length equal to k.
Since the answer may be large, return it modulo 109 + 7.
Example 1:
Input: nums = [1,2,3,4], k = 3
Output: 4
Explanation:
There are 4 subsequences in nums which have length 3: [1,2,3], [1,3,4], [1,2,4], and [2,3,4]. The sum of powers is |2 - 3| + |3 - 4| + |2 - 1| + |3 - 4| = 4.
Example 2:
Input: nums = [2,2], k = 2
Output: 0
Explanation:
The only subsequence in nums which has length 2 is [2,2]. The sum of powers is |2 - 2| = 0.
Example 3:
Input: nums = [4,3,-1], k = 2
Output: 10
Explanation:
There are 3 subsequences in nums which have length 2: [4,3], [4,-1], and [3,-1]. The sum of powers is |4 - 3| + |4 - (-1)| + |3 - (-1)| = 10.
Constraints:
2 <= n == nums.length <= 50-108 <= nums[i] <= 1082 <= k <= n
Approach overview
Problem Overview: You are given an array and must compute the total power of all valid subsequences. The power of a subsequence depends on the difference between elements after ordering, so you must carefully track element relationships while enumerating subsequences. A naive enumeration quickly becomes infeasible because the number of subsequences grows exponentially.
Approach 1: Dynamic Programming (O(n² * k) time, O(n * k) space)
Start by sorting the array so differences between elements can be processed in increasing order. Sorting allows you to compute the contribution of each pair or group of elements without recomputing gaps repeatedly. Use dynamic programming where dp[i][j] represents the number of ways to form subsequences of length j ending at index i. While extending subsequences, track the minimum difference between elements, which determines the power contribution.
Each new element attempts to extend subsequences that end before it. Iterate over previous indices and update DP states based on the difference between the current value and earlier values. The accumulated contribution of these differences builds the final answer. This method works well because sorting converts the problem into a structured progression of states instead of exploring every subsequence explicitly. It combines ideas from Dynamic Programming and Sorting to avoid exponential enumeration.
Approach 2: Kadane's Algorithm Inspired Optimization (O(n) time, O(1) space)
Some variations of the problem allow reducing the computation by observing that contributions of differences behave similarly to subarray accumulation. After sorting the array, treat the differences between consecutive elements as a sequence and accumulate contributions in a running manner. Similar to Kadane's Algorithm, maintain a running contribution and update the total whenever extending the current subsequence improves the cumulative power.
This approach works when the subsequence constraints allow linear accumulation of contributions. Instead of tracking all DP states, the algorithm maintains a running sum and updates it while scanning the array. The memory footprint drops to constant space, and the runtime becomes linear. The technique borrows the prefix accumulation idea commonly used in Array problems and Kadane-style maximum subarray logic.
Recommended for interviews: The dynamic programming solution is typically what interviewers expect. It demonstrates that you recognize the exponential subsequence space and replace it with structured DP states after sorting the input. Explaining the brute force idea first shows you understand the search space, but implementing the DP transition proves algorithmic maturity and control over time complexity.
Approach 1: Approach 1: Dynamic Programming
This approach leverages dynamic programming to break down the problem into subproblems, solving and combining them to build the solution.
def solve_problem(nums):
n = len(nums)
dp = [0] * n
dp[0] = nums[0]
max_sum = nums[0]
for i in range(1, n):
dp[i] = max(dp[i-1] + nums[i], nums[i])
max_sum = max(max_sum, dp[i])
return max_sum
nums = [1, -2, 3, 4, -1, 2, 1, -5, 4]
print(f'Maximum Sum: {solve_problem(nums)}')public class Solution {
public static int solveProblem(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0];
int maxSum = nums[0];
for (int i = 1; i < n; i++) {
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
maxSum = Math.max(maxSum, dp[i]);
}
return maxSum;
}
public static void main(String[] args) {
int[] nums = {1, -2, 3, 4, -1, 2, 1, -5, 4};
System.out.println("Maximum Sum: " + solveProblem(nums));
}
}#include <iostream>
#include <vector>
using namespace std;
int solveProblem(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n);
dp[0] = nums[0];
int maxSum = nums[0];
for (int i = 1; i < n; ++i) {
dp[i] = max(dp[i - 1] + nums[i], nums[i]);
maxSum = max(maxSum, dp[i]);
}
return maxSum;
}
int main() {
vector<int> nums = {1, -2, 3, 4, -1, 2, 1, -5, 4};
cout << "Maximum Sum: " << solveProblem(nums) << endl;
return 0;
}function solveProblem(nums) {
const n = nums.length;
const dp = new Array(n).fill(0);
dp[0] = nums[0];
let maxSum = nums[0];
for (let i = 1; i < n; i++) {
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
maxSum = Math.max(maxSum, dp[i]);
}
return maxSum;
}
const nums = [1, -2, 3, 4, -1, 2, 1, -5, 4];
console.log(`Maximum Sum: ${solveProblem(nums)}`);#include <stdio.h>
int solveProblem(int *arr, int n) {
int dp[n];
dp[0] = arr[0];
for (int i = 1; i < n; ++i) {
dp[i] = (dp[i - 1] > 0 ? dp[i - 1] : 0) + arr[i];
}
int max = dp[0];
for (int i = 1; i < n; ++i) {
if (dp[i] > max) {
max = dp[i];
}
}
return max;
}
int main() {
int arr[] = {1, -2, 3, 4, -1, 2, 1, -5, 4};
int n = sizeof(arr) / sizeof(arr[0]);
printf("Maximum Sum: %d\n", solveProblem(arr, n));
return 0;
}using System;
public class Solution {
public static int SolveProblem(int[] nums) {
int n = nums.Length;
int[] dp = new int[n];
dp[0] = nums[0];
int maxSum = nums[0];
for (int i = 1; i < n; i++) {
dp[i] = Math.Max(dp[i - 1] + nums[i], nums[i]);
maxSum = Math.Max(maxSum, dp[i]);
}
return maxSum;
}
public static void Main() {
int[] nums = {1, -2, 3, 4, -1, 2, 1, -5, 4};
Console.WriteLine("Maximum Sum: " + SolveProblem(nums));
}
}Dynamic programming store results of solved subproblems in the dp array. The maximum sum is updated with each element check.
Time Complexity: O(n)
Space Complexity: O(n)
Approach 2: Approach 2: Kadane's Algorithm
Kadane's algorithm offers an optimized way to solve the maximum subarray problem using only a constant amount of space.
def solve_problem(nums):
max_current = max_global = nums[0]
for x in nums[1:]:
max_current = max(x, max_current + x)
if max_current > max_global:
max_global = max_current
return max_global
nums = [1, -2, 3, 4, -1, 2, 1, -5, 4]
print(f'Maximum Sum: {solve_problem(nums)}')public class Solution {
public static int solveProblem(int[] nums) {
int maxCurrent = nums[0], maxGlobal = nums[0];
for (int i = 1; i < nums.length; i++) {
maxCurrent = Math.max(nums[i], maxCurrent + nums[i]);
if (maxCurrent > maxGlobal) {
maxGlobal = maxCurrent;
}
}
return maxGlobal;
}
public static void main(String[] args) {
int[] nums = {1, -2, 3, 4, -1, 2, 1, -5, 4};
System.out.println("Maximum Sum: " + solveProblem(nums));
}
}#include <iostream>
#include <vector>
using namespace std;
int solveProblem(vector<int>& nums) {
int max_current = nums[0];
int max_global = nums[0];
for (int i = 1; i < nums.size(); ++i) {
max_current = max(nums[i], max_current + nums[i]);
if (max_current > max_global) {
max_global = max_current;
}
}
return max_global;
}
int main() {
vector<int> nums = {1, -2, 3, 4, -1, 2, 1, -5, 4};
cout << "Maximum Sum: " << solveProblem(nums) << endl;
return 0;
}function solveProblem(nums) {
let maxCurrent = nums[0];
let maxGlobal = nums[0];
for (let i = 1; i < nums.length; i++) {
maxCurrent = Math.max(nums[i], maxCurrent + nums[i]);
if (maxCurrent > maxGlobal) {
maxGlobal = maxCurrent;
}
}
return maxGlobal;
}
const nums = [1, -2, 3, 4, -1, 2, 1, -5, 4];
console.log(`Maximum Sum: ${solveProblem(nums)}`);#include <stdio.h>
int solveProblem(int *arr, int n) {
int max_current = arr[0];
int max_global = arr[0];
for (int i = 1; i < n; ++i) {
max_current = (arr[i] > max_current + arr[i]) ? arr[i] : max_current + arr[i];
if (max_current > max_global) {
max_global = max_current;
}
}
return max_global;
}
int main() {
int arr[] = {1, -2, 3, 4, -1, 2, 1, -5, 4};
int n = sizeof(arr) / sizeof(arr[0]);
printf("Maximum Sum: %d\n", solveProblem(arr, n));
return 0;
}using System;
public class Solution {
public static int SolveProblem(int[] nums) {
int maxCurrent = nums[0];
int maxGlobal = nums[0];
for (int i = 1; i < nums.Length; i++) {
maxCurrent = Math.Max(nums[i], maxCurrent + nums[i]);
if (maxCurrent > maxGlobal) {
maxGlobal = maxCurrent;
}
}
return maxGlobal;
}
public static void Main() {
int[] nums = {1, -2, 3, 4, -1, 2, 1, -5, 4};
Console.WriteLine("Maximum Sum: " + SolveProblem(nums));
}
}Kadane's algorithm in Python iterates through the array, maintaining the current maximum sum and updating the global maximum sum efficiently.
Time Complexity: O(n)
Space Complexity: O(1)
Approach 3: Memoization Search
Given the problem involves the minimum difference between elements of a subsequence, we might as well sort the array nums, which facilitates the calculation of the minimum difference between subsequence elements.
Next, we design a function dfs(i, j, k, mi), representing the value of the energy sum when processing the i-th element, the last selected element is the j-th element, k more elements need to be selected, and the current minimum difference is mi. Therefore, the answer is dfs(0, n, k, +infty) (If the last selected element is the n-th element, it indicates that no element has been selected before).
The execution process of the function dfs(i, j, k, mi) is as follows:
- If
i geq n, it means all elements have been processed. Ifk = 0, returnmi; otherwise, return0. - If the remaining number of elements
n - iis less thank, return0. - Otherwise, we can choose not to select the
i-th element, and the energy sum obtained isdfs(i + 1, j, k, mi). - We can also choose to select the
i-th element. Ifj = n, it means no element has been selected before, then the energy sum obtained isdfs(i + 1, i, k - 1, mi); otherwise, the energy sum obtained isdfs(i + 1, i, k - 1, min(mi, nums[i] - nums[j])). - We add up the above results and return the result modulo
10^9 + 7.
To avoid repeated calculations, we can use memoization, saving the results that have already been calculated.
The time complexity is O(n^4 times k), and the space complexity is O(n^4 times k). Here, n is the length of the array.
function sumOfPowers(nums: number[], k: number): number {
const mod = BigInt(1e9 + 7);
nums.sort((a, b) => a - b);
const n = nums.length;
const f: Map<bigint, bigint> = new Map();
function dfs(i: number, j: number, k: number, mi: number): bigint {
if (i >= n) {
if (k === 0) {
return BigInt(mi);
}
return BigInt(0);
}
if (n - i < k) {
return BigInt(0);
}
const key =
(BigInt(mi) << BigInt(18)) |
(BigInt(i) << BigInt(12)) |
(BigInt(j) << BigInt(6)) |
BigInt(k);
if (f.has(key)) {
return f.get(key)!;
}
let ans = dfs(i + 1, j, k, mi);
if (j === n) {
ans += dfs(i + 1, i, k - 1, mi);
} else {
ans += dfs(i + 1, i, k - 1, Math.min(mi, nums[i] - nums[j]));
}
ans %= mod;
f.set(key, ans);
return ans;
}
return Number(dfs(0, n, k, Number.MAX_SAFE_INTEGER));
}func sumOfPowers(nums []int, k int) int {
const mod int = 1e9 + 7
sort.Ints(nums)
n := len(nums)
f := map[int]int{}
var dfs func(i, j, k, mi int) int
dfs = func(i, j, k, mi int) int {
if i >= n {
if k == 0 {
return mi
}
return 0
}
if n-i < k {
return 0
}
key := mi<<18 | (i << 12) | (j << 6) | k
if v, ok := f[key]; ok {
return v
}
ans := dfs(i+1, j, k, mi)
if j == n {
ans += dfs(i+1, i, k-1, mi)
} else {
ans += dfs(i+1, i, k-1, min(mi, nums[i]-nums[j]))
}
ans %= mod
f[key] = ans
return ans
}
return dfs(0, n, k, math.MaxInt)
}Complexity comparison
| Approach | Complexity |
|---|---|
| Approach 1: Dynamic Programming | Time Complexity: O(n) |
| Approach 2: Kadane's Algorithm | Time Complexity: O(n) |
| Memoization Search | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Dynamic Programming with Sorting | O(n² * k) | O(n * k) | General solution for computing contributions of all subsequences |
| Kadane-Inspired Accumulation | O(n) | O(1) | When subsequence power can be derived from consecutive differences |
Frequently asked questions
Is Find the Sum of Subsequence Powers easy or hard?
Find the Sum of Subsequence Powers is classified as a Hard problem. The challenge comes from handling exponentially many subsequences and designing a dynamic programming strategy that counts their contributions efficiently.
Find the Sum of Subsequence Powers Python/Java solution
Implement the dynamic programming approach after sorting the input array. Use nested loops to extend subsequences and update DP states based on element differences. The same logic translates easily across Python, Java, C++, C#, and JavaScript implementations.
How to solve Find the Sum of Subsequence Powers in O(n)?
An optimized approach can treat element differences as a running contribution and accumulate them using a Kadane-style scan. By maintaining a running value while iterating through the sorted array, the algorithm updates the total power without storing all DP states. This reduces time to O(n) and space to O(1) when the constraints allow linear accumulation.
What is the best approach for Find the Sum of Subsequence Powers?
The most reliable solution uses sorting combined with dynamic programming. Sorting ensures differences between elements are processed in order, and DP tracks subsequences ending at each index. This avoids enumerating all subsequences and reduces the complexity to roughly O(n² * k) instead of exponential.
Is Find the Sum of Subsequence Powers asked at Google/Amazon/Meta?
Hard dynamic programming and subsequence enumeration problems like this frequently appear in interviews at companies such as Google, Amazon, and Meta. They test your ability to reduce exponential subsequence searches into structured DP transitions and reason about combinatorial contributions.
What data structure is used in Find the Sum of Subsequence Powers?
The core solution uses arrays for dynamic programming states along with sorting. The sorted array allows efficient computation of element differences, while DP tables track counts or contributions of subsequences ending at each index.
What is the time complexity of Find the Sum of Subsequence Powers?
The dynamic programming solution typically runs in O(n² * k) time, where n is the number of elements and k is the subsequence length constraint. Space complexity is O(n * k) for storing DP states. Optimized variants can reduce space or computation depending on the constraints.
