Range Sum of Sorted Subarray Sums
In this page, we will solve the Range Sum of Sorted Subarray Sums problem using different approaches: calculating all subarray sums and sorting them, and using a min-heap for efficiency. We will provide the implementation of the solution in JavaScript, TypeScript, Python, Java, C++, and more.
Problem Descriptionβ
You are given the array nums
consisting of n
positive integers. You computed the sum of all non-empty continuous subarrays from the array and then sorted them in non-decreasing order, creating a new array of numbers.
Return the sum of the numbers from index left
to index right
(indexed from 1), inclusive, in the new array. Since the answer can be a huge number return it modulo .
Examplesβ
Example 1:
Input: nums = [1,2,3,4], n = 4, left = 1, right = 5
Output: 13
Explanation: All subarray sums are 1, 3, 6, 10, 2, 5, 9, 3, 7, 4. After sorting them in non-decreasing order we have the new array [1, 2, 3, 3, 4, 5, 6, 7, 9, 10]. The sum of the numbers from index left = 1 to right = 5 is 1 + 2 + 3 + 3 + 4 = 13.
Example 2:
Input: nums = [1,2,3,4], n = 4, left = 3, right = 4
Output: 6
Explanation: The given array is the same as example 1. We have the new array [1, 2, 3, 3, 4, 5, 6, 7, 9, 10]. The sum of the numbers from index left = 3 to right = 4 is 3 + 3 = 6.
Example 3:
Input: nums = [1,2,3,4], n = 4, left = 1, right = 10
Output: 50
Constraintsβ
Explanationβ
There are three main approaches discussed:
-
Naive Approach:
- Calculate all possible subarray sums and store them in a list.
- Sort the list of subarray sums.
- Calculate the sum of the range of sorted subarray sums from
left
toright
.
-
Min-Heap Approach:
- Use a min-heap to store the subarray sums dynamically.
- Extract the minimum elements from the heap for the required range and sum them up.
-
Fenwick Tree Approach:
- Use a Fenwick Tree to manage prefix sums.
- Calculate subarray sums based on prefix sums.
- Sort the subarray sums and sum the elements in the required range.
Solution for Range Sum of Sorted Subarray Sumsβ
Intuition and Approachβ
To solve the problem, we can use two approaches:
- Brute Force Approach: Calculate all subarray sums, sort them, and then find the sum of the specified range.
- Optimized Approach Using Min-Heap: Use a min-heap to keep track of the smallest sums and avoid sorting the entire list of subarray sums.
- Brute Force
- Min-Heap
- Fenwick Tree
Approach 1: Brute Forceβ
Implementationβ
function rangeSumNaive() { function rangeSum(nums, n, left, right) { const MOD = 1e9 + 7; const allSums = []; for (let i = 0; i < n; i++) { let sum = 0; for (let j = i; j < n; j++) { sum += nums[j]; allSums.push(sum); } } allSums.sort((a, b) => a - b); let result = 0; for (let i = left - 1; i < right; i++) { result = (result + allSums[i]) % MOD; } return result; } const nums = [1, 2, 3, 4]; const n = 4, left = 1, right = 5; const result = rangeSum(nums, n, left, right); return ( <div> <p> <b>Input:</b> {JSON.stringify(nums)} </p> <p> <b>Output:</b> {result} </p> </div> ); }
Code in Different Languagesβ
- JavaScript
- TypeScript
- Python
- Java
- C++
function rangeSumOfSortedSubarraySums(nums, n, left, right) {
const MOD = 1e9 + 7;
const subarraySums = [];
for (let i = 0; i < n; i++) {
let sum = 0;
for (let j = i; j < n; j++) {
sum += nums[j];
subarraySums.push(sum);
}
}
subarraySums.sort((a, b) => a - b);
let result = 0;
for (let i = left - 1; i < right; i++) {
result = (result + subarraySums[i]) % MOD;
}
return result;
}
function rangeSumOfSortedSubarraySums(nums: number[], n: number, left: number, right: number): number {
const MOD = 1e9 + 7;
const subarraySums: number[] = [];
for (let i = 0; i < n; i++) {
let sum = 0;
for (let j = i; j < n; j++) {
sum += nums[j];
subarraySums.push(sum);
}
}
subarraySums.sort((a, b) => a - b);
let result = 0;
for (let i = left - 1; i < right; i++) {
result = (result + subarraySums[i]) % MOD;
}
return result;
}
from typing import List
class Solution:
def rangeSum(self, nums: List[int], n: int, left: int, right: int) -> int:
MOD = 10**9 + 7
subarray_sums = []
for i in range(n):
sum = 0
for j in range(i, n):
sum += nums[j]
subarray_sums.append(sum)
subarray_sums.sort()
result = 0
for i in range(left - 1, right):
result = (result + subarray_sums[i]) % MOD
return result
import java.util.*;
class Solution {
public int rangeSum(int[] nums, int n, int left, int right) {
final int MOD = 1000000007;
List<Integer> subarraySums = new ArrayList<>();
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = i; j < n; j++) {
sum += nums[j];
subarraySums.add(sum);
}
}
Collections.sort(subarraySums);
int result = 0;
for (int i = left - 1; i < right; i++) {
result = (result + subarraySums.get(i)) % MOD;
}
return result;
}
}
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
int rangeSum(vector<int>& nums, int n, int left, int right) {
const int MOD = 1e9 + 7;
vector<int> subarraySums;
for (int i = 0; i < n; ++i) {
int sum = 0;
for (int j = i; j < n; ++j) {
sum += nums[j];
subarraySums.push_back(sum);
}
}
sort(subarraySums.begin(), subarray
Sums.end());
int result = 0;
for (int i = left - 1; i < right; ++i) {
result = (result + subarraySums[i]) % MOD;
}
return result;
}
};
Approach 2: Min-Heapβ
Explanationβ
The min-heap approach can optimize the time complexity. Instead of calculating all subarray sums and sorting them, we use a min-heap to keep track of the smallest sums.
Implementationβ
function rangeSumMinHeap() { function rangeSum(nums, n, left, right) { const MOD = 1e9 + 7; const minHeap = []; for (let i = 0; i < n; ++i) { let sum = 0; for (let j = i; j < n; ++j) { sum += nums[j]; minHeap.push(sum); } } minHeap.sort((a, b) => a - b); let result = 0; for (let i = 0; i < right; ++i) { const minSum = minHeap[i]; if (i >= left - 1) { result = (result + minSum) % MOD; } } return result; } const nums = [1, 2, 3, 4]; const n = 4, left = 1, right = 5; const result = rangeSum(nums, n, left, right); return ( <div> <p> <b>Input:</b> {JSON.stringify(nums)} </p> <p> <b>Output:</b> {result} </p> </div> ); }
- JavaScript
- TypeScript
- Python
- Java
- C++
class MinHeap {
constructor() {
this.heap = [];
}
insert(val) {
this.heap.push(val);
this.bubbleUp();
}
bubbleUp() {
let index = this.heap.length - 1;
const current = this.heap[index];
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
const parent = this.heap[parentIndex];
if (current >= parent) break;
this.heap[index] = parent;
index = parentIndex;
}
this.heap[index] = current;
}
extractMin() {
const min = this.heap[0];
const end = this.heap.pop();
if (this.heap.length > 0) {
this.heap[0] = end;
this.sinkDown(0);
}
return min;
}
sinkDown(index) {
const length = this.heap.length;
const element = this.heap[index];
while (true) {
let leftChildIndex = 2 * index + 1;
let rightChildIndex = 2 * index + 2;
let leftChild, rightChild;
let swap = null;
if (leftChildIndex < length) {
leftChild = this.heap[leftChildIndex];
if (leftChild < element) swap = leftChildIndex;
}
if (rightChildIndex < length) {
rightChild = this.heap[rightChildIndex];
if (
(swap === null && rightChild < element) ||
(swap !== null && rightChild < leftChild)
) {
swap = rightChildIndex;
}
}
if (swap === null) break;
this.heap[index] = this.heap[swap];
index = swap;
}
this.heap[index] = element;
}
}
function rangeSumOfSortedSubarraySums(nums, n, left, right) {
const MOD = 1e9 + 7;
const heap = new MinHeap();
for (let i = 0; i < n; i++) {
let sum = 0;
for (let j = i; j < n; j++) {
sum += nums[j];
heap.insert(sum);
}
}
let result = 0;
for (let i = 0; i < right; i++) {
let minSum = heap.extractMin();
if (i >= left - 1) {
result = (result + minSum) % MOD;
}
}
return result;
}
class MinHeap {
heap: number[];
constructor() {
this.heap = [];
}
insert(val: number): void {
this.heap.push(val);
this.bubbleUp();
}
bubbleUp(): void {
let index = this.heap.length - 1;
const current = this.heap[index];
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
const parent = this.heap[parentIndex];
if (current >= parent) break;
this.heap[index] = parent;
index = parentIndex;
}
this.heap[index] = current;
}
extractMin(): number {
const min = this.heap[0];
const end = this.heap.pop();
if (this.heap.length > 0) {
this.heap[0] = end!;
this.sinkDown(0);
}
return min;
}
sinkDown(index: number): void {
const length = this.heap.length;
const element = this.heap[index];
while (true) {
let leftChildIndex = 2 * index + 1;
let rightChildIndex = 2 * index + 2;
let leftChild, rightChild;
let swap = null;
if (leftChildIndex < length) {
leftChild = this.heap[leftChildIndex];
if (leftChild < element) swap = leftChildIndex;
}
if (rightChildIndex < length) {
rightChild = this.heap[rightChildIndex];
if (
(swap === null && rightChild < element) ||
(swap !== null && rightChild < leftChild)
) {
swap = rightChildIndex;
}
}
if (swap === null) break;
this.heap[index] = this.heap[swap];
index = swap;
}
this.heap[index] = element;
}
}
function rangeSumOfSortedSubarraySums(nums: number[], n: number, left: number, right: number): number {
const MOD = 1e9 + 7;
const heap = new MinHeap();
for (let i = 0; i < n; i++) {
let sum = 0;
for (let j = i; j < n; j++) {
sum += nums[j];
heap.insert(sum);
}
}
let result = 0;
for (let i = 0; i < right; i++) {
let minSum = heap.extractMin();
if (i >= left - 1) {
result = (result + minSum) % MOD;
}
}
return result;
}
import heapq
from typing import List
class Solution:
def rangeSum(self, nums: List[int], n: int, left: int, right: int) -> int:
MOD = 10**9 + 7
min_heap = []
for i in range(n):
sum = 0
for j in range(i, n):
sum += nums[j]
heapq.heappush(min_heap, sum)
result = 0
for i in range(right):
min_sum = heapq.heappop(min_heap)
if i >= left - 1:
result = (result + min_sum) % MOD
return result
import java.util.PriorityQueue;
class Solution {
public int rangeSum(int[] nums, int n, int left, int right) {
final int MOD = 1000000007;
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = i; j < n; j++) {
sum += nums[j];
minHeap.offer(sum);
}
}
int result = 0;
for (int i = 0; i < right; i++) {
int minSum = minHeap.poll();
if (i >= left - 1) {
result = (result + minSum) % MOD;
}
}
return result;
}
}
#include <vector>
#include <queue>
using namespace std;
class Solution {
public:
int rangeSum(vector<int>& nums
, int n, int left, int right) {
const int MOD = 1e9 + 7;
priority_queue<int, vector<int>, greater<int>> minHeap;
for (int i = 0; i < n; ++i) {
int sum = 0;
for (int j = i; j < n; ++j) {
sum += nums[j];
minHeap.push(sum);
}
}
int result = 0;
for (int i = 0; i < right; ++i) {
int minSum = minHeap.top();
minHeap.pop();
if (i >= left - 1) {
result = (result + minSum) % MOD;
}
}
return result;
}
};
Approach 3: Fenwick Treeβ
Explanationβ
Using a Fenwick Tree (or Binary Indexed Tree) can efficiently manage the prefix sums and query the range sum.
Implementationβ
function rangeSumFenwickTree() { class FenwickTree { constructor(size) { this.size = size; this.tree = Array(size + 1).fill(0); } update(index, value) { while (index <= this.size) { this.tree[index] += value; index += index & -index; } } query(index) { let sum = 0; while (index > 0) { sum += this.tree[index]; index -= index & -index; } return sum; } } function rangeSumOfSortedSubarraySums(nums, n, left, right) { const MOD = 1e9 + 7; let prefixSum = Array(n + 1).fill(0); let allSums = []; for (let i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + nums[i]; } for (let i = 0; i <= n; i++) { for (let j = i + 1; j <= n; j++) { allSums.push(prefixSum[j] - prefixSum[i]); } } allSums.sort((a, b) => a - b); let result = 0; for (let i = left - 1; i < right; i++) { result = (result + allSums[i]) % MOD; } return result; } const nums = [1, 2, 3, 4]; const n = 4, left = 1, right = 5; const result = rangeSumOfSortedSubarraySums(nums, n, left, right); return ( <div> <p> <b>Input:</b> {JSON.stringify(nums)} </p> <p> <b>Output:</b> {result} </p> </div> ); }
- JavaScript
- TypeScript
- Python
- Java
- C++
class FenwickTree {
constructor(size) {
this.size = size;
this.tree = Array(size + 1).fill(0);
}
update(index, value) {
while (index <= this.size) {
this.tree[index] += value;
index += index & -index;
}
}
query(index) {
let sum = 0;
while (index > 0) {
sum += this.tree[index];
index -= index & -index;
}
return sum;
}
}
function rangeSumOfSortedSubarraySums(nums, n, left, right) {
const MOD = 1e9 + 7;
let prefixSum = Array(n + 1).fill(0);
let allSums = [];
for (let i = 0; i < n; i++) {
prefixSum[i + 1] = prefixSum[i] + nums[i];
}
for (let i = 0; i <= n; i++) {
for (let j = i + 1; j <= n; j++) {
allSums.push(prefixSum[j] - prefixSum[i]);
}
}
allSums.sort((a, b) => a - b);
let result = 0;
for (let i = left - 1; i < right; i++) {
result = (result + allSums[i]) % MOD;
}
return result;
}
class FenwickTree {
size: number;
tree: number[];
constructor(size: number) {
this.size = size;
this.tree = Array(size + 1).fill(0);
}
update(index: number, value: number): void {
while (index <= this.size) {
this.tree[index] += value;
index += index & -index;
}
}
query(index: number): number {
let sum = 0;
while (index > 0) {
sum += this.tree[index];
index -= index & -index;
}
return sum;
}
}
function rangeSumOfSortedSubarraySums(nums: number[], n: number, left: number, right: number): number {
const MOD = 1e9 + 7;
let prefixSum = Array(n + 1).fill(0);
let allSums: number[] = [];
for (let i = 0; i < n; i++) {
prefixSum[i + 1] = prefixSum[i] + nums[i];
}
for (let i = 0; i <= n; i++) {
for (let j = i + 1; j <= n; j++) {
allSums.push(prefixSum[j] - prefixSum[i]);
}
}
allSums.sort((a, b) => a - b);
let result = 0;
for (let i = left - 1; i < right; i++) {
result = (result + allSums[i]) % MOD;
}
return result;
}
class FenwickTree:
def __init__(self, size: int):
self.size = size
self.tree = [0] * (size + 1)
def update(self, index: int, value: int):
while index <= self.size:
self.tree[index] += value
index += index & -index
def query(self, index: int) -> int:
sum = 0
while index > 0:
sum += self.tree[index]
index -= index & -index
return sum
def rangeSumOfSortedSubarraySums(nums, n, left, right):
MOD = 10**9 + 7
prefix_sum = [0] * (n + 1)
all_sums = []
for i in range(n):
prefix_sum[i + 1] = prefix_sum[i] + nums[i]
for i in range(n + 1):
for j in range(i + 1, n + 1):
all_sums.append(prefix_sum[j] - prefix_sum[i])
all_sums.sort()
result = 0
for i in range(left - 1, right):
result = (result + all_sums[i]) % MOD
return result
import java.util.Arrays;
class FenwickTree {
private int[] tree;
private int size;
public FenwickTree(int size) {
this.size = size;
this.tree = new int[size + 1];
}
public void update(int index, int value) {
while (index <= size) {
tree[index] += value;
index += index & -index;
}
}
public int query(int index) {
int sum = 0;
while (index > 0) {
sum += tree[index];
index -= index & -index;
}
return sum;
}
}
class Solution {
public int rangeSum(int[] nums, int n, int left, int right) {
final int MOD = 1000000007;
int[] prefixSum = new int[n + 1];
int[] allSums = new int[n * (n + 1) / 2];
int k = 0;
for (int i = 0; i < n; i++) {
prefixSum[i + 1] = prefixSum[i] + nums[i];
}
for (int i = 0; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
allSums[k++] = prefixSum[j] - prefixSum[i];
}
}
Arrays.sort(allSums);
int result = 0;
for (int i = left - 1; i < right; i++) {
result = (result + allSums[i]) % MOD;
}
return result;
}
}
#include <vector>
#include <algorithm>
using namespace std;
class FenwickTree {
public:
FenwickTree(int size) : tree(size + 1, 0), size(size) {}
void update(int index, int value) {
while (index <= size) {
tree[index] += value;
index += index & -index;
}
}
int query(int index) const {
int sum = 0;
while (index > 0) {
sum += tree[index];
index -= index & -index;
}
return sum;
}
private:
vector<int> tree;
int size;
};
class Solution {
public:
int rangeSum(vector<int>& nums, int n, int left, int right) {
const int MOD = 1e9 + 7;
vector<int> prefixSum(n + 1, 0);
vector<int> allSums(n * (n + 1) / 2);
int k = 0;
for (int i = 0; i < n; ++i) {
prefixSum[i + 1] = prefixSum[i] + nums[i];
}
for (int i = 0; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
allSums[k++] = prefixSum[j] - prefixSum[i];
}
}
sort(allSums.begin(), allSums.end());
int result = 0;
for (int i = left - 1; i < right; ++i) {
result = (result + allSums[i]) % MOD;
}
return result;
}
};
Each approach has its own time and space complexity considerations. The naive approach is simple but may be inefficient for large inputs. The min-heap approach optimizes the process of finding the smallest subarray sums. The Fenwick Tree approach efficiently manages prefix sums but requires understanding of Fenwick Tree operations.
Referencesβ
- LeetCode Problem: Range Sum of Sorted Subarray Sums
- Solution Link: Range Sum of Sorted Subarray Sums Solution on LeetCode
- Authors LeetCode Profile: Manish Kumar Gupta