Maximum Good Subarray Sum solution and explanation
9 more videos on this problem
3026. Maximum Good Subarray Sum | Prefix Sums | Hash Table | Biweekly Contest 123Aryan Mittal · 25:33 · 6K views
Maximum Good Subarray Sum - Python - Leetcode 3026CheatCode Ninja · 9:04 · 2K views
3026 Maximum Good Subarray Sum || Prefix Sum + Map Indexes ✅Ayush Rao · 9:51 · 1K views
3026. Maximum Good Subarray Sum | Leetcode Biweekly 123codingMohan · 22:35 · 1K views
3026. Maximum Good Subarray Sum (Leetcode Medium)Programming Live with Larry · 12:38 · 1K views
Leetcode 3026: Maximum Good Subarray SumAlgorithms Casts · 13:01 · 817 views
(Not Optimal) 3026. Maximum Good Subarray Sum in Hindi || Leetcode Biweekly contest 123 |GeekstocodeGeekstocode · 17:20 · 385 views
3026. Maximum Good Subarray Sum solution | leetcode Biweekly Contest 123 problem c Solution O(n)Shivam Mishra LeetCode · 28:09 · 375 views
LeetCode 3026 - Maximum Good Subarray Sum - PythonAlpha-Code · 22:52 · 116 views
3026. Maximum Good Subarray Sum | Brute & Optimal | Biweekly Contest 123 | Beats 100%😎Code With Anubhav · 52:52 · 99 views
The problem
You are given an array nums of length n and a positive integer k.
A subarray of nums is called good if the absolute difference between its first and last element is exactly k, in other words, the subarray nums[i..j] is good if |nums[i] - nums[j]| == k.
Return the maximum sum of a good subarray of nums. If there are no good subarrays, return 0.
Example 1:
Input: nums = [1,2,3,4,5,6], k = 1 Output: 11 Explanation: The absolute difference between the first and last element must be 1 for a good subarray. All the good subarrays are: [1,2], [2,3], [3,4], [4,5], and [5,6]. The maximum subarray sum is 11 for the subarray [5,6].
Example 2:
Input: nums = [-1,3,2,4,5], k = 3 Output: 11 Explanation: The absolute difference between the first and last element must be 3 for a good subarray. All the good subarrays are: [-1,3,2], and [2,4,5]. The maximum subarray sum is 11 for the subarray [2,4,5].
Example 3:
Input: nums = [-1,-2,-3,-4], k = 2 Output: -6 Explanation: The absolute difference between the first and last element must be 2 for a good subarray. All the good subarrays are: [-1,-2,-3], and [-2,-3,-4]. The maximum subarray sum is -6 for the subarray [-1,-2,-3].
Constraints:
2 <= nums.length <= 105-109 <= nums[i] <= 1091 <= k <= 109
Approach overview
Problem Overview: You are given an integer array and a value k. A subarray is considered good if the absolute difference between its first and last elements equals k. The goal is to compute the maximum possible sum among all such subarrays.
Approach 1: Two Pointers with Prefix Sum Tracking (O(n) time, O(n) space)
This approach scans the array while maintaining running prefix sums so any subarray sum can be computed in constant time. While iterating with a right pointer, track previously seen values and check whether a value equal to nums[r] - k or nums[r] + k appeared earlier. If such a value exists, treat its position as a potential starting point and compute the subarray sum using prefix sums. Two moving boundaries help evaluate candidate subarrays as the array is traversed once. The method relies on fast lookups and incremental prefix updates, making it efficient for large arrays.
Approach 2: HashMap for Start Index Distribution (O(n) time, O(n) space)
The optimal solution combines prefix sum with a hash table. As you iterate through the array, maintain the current prefix sum and a map storing the minimum prefix sum observed before each value. For the current value x, check whether x - k or x + k has appeared before. If it has, subtract the stored minimum prefix sum from the current prefix to get the candidate subarray sum. Updating the map with the smallest prefix value ensures future subarrays produce the largest possible sum. This approach avoids storing all indices and keeps the lookup constant time, resulting in a clean linear solution using array traversal and hashing.
Recommended for interviews: Interviewers typically expect the hash map + prefix sum solution. A brute force idea demonstrates understanding of subarrays, but the optimized approach shows you know how to transform subarray sum problems into prefix computations with constant-time hash lookups.
Approach 1: Two Pointers Approach
In this approach, we start from each element and use two pointers to find good subarrays. One pointer begins at the current element and moves forward to find potential subarray ends. The other pointer helps to calculate the sum of the subarray.
def maxGoodSubarraySum(nums, k):
max_sum = 0
for i in range(len(nums)):
for j in range(i, len(nums)):
if abs(nums[i] - nums[j]) == k:
current_sum = sum(nums[i:j + 1])
max_sum = max(max_sum, current_sum)
return max_sum
nums = [1, 2, 3, 4, 5, 6]
k = 1
print(maxGoodSubarraySum(nums, k))import java.util.*;
public class Main {
public static int maxGoodSubarraySum(int[] nums, int k) {
int maxSum = 0;
for (int i = 0; i < nums.length; ++i) {
for (int j = i; j < nums.length; ++j) {
if (Math.abs(nums[i] - nums[j]) == k) {
int sum = 0;
for (int l = i; l <= j; ++l) {
sum += nums[l];
}
if (sum > maxSum) {
maxSum = sum;
}
}
}
}
return maxSum;
}
public static void main(String[] args) {
int[] nums = {1, 2, 3, 4, 5, 6};
int k = 1;
System.out.println(maxGoodSubarraySum(nums, k));
}
}#include <iostream>
#include <vector>
#include <cmath>
int maxGoodSubarraySum(std::vector<int>& nums, int k) {
int maxSum = 0;
for (int i = 0; i < nums.size(); ++i) {
for (int j = i; j < nums.size(); ++j) {
if (std::abs(nums[i] - nums[j]) == k) {
int sum = 0;
for (int l = i; l <= j; ++l) {
sum += nums[l];
}
if (sum > maxSum) {
maxSum = sum;
}
}
}
}
return maxSum;
}
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5, 6};
int k = 1;
std::cout << maxGoodSubarraySum(nums, k) << std::endl;
return 0;
}function maxGoodSubarraySum(nums, k) {
let maxSum = 0;
for (let i = 0; i < nums.length; i++) {
for (let j = i; j < nums.length; j++) {
if (Math.abs(nums[i] - nums[j]) === k) {
const sum = nums.slice(i, j + 1).reduce((a, b) => a + b, 0);
maxSum = Math.max(maxSum, sum);
}
}
}
return maxSum;
}
const nums = [1, 2, 3, 4, 5, 6];
const k = 1;
console.log(maxGoodSubarraySum(nums, k));#include <stdio.h>
#include <stdlib.h>
int maxGoodSubarraySum(int* nums, int numsSize, int k) {
int maxSum = 0;
for (int i = 0; i < numsSize; ++i) {
for (int j = i; j < numsSize; ++j) {
if (abs(nums[i] - nums[j]) == k) {
int sum = 0;
for (int l = i; l <= j; ++l) {
sum += nums[l];
}
if (sum > maxSum) {
maxSum = sum;
}
}
}
}
return maxSum;
}
int main() {
int nums[] = {1, 2, 3, 4, 5, 6};
int k = 1;
printf("%d\n", maxGoodSubarraySum(nums, 6, k));
return 0;
}using System;
public class Solution {
public int MaxGoodSubarraySum(int[] nums, int k) {
int maxSum = 0;
for (int i = 0; i < nums.Length; i++) {
for (int j = i; j < nums.Length; j++) {
if (Math.Abs(nums[i] - nums[j]) == k) {
int sum = 0;
for (int l = i; l <= j; l++) {
sum += nums[l];
}
maxSum = Math.Max(maxSum, sum);
}
}
}
return maxSum;
}
public static void Main() {
int[] nums = {1, 2, 3, 4, 5, 6};
int k = 1;
Console.WriteLine(new Solution().MaxGoodSubarraySum(nums, k));
}
}This Python code follows up on the same logic using the Pythonic syntax for easy reading and concise representation of steps.
Time Complexity: O(n^3).
Space Complexity: O(1).
Approach 2: HashMap for Start Index Distribution
This approach utilizes a HashMap to map the possible starting points of subarrays to see if the given element can serve as a potential endpoint to build a good subarray.
def maxGoodSubarraySum(nums, k):
holders = {}
max_sum = float('-inf')
for i, num in enumerate(nums):
holders[num] = i
for i in range(len(nums)):
current_sum = 0
for j in range(i, len(nums)):
current_sum += nums[j]
if nums[j] - k in holders:
max_sum = max(max_sum, current_sum)
return max_sum if max_sum != float('-inf') else 0
nums = [1, 2, 3, 4, 5, 6]
k = 1
print(maxGoodSubarraySum(nums, k))import java.util.*;
public class Main {
public static int maxGoodSubarraySum(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
int maxSum = Integer.MIN_VALUE;
for (int j = 0; j < nums.length; ++j) {
map.put(nums[j], j);
}
for (int i = 0; i < nums.length; ++i) {
int sum = 0;
for (int j = i; j < nums.length; ++j) {
sum += nums[j];
if (map.containsKey(nums[j] - k)) {
maxSum = Math.max(maxSum, sum);
}
}
}
return maxSum == Integer.MIN_VALUE ? 0 : maxSum;
}
public static void main(String[] args) {
int[] nums = {1, 2, 3, 4, 5, 6};
int k = 1;
System.out.println(maxGoodSubarraySum(nums, k));
}
}#include <iostream>
#include <vector>
#include <unordered_map>
#include <limits.h>
int maxGoodSubarraySum(std::vector<int>& nums, int k) {
std::unordered_map<int, int> hashMap;
int maxSum = INT_MIN;
for (int j = 0; j < nums.size(); ++j) {
hashMap[nums[j]] = j;
}
for (int i = 0; i < nums.size(); ++i) {
int sum = 0;
for (int j = i; j < nums.size(); ++j) {
sum += nums[j];
if (hashMap.find(nums[j] - k) != hashMap.end()) {
maxSum = std::max(maxSum, sum);
}
}
}
return maxSum == INT_MIN ? 0 : maxSum;
}
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5, 6};
int k = 1;
std::cout << maxGoodSubarraySum(nums, k) << std::endl;
return 0;
}function maxGoodSubarraySum(nums, k) {
const holders = new Map();
let maxSum = -Infinity;
nums.forEach(num => holders.set(num, true));
for (let i = 0; i < nums.length; i++) {
let currentSum = 0;
for (let j = i; j < nums.length; j++) {
currentSum += nums[j];
if (holders.has(nums[j] - k)) {
maxSum = Math.max(maxSum, currentSum);
}
}
}
return maxSum === -Infinity ? 0 : maxSum;
}
const nums = [1, 2, 3, 4, 5, 6];
const k = 1;
console.log(maxGoodSubarraySum(nums, k));#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define HASH_TABLE_SIZE 100003
typedef struct HashNode {
int key;
int value;
struct HashNode* next;
} HashNode;
HashNode* hashTable[HASH_TABLE_SIZE];
unsigned int hash(int key) {
return (unsigned int)key % HASH_TABLE_SIZE;
}
void insert(int key, int value) {
unsigned int index = hash(key);
HashNode* node = (HashNode*)malloc(sizeof(HashNode));
node->key = key;
node->value = value;
node->next = hashTable[index];
hashTable[index] = node;
}
HashNode* search(int key) {
unsigned int index = hash(key);
HashNode* node = hashTable[index];
while (node) {
if (node->key == key) return node;
node = node->next;
}
return NULL;
}
int maxGoodSubarraySum(int* nums, int numsSize, int k) {
for (int i = 0; i < HASH_TABLE_SIZE; ++i) hashTable[i] = NULL;
int maxSum = INT_MIN;
for (int i = 0; i < numsSize; ++i) {
int sum = 0;
for (int j = i; j < numsSize; ++j) {
sum += nums[j];
int key = nums[j] - k;
HashNode* node = search(key);
if (node) {
maxSum = maxSum > sum ? maxSum : sum;
}
}
insert(nums[i], sum);
}
return maxSum == INT_MIN ? 0 : maxSum;
}
int main() {
int nums[] = {1, 2, 3, 4, 5, 6};
int k = 1;
printf("%d\n", maxGoodSubarraySum(nums, 6, k));
return 0;
}using System;
using System.Collections.Generic;
public class Solution {
public int MaxGoodSubarraySum(int[] nums, int k) {
var map = new Dictionary<int, int>();
int maxSum = int.MinValue;
foreach (var num in nums) {
if (!map.ContainsKey(num))
map[num] = 0;
}
for (int i = 0; i < nums.Length; i++) {
int sum = 0;
for (int j = i; j < nums.Length; j++) {
sum += nums[j];
if (map.ContainsKey(nums[j] - k)) {
maxSum = Math.Max(maxSum, sum);
}
}
}
return maxSum == int.MinValue ? 0 : maxSum;
}
public static void Main() {
int[] nums = {1, 2, 3, 4, 5, 6};
int k = 1;
Console.WriteLine(new Solution().MaxGoodSubarraySum(nums, k));
}
}The Python solution uses dictionary storage to keep all potential starting integer values, which are then used during iteration to establish valid subarrays and calculate their sums.
Time Complexity: O(n^2).
Space Complexity: O(n) for the dictionary.
Approach 3: Prefix Sum + Hash Table
We use a hash table p to record the sum s of the prefix array nums[0..i-1] for nums[i]. If there are multiple identical nums[i], we only keep the smallest s. Initially, we set p[nums[0]] to 0. In addition, we use a variable s to record the current prefix sum, initially s = 0. Initialize the answer ans to -infty.
Next, we enumerate nums[i], and maintain a variable s to represent the sum of nums[0..i]. If nums[i] - k is in p, then we have found a good subarray, and update the answer to ans = max(ans, s - p[nums[i] - k]). Similarly, if nums[i] + k is in p, then we have also found a good subarray, and update the answer to ans = max(ans, s - p[nums[i] + k]). Then, if i + 1 \lt n and nums[i + 1] is not in p, or p[nums[i + 1]] \gt s, we set p[nums[i + 1]] to s.
Finally, if ans = -infty, then we return 0, otherwise return ans.
The time complexity is O(n), and the space complexity is O(n). Here, n is the length of the array.
function maximumSubarraySum(nums: number[], k: number): number {
const p: Map<number, number> = new Map();
p.set(nums[0], 0);
let ans: number = -Infinity;
let s: number = 0;
const n: number = nums.length;
for (let i = 0; i < n; ++i) {
s += nums[i];
if (p.has(nums[i] - k)) {
ans = Math.max(ans, s - p.get(nums[i] - k)!);
}
if (p.has(nums[i] + k)) {
ans = Math.max(ans, s - p.get(nums[i] + k)!);
}
if (i + 1 < n && (!p.has(nums[i + 1]) || p.get(nums[i + 1])! > s)) {
p.set(nums[i + 1], s);
}
}
return ans === -Infinity ? 0 : ans;
}func maximumSubarraySum(nums []int, k int) int64 {
p := map[int]int64{nums[0]: 0}
var s int64 = 0
n := len(nums)
var ans int64 = math.MinInt64
for i, x := range nums {
s += int64(x)
if t, ok := p[nums[i]-k]; ok {
ans = max(ans, s-t)
}
if t, ok := p[nums[i]+k]; ok {
ans = max(ans, s-t)
}
if i+1 == n {
break
}
if t, ok := p[nums[i+1]]; !ok || s < t {
p[nums[i+1]] = s
}
}
if ans == math.MinInt64 {
return 0
}
return ans
}Complexity comparison
| Approach | Complexity |
|---|---|
| Two Pointers Approach | Time Complexity: O(n^3). |
| HashMap for Start Index Distribution | Time Complexity: O(n^2). |
| Prefix Sum + Hash Table | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Two Pointers with Prefix Sum | O(n) | O(n) | When scanning the array once while evaluating candidate boundaries using prefix sums |
| HashMap + Prefix Sum (Optimal) | O(n) | O(n) | General case; best choice when fast lookups for values differing by k are required |
Frequently asked questions
Is Maximum Good Subarray Sum easy or hard?
Maximum Good Subarray Sum is rated Medium difficulty. The challenge lies in recognizing that the condition on the first and last elements can be converted into hash lookups combined with prefix sum subtraction.
Maximum Good Subarray Sum Python/Java solution
Python and Java solutions typically maintain a running prefix sum and a HashMap or dictionary mapping numbers to the smallest prefix sum seen before them. During iteration, the algorithm checks for values differing by k and updates the maximum subarray sum accordingly.
How to solve Maximum Good Subarray Sum in O(n)?
Maintain a running prefix sum while iterating through the array. For each element x, check if x - k or x + k appeared earlier using a hash map that stores the smallest prefix sum before those values. Subtracting that stored prefix from the current prefix gives the subarray sum candidate in constant time.
What is the best approach for Maximum Good Subarray Sum?
The most efficient approach uses a prefix sum combined with a hash map. While iterating through the array, store the minimum prefix sum seen for each value and check if values differing by k exist. This allows computing candidate subarray sums in constant time, producing an overall O(n) time complexity.
Is Maximum Good Subarray Sum asked at Google/Amazon/Meta?
Problems involving prefix sums, hash maps, and subarray optimization frequently appear in interviews at companies like Amazon, Google, and Meta. Variants of this problem test the ability to transform subarray conditions into prefix sum lookups.
What data structure is used in Maximum Good Subarray Sum?
The key data structures are a hash map for constant-time value lookup and a prefix sum array or running prefix variable for quick subarray sum computation. This combination allows evaluating candidate subarrays without nested loops.
What is the time complexity of Maximum Good Subarray Sum?
The optimal algorithm runs in O(n) time because the array is scanned once and each lookup in the hash map takes constant time on average. The space complexity is O(n) to store prefix sums or value mappings.
