Prefix Sum & HashMap - Summary

93 阅读3分钟

Core Concept of Prefix Sum

Prefix Sum is a technique used to efficiently calculate the sum of subarrays. It allows us to preprocess sums to avoid redundant calculations during queries.

Key formula:

prefixSum[j]−prefixSum[i]=target

Rearrange:

prefixSum[i]=prefixSum[j]−target

Using a HashMap, we store previous prefix sums and their indices, which enables us to find subarrays efficiently.

🔹 Problem Patterns & HashMap Usage

Pattern**Problem TypeKey HashMap ConceptHashMap Key (Prefix Sum)HashMap Value (Stored Information)
Fixed sum matchFind shortest subarray with sum == targetCheck if prefixSum[j] - target exists in the mapprefixSum values encounteredIndex where that prefixSum first appeared
Fixed sum countCount subarrays with sum == targetCount occurrences of prefixSum[j] - targetprefixSum values encounteredFrequency of each prefixSum
Modulo conditionLongest subarray with sum % k == 0Check if prefixSum[j] % k has appeared beforeprefixSum % k valuesFirst occurrence index
Balanced sumLongest contiguous subarray with equal number of 0 and 1Convert 0 to -1, check prefixSum[j]prefixSum valuesFirst occurrence index
Closest sumSubarray with sum closest to targetUse TreeMap for nearest lookupprefixSum valuesIndex where that prefixSum first appeared

🔹 Problem Summaries & Key Insights**

1️⃣ Shortest Subarray with Sum == Target**

  • Key Idea:Maintain a prefix sum while iterating, store previous sums in a HashMap.
  • HashMap Stores:(prefixSum → first index where it appears)
  • Logic: If prefixSum[j] - target exists in the map, we update the shortest length.

public int shortestSubarray(int[] nums, int target) {
   int shortest = Integer.MAX_VALUE, sum = 0;
   Map<Integer, Integer> map = new HashMap<>();
   map.put(0, -1);

   for (int j = 0; j < nums.length; j++) {
      sum += nums[j];
      if (map.containsKey(sum - target)) {
         shortest = Math.min(shortest, j - map.get(sum - target));
      }
      map.put(sum, j);
   }
   return shortest == Integer.MAX_VALUE ? -1 : shortest;
}

✅ Use case:Find a fixed-length window with a required sum.

2️⃣ Longest Subarray with Sum == Target**

  • Key Idea: Use HashMap to store the first occurrence of each prefix sum.
  • HashMap Stores: (prefixSum → first occurrence index)
  • Logic: If prefixSum[j] - target exists, update longest length.

public int longestSubarray(int[] nums, int target) { int longest = Integer.MIN_VALUE, sum = 0; Map<Integer, Integer> map = new HashMap<>(); map.put(0, -1);

for (int j = 0; j < nums.length; j++) { sum += nums[j]; if (map.containsKey(sum - target)) { longest = Math.max(longest, j - map.get(sum - target)); } map.putIfAbsent(sum, j); } return longest == Integer.MIN_VALUE ? 0 : longest; }

✅ Use case: Finding the longest matching subarray.

3️⃣ Count Subarrays with Sum == Target**

  • Key Idea:Instead of finding a single match, count all occurrences where prefixSum[j] - target appeared before.
  • HashMap Stores: (prefixSum → frequency count)`
  • Logic: If prefixSum[j] - target is in the map, add its frequency to the count.

public int countSubarray(int[] nums, int target) {
   int result = 0, sum = 0;
   Map<Integer, Integer> map = new HashMap<>();
   map.put(0, 1);

   for (int j = 0; j < nums.length; j++) {
      sum += nums[j];
      result += map.getOrDefault(sum - target, 0);
      map.put(sum, map.getOrDefault(sum, 0) + 1);
   }
   return result;
}

✅ Use case:Counting frequency of subarrays meeting a condition.

4️⃣ Subarray with Sum Closest to Target

  • Key Idea: Instead of exact matches, find the closest prefixSum[i] using a TreeMap.
  • TreeMap Stores: (prefixSum → index)
  • Logic: Use floorKey() and ceilingKey() to find the nearest sum.

public int closestSubarray(int[] nums, int target) {
   int closest = Integer.MAX_VALUE, sum = 0;
   TreeMap<Integer, Integer> prefixMap = new TreeMap<>();
   prefixMap.put(0, -1);

   for (int j = 0; j < nums.length; j++) {
      sum += nums[j];
      Integer floor = prefixMap.floorKey(sum - target);
      Integer ceil = prefixMap.ceilingKey(sum - target);

      if (floor != null) closest = Math.min(closest, Math.abs(sum - floor - target));
      if (ceil != null) closest = Math.min(closest, Math.abs(sum - ceil - target));

      prefixMap.put(sum, j);
   }
   return closest;
}

Use case: Finding the closest sum rather than an exact match.


5️⃣ Longest Subarray Where Sum % k == 0

  • Key Idea: If two prefix sums have the same remainder when divided by k, their difference is divisible by k.
  • HashMap Stores: (prefixSum % k → first occurrence index)

public int longestSubarrayDivK(int[] nums, int k) {
   int longest = 0, sum = 0;
   Map<Integer, Integer> remainderIndex = new HashMap<>();
   remainderIndex.put(0, -1);

   for (int j = 0; j < nums.length; j++) {
      sum += nums[j];
      int remainder = sum % k;
      if (remainder < 0) remainder += k;  // Handle negative cases

      if (remainderIndex.containsKey(remainder)) {
         longest = Math.max(longest, j - remainderIndex.get(remainder));
      } else {
         remainderIndex.put(remainder, j);
      }
   }
   return longest;
}

✅ Use case:Finding divisibility conditions in subarrays.

6️⃣ Contiguous Array (Equal 0s and 1s)**

  • Key Idea:Convert 0 to -1 and use prefix sum.
  • HashMap Stores: (prefixSum → first occurrence index)

public int findMaxLength(int[] nums) {
   Map<Integer, Integer> map = new HashMap<>();
   map.put(0, -1);

   int maxLength = 0, prefixSum = 0;

   for (int i = 0; i < nums.length; i++) {
      prefixSum += (nums[i] == 1) ? 1 : -1;

      if (map.containsKey(prefixSum)) {
         maxLength = Math.max(maxLength, i - map.get(prefixSum));
      } else {
         map.put(prefixSum, i);
      }
   }
   return maxLength;
}

✅ Use case: Finding the longest balanced subarray.

🔹 Key Differences & Common Mistakes

TypeExact MatchFrequency CountClosest MatchModulo Condition
MethodprefixSum[j] - target == prefixSum[i]count += map.get(prefixSum[j] - target)floorKey() & ceilingKey()prefixSum[j] % k == prefixSum[i] % k
HashMap UseFirst occurrence indexFrequency countOrdered Map (TreeMap)First occurrence index

✅ AI & ML Value:

  • Time-series forecasting (e.g., anomaly detection in logs)
  • NLP Sequence Analysis (e.g., detecting patterns in text)
  • Fraud Detection (e.g., detecting abnormal spending sequences)

🔹 Summary

  • Use HashMap for exact match problems (shortest, longest, count)
  • Use TreeMap for closest match problems (binary search needs)
  • Modulo-based problems leverage remainder relationships
  • Common mistakes: Not handling negative cases, incorrect prefix sum initialization.

**Mastering Prefix Sum + HashMap is essential for solving a broad range of subarray problems efficiently! 🚀