Use prefix sum and store the count of sum in a hashmap. When map.containsKey(sum - k), it indicates that there is a subarray sum which equals k, add it to the result.
Add a record to map (map.put(0, 1)), this give the count between any number 0, in case that number equals k.
Addition to LC560, store the minimum subarray lens before i which sums to target in a min array. When the previous minimum prevMin exists, it means there is a subarray sums to sum - target. That lens is i - prevMin. The result is the current min and previous min, which is i - prevMin + min[prevMin].
Range Add Queries 2D: Difference Array Optimization
Problem Overview
Given an n × n matrix initialized to zeros, efficiently process multiple range update queries where each query adds 1 to all cells in a rectangular region [r1,c1] to [r2,c2].
Visual Demo
Example: n = 4, Queries: [[1,1,2,2], [0,0,1,1]]
Step 1: Process Query 1 - Add 1 to region [1,1] to [2,2]
Apply Difference Array Technique:
Step 2: Process Query 2 - Add 1 to region [0,0] to [1,1]
Accumulate difference markers:
Step 3: Apply Prefix Sum (Row-wise)
Convert difference array to actual values:
Final Result Matrix:
Algorithm Breakdown
Phase 1: Difference Array Setup
For each query [r1, c1, r2, c2]:
Visual for Query [1,1,2,2]:
Phase 2: Prefix Sum Restoration
Row-by-row transformation:
Key Insights
Difference Array Magic
Range increment[L, R] becomes two point updates: +1 at L, -1 at R+1
Prefix sum converts difference markers back to actual incremented values
Time complexity drops from O(Q × R × C) to O(Q × R + R × C)
Why This Works
Lazy marking: Instead of updating every cell immediately, mark range boundaries
Batch processing: Apply all difference markers first, then compute final values
Cumulative effect: Multiple queries naturally accumulate at marked positions
Time Complexity: O(Q × R + R × C) where Q = queries, R = rows, C = columns
Space Complexity: O(1) extra space (in-place on result matrix)
This technique is particularly powerful when the number of queries is large, transforming what would be expensive range updates into efficient boundary marking operations.
public int subarraySum(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
int sum = 0, result = 0;
for (int n : nums) {
sum += n;
if (map.containsKey(sum - k)) {
result += map.get(sum - k);
}
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
return result;
}
public int minSumOfLengths(int[] arr, int target) {
Map<Integer, Integer> map = new HashMap<>();
int sum = 0;
map.put(0, -1);
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
map.put(sum, i);
}
sum = 0;
int one = Integer.MAX_VALUE, res = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
if (map.containsKey(sum - target)) {
one = Math.min(one, i - map.get(sum - target));
}
if (map.containsKey(sum + target) && one != Integer.MAX_VALUE) {
res = Math.min(res, one + (map.get(sum + target) - i));
}
}
return res == Integer.MAX_VALUE ? -1 : res;
}
public int minSumOfLengths(int[] arr, int target) {
Map<Integer, Integer> map = new HashMap<>();
map.put(0, -1);
int n = arr.length;
int[] min = new int[n];
Arrays.fill(min, Integer.MAX_VALUE);
int sum = 0;
int best = Integer.MAX_VALUE;
int res = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
sum += arr[i];
Integer prevMin = map.get(sum - target);
if (prevMin != null) {
if (prevMin != -1 && min[prevMin] != Integer.MAX_VALUE) {
res = Math.min(res, i - prevMin + min[prevMin]);
}
best = Math.min(best, i - prevMin);
}
min[i] = best;
map.put(sum, i);
}
return res == Integer.MAX_VALUE ? -1 : res;
}
public int minSumOfLengths(int[] arr, int target) {
int n = arr.length;
int best[] = new int[n];
Arrays.fill(best, Integer.MAX_VALUE);
int sum = 0, start = 0, ans = Integer.MAX_VALUE, bestSoFar = Integer.MAX_VALUE;
for(int i = 0; i < n; i++){
sum += arr[i];
while(sum > target){
sum -= arr[start];
start++;
}
if(sum == target){
if(start > 0 && best[start - 1] != Integer.MAX_VALUE){
ans = min(ans, best[start - 1] + i - start + 1);
}
bestSoFar = min(bestSoFar, i - start + 1);
}
best[i] = bestSoFar;
}
return ans == Integer.MAX_VALUE ? -1 : ans;
}
public boolean checkSubarraySum(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
map.put(0, -1);
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
if (k != 0) sum %= k;
if (map.containsKey(sum)) {
if (map.get(sum) < i - 1) return true;
} else {
map.put(sum, i);
}
}
return false;
}
public int maxSubArrayLen(int[] nums, int k) {
if (nums == null || nums.length == 0) return 0;
Map<Integer, Integer> map = new HashMap<>();
map.put(0, -1);
int sum = 0, res = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
if (map.containsKey(sum - k)) {
res = Math.max(res, i - map.get(sum - k));
}
if (!map.containsKey(sum)) map.put(sum, i);
}
return res;
}
def maxSubArrayLen(self, nums: List[int], k: int) -> int:
_dict = {}
_dict[0] = -1
_sum = 0
_min = sys.maxsize
for i in range(len(nums)):
_sum += nums[i]
if _sum - k in _dict:
_min = min(_min, i - _dict[_sum - k])
if _sum not in _dict:
_dict[_sum] = i
return 0 if _min == sys.maxsize else _min
public int maxProduct(int[] nums) {
int n = nums.length;
int[] pos = new int[n];
int[] neg = new int[n];
int max = nums[0];
pos[0] = neg[0] = nums[0];
for (int i = 1; i < n; i++) {
pos[i] = Math.max(Math.max(pos[i - 1] * nums[i], neg[i - 1] * nums[i]),
nums[i]);
neg[i] = Math.min(Math.min(pos[i - 1] * nums[i], neg[i - 1] * nums[i]),
nums[i]);
max = Math.max(max, pos[i]);
}
return max;
}
List<Integer> list;
public ProductOfNumbers() {
list = new ArrayList<>();
list.add(1);
}
public void add(int num) {
if (num > 0) {
list.add(list.get(list.size() - 1) * num);
} else {
list = new ArrayList<>();
list.add(1);
}
}
public int getProduct(int k) {
if (k >= list.size()) return 0;
return list.get(list.size() - 1) / list.get(list.size() - k - 1);
}
List<Integer> list;
TreeMap<Integer, int[]> memo; // start : [end, product]
public ProductOfNumbers() {
list = new ArrayList<>();
memo = new TreeMap<>();
}
public void add(int num) {
list.add(num);
}
public int getProduct(int k) {
int endIndex = list.size() - 1;
int startIndex = endIndex - k + 1;
int product = 1;
if (memo.containsKey(startIndex)) {
int[] temp = memo.get(startIndex);
int newend = temp[0];
product *= temp[1] * getProductBetween(newend + 1, endIndex);
} else if (memo.ceilingKey(startIndex) != null) {
int ceil = memo.ceilingKey(startIndex);
int[] temp = memo.get(ceil);
int newend = temp[0];
product *= getProductBetween(startIndex, ceil - 1) * temp[1] * getProductBetween(newend + 1, endIndex);
} else {
product = getProductBetween(startIndex, endIndex);
}
memo.put(startIndex, new int[]{endIndex, product});
return product;
}
private int getProductBetween(int start, int end) {
int product = 1;
for (int i = start; i <= end; i++) {
product *= list.get(i);
}
return product;
}
class Solution {
public int subarraysDivByK(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
int sum = 0, res = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
int remainder = ((sum % k) + k) % k;
int remainderCount = map.getOrDefault(remainder, 0);
res += remainderCount;
map.put(remainder, remainderCount + 1);
}
return res;
}
}
int minStartValue(vector<int>& nums) {
vector<int> prefix(nums.size(), 0);
int minVal = 0;
for (int i = 0; i < nums.size(); ++i) {
if (i == 0) {
prefix[i] = nums[i];
} else {
prefix[i] = nums[i] + prefix[i - 1];
}
minVal = min(minVal, prefix[i]);
}
return 1 - minVal;
}
class Solution {
public:
int pivotIndex(vector<int>& nums) {
int n = nums.size();
int sum = 0;
for (int num : nums) sum += num;
int prefixSum = 0;
for (int i = 0; i < n; ++i) {
if (prefixSum == sum - prefixSum - nums[i]) return i;
prefixSum += nums[i];
}
return -1;
}
};
Initial Matrix (4×4):
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
After Query 1 difference marking:
0 0 0 0
0 +1 0 -1 ← Row 1: +1 at col 1, -1 at col 3
0 +1 0 -1 ← Row 2: +1 at col 1, -1 at col 3
0 0 0 0
After Query 2 difference marking:
+1 0 -1 0 ← Row 0: +1 at col 0, -1 at col 2
+1 +1 0 -1 ← Row 1: +1 at col 0, +1 at col 1, -1 at col 3
0 +1 0 -1 ← Row 2: +1 at col 1, -1 at col 3
0 0 0 0