Maximum Prefix Subarray Sum — Problem Statement & Solution Guide
Quick Answer & Algorithm Key Takeaway
Master coding challenges related to Arrays and solve the Maximum Prefix Subarray Sum problem optimally.
O(n+|pref|)O(n)Problem Description
Given an integer array nums and a second integer array pref, determine the largest possible sum of a contiguous subarray of nums that begins with the exact sequence pref. Formally, find an index i such that nums[i..i+|pref|-1] equals pref, then choose an end index j ≥ i+|pref|-1 and compute the sum S = Σ_{k=i}^{j} nums[k]. Among all valid pairs (i, j) return the maximum S. If pref does not appear as a contiguous subsequence of nums, output 0.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Maximum Prefix Subarray Sum"
WHY DOES IT MATTER?
Many real‑world queries ask for the best performance metric that must begin with a known signature (e.g., a transaction log that starts with a specific event). Recognizing the pattern‑first constraint and then optimizing the continuation is a recurring algorithmic motif.
OPTIMIZATION CHALLENGE
The key insight is decoupling the two phases: locate all valid starts in linear time, then pre‑compute the maximum suffix of the prefix‑sum array so each start can instantly retrieve the best possible end. This reduces the naïve O(n·|pref|) or O(n²) to O(n).
REAL-WORLD CONNECTION
Think of a network packet stream where a particular header sequence must be present; once the header is detected, you want to maximize throughput of the following payload. The header detection is pattern matching, and maximizing payload size is analogous to the maximum‑prefix sum.
In an interview, first state the two‑step plan (match then extend), write KMP or rolling hash for the match, then show the suffix‑max trick on prefix sums – this demonstrates both algorithmic breadth and depth.
COMPLEXITY AT A GLANCE
O(n+|pref|)O(n)Core Theory — Why This Approach?
The problem combines pattern matching with a variant of the maximum‑prefix subarray problem. First we must locate every index i where the sub‑array nums[i..i+|pref|-1] exactly equals pref. A naïve scan for each possible i would be O(n·|pref|) and quickly becomes infeasible for large n (up to 10^5 or more). Efficient string‑matching algorithms such as KMP or rolling‑hash (Rabin‑Karp) treat the integer arrays as strings and locate all occurrences in O(n+|pref|) time. Once an occurrence is found, the remaining task is to extend the subarray to the right to maximize its sum while preserving contiguity. This reduces to finding, for each start i, the maximum value of prefixSum[j+1]‑prefixSum[i] for j≥i+|pref|-1, i.e. the maximum suffix of the prefix‑sum array. By pre‑computing the suffix maximum of the prefix‑sum array we can answer each occurrence in O(1), yielding an overall linear solution.
The optimal paradigm therefore intertwines two classic techniques: linear‑time pattern matching to satisfy the prefix constraint, and prefix‑sum + suffix‑maximum preprocessing to answer the “best extension” query instantly. This avoids the quadratic blow‑up of trying every possible end index for every match, which would be O(n²) in the worst case.
Interview Questions on This Problem
Q1How would you modify the solution if the subarray must start with pref but also end with another pattern suf?
First locate all start indices matching pref using KMP, then locate all end indices matching suf. For each start i, find the farthest end index j≥i+|pref|-1 that also begins suf; using a suffix‑maximum array of prefix sums restricted to valid end positions yields the maximum sum in O(n).
Q2What is the time‑space trade‑off if you replace KMP with a hash‑based Rabin‑Karp approach for finding pref?
Rabin‑Karp offers expected O(n) time with O(1) extra space but introduces a small probability of collision, requiring a verification step. KMP guarantees worst‑case O(n) without collisions but uses O(|pref|) extra space for the failure function. Both are linear, but KMP is deterministic.
Examples
Input
5 3 -2 5 -1 2 2 3 -2
Output
7
Explanation: The prefix [3,-2] matches the first two elements of nums. Possible subarrays starting there are: [3,-2] → sum = 1 [3,-2,5] → sum = 6 [3,-2,5,-1] → sum = 5 [3,-2,5,-1,2] → sum = 7 The maximum sum is 7.
Input
5 1 2 3 4 5 2 2 3
Output
14
Explanation: The prefix [2,3] occurs starting at index 1. Extending the subarray gives: [2,3] → sum = 5 [2,3,4] → sum = 9 [2,3,4,5] → sum = 14 The largest achievable sum is 14.
Input
4 -5 -1 -3 -2 2 -1 -3
Output
-4
Explanation: The prefix [-1,-3] matches nums[1..2]. The subarrays are: [-1,-3] → sum = -4 [-1,-3,-2] → sum = -6 The best (least negative) sum is -4.
Constraints
- 1 <= nums.length <= 100000
- 1 <= pref.length <= nums.length
- -10^9 <= nums[i] <= 10^9
- -10^9 <= pref[i] <= 10^9
Optimal Approach & Strategy
Use KMP (or rolling hash) to find all prefix matches in O(n), compute prefix sums, build a suffix‑max array of those sums, and evaluate each match in O(1).
Brute Force Approach
Check every possible start index, verify the prefix, then try every possible end index to compute the sum, keeping the maximum.
Code Solutions
// Node.js solution
function maxPrefixSubarraySum(nums, pref) {
const n = nums.length;
const m = pref.length;
if (m === 0) return 0; // empty prefix, any subarray – choose max subarray sum (Kadane) but not required here
const prefSum = new Array(n + 1).fill(0n);
for (let i = 0; i < n; ++i) prefSum[i + 1] = prefSum[i] + BigInt(nums[i]);
const suffixMax = new Array(n + 2).fill(-9223372036854775808n);
suffixMax[n] = prefSum[n];
for (let i = n - 1; i >= 0; --i) {
suffixMax[i] = prefSum[i] > suffixMax[i + 1] ? prefSum[i] : suffixMax[i + 1];
}
let best = -9223372036854775808n;
outer: for (let i = 0; i + m <= n; ++i) {
for (let k = 0; k < m; ++k) {
if (nums[i + k] !== pref[k]) continue outer;
}
const candidate = suffixMax[i + m] - prefSum[i];
if (candidate > best) best = candidate;
}
if (best === -9223372036854775808n) return 0;
return Number(best);
}
function main(){
const fs = require('fs');
const data = fs.readFileSync(0,'utf8').trim().split(/\s+/).map(Number);
let p=0;
const n=data[p++];
const nums=data.slice(p,p+n); p+=n;
const m=data[p++];
const pref=data.slice(p,p+m);
console.log(maxPrefixSubarraySum(nums,pref).toString());
}
main();#include <bits/stdc++.h>
using namespace std;
long long maxPrefixSubarraySum(const vector<int>& nums, const vector<int>& pref){
int n = nums.size();
int m = pref.size();
if(m==0) return 0; // empty prefix yields any subarray, choose max subarray sum (Kadane)
// prefix sums of nums
vector<long long> prefSum(n+1,0);
for(int i=0;i<n;++i) prefSum[i+1]=prefSum[i]+nums[i];
// suffix maximum of prefSum
vector<long long> suffixMax(n+2,LLONG_MIN);
suffixMax[n]=prefSum[n];
for(int i=n-1;i>=0;--i) suffixMax[i]=max(prefSum[i],suffixMax[i+1]);
long long best = LLONG_MIN;
for(int i=0;i+ m <= n; ++i){
bool ok=true;
for(int k=0;k<m;++k){
if(nums[i+k]!=pref[k]){ ok=false; break; }
}
if(!ok) continue;
// we need max_{j >= i+m-1} sum(i..j) = max_{t >= i+m} prefSum[t] - prefSum[i]
long long candidate = suffixMax[i+m] - prefSum[i];
best = max(best, candidate);
}
if(best==LLONG_MIN) return 0; // pref not found
return best;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n; if(!(cin>>n)) return 0;
vector<int> nums(n);
for(int i=0;i<n;++i) cin>>nums[i];
int m; cin>>m;
vector<int> pref(m);
for(int i=0;i<m;++i) cin>>pref[i];
cout<<maxPrefixSubarraySum(nums,pref);
return 0;
}import java.io.*;
import java.util.*;
public class Main {
static long maxPrefixSubarraySum(int[] nums, int[] pref) {
int n = nums.length;
int m = pref.length;
if (m == 0) return 0L;
long[] prefSum = new long[n + 1];
for (int i = 0; i < n; i++) prefSum[i + 1] = prefSum[i] + nums[i];
long[] suffixMax = new long[n + 2];
Arrays.fill(suffixMax, Long.MIN_VALUE);
suffixMax[n] = prefSum[n];
for (int i = n - 1; i >= 0; i--) {
suffixMax[i] = Math.max(prefSum[i], suffixMax[i + 1]);
}
long best = Long.MIN_VALUE;
outer:
for (int i = 0; i + m <= n; i++) {
for (int k = 0; k < m; k++) {
if (nums[i + k] != pref[k]) continue outer;
}
long candidate = suffixMax[i + m] - prefSum[i];
if (candidate > best) best = candidate;
}
return best == Long.MIN_VALUE ? 0L : best;
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int[] nums = new int[n];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) nums[i] = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
int m = Integer.parseInt(st.nextToken());
int[] pref = new int[m];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < m; i++) pref[i] = Integer.parseInt(st.nextToken());
System.out.println(maxPrefixSubarraySum(nums, pref));
}
}import sys
def max_prefix_subarray_sum(nums, pref):
n = len(nums)
m = len(pref)
if m == 0:
return 0
# prefix sums
pref_sum = [0]
for x in nums:
pref_sum.append(pref_sum[-1] + x)
# suffix max of prefix sums
suffix_max = [float('-inf')] * (n + 2)
suffix_max[n] = pref_sum[n]
for i in range(n - 1, -1, -1):
suffix_max[i] = max(pref_sum[i], suffix_max[i + 1])
best = None
for i in range(n - m + 1):
if nums[i:i + m] != pref:
continue
candidate = suffix_max[i + m] - pref_sum[i]
if best is None or candidate > best:
best = candidate
return best if best is not None else 0
def main():
data = list(map(int, sys.stdin.read().strip().split()))
if not data:
return
it = iter(data)
n = next(it)
nums = [next(it) for _ in range(n)]
m = next(it)
pref = [next(it) for _ in range(m)]
print(max_prefix_subarray_sum(nums, pref))
if __name__ == "__main__":
main()// Node.js solution
function maxPrefixSubarraySum(nums, pref) {
const n = nums.length;
const m = pref.length;
if (m === 0) return 0; // empty prefix, any subarray – choose max subarray sum (Kadane) but not required here
const prefSum = new Array(n + 1).fill(0n);
for (let i = 0; i < n; ++i) prefSum[i + 1] = prefSum[i] + BigInt(nums[i]);
const suffixMax = new Array(n + 2).fill(-9223372036854775808n);
suffixMax[n] = prefSum[n];
for (let i = n - 1; i >= 0; --i) {
suffixMax[i] = prefSum[i] > suffixMax[i + 1] ? prefSum[i] : suffixMax[i + 1];
}
let best = -9223372036854775808n;
outer: for (let i = 0; i + m <= n; ++i) {
for (let k = 0; k < m; ++k) {
if (nums[i + k] !== pref[k]) continue outer;
}
const candidate = suffixMax[i + m] - prefSum[i];
if (candidate > best) best = candidate;
}
if (best === -9223372036854775808n) return 0;
return Number(best);
}
function main(){
const fs = require('fs');
const data = fs.readFileSync(0,'utf8').trim().split(/\s+/).map(Number);
let p=0;
const n=data[p++];
const nums=data.slice(p,p+n); p+=n;
const m=data[p++];
const pref=data.slice(p,p+m);
console.log(maxPrefixSubarraySum(nums,pref).toString());
}
main();Asked in Top Tech Interviews
Solve in Interative Editor
Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.