Files
cpp-flashcards/org/questions/qn_01.org
T

8.8 KiB

Master Subarray Pattern Sheet

Subarray Divisible by K — Remainder Pattern [algorithm:array]

Front

Why does "subarray sum divisible by K" work with prefix remainders?

Back

If Sum(i..j) mod K = 0, then: (Prefix[j] - Prefix[i-1]) mod K = 0

By modular arithmetic: Prefix[j] mod K = Prefix[i-1] mod K

So we find pairs of indices with the same prefix remainder.

Transformation: store current_sum % K in hash map.

Data structure: hash map tracking frequencies of remainders.

C++ caveat: % can return negative for negative operands. Fix: remainder = ((prefix_sum % K) + K) % K

Python: % always non-negative, no fix needed.

Subarray Equal 0s and 1s — Value Mapping [algorithm:array]

Front

Find the longest subarray with equal number of 0s and 1s. Example: nums = [0,1] → Output: 2

Back

Replace all 0s with -1. The problem becomes: "Find a subarray whose sum equals 0."

int findMaxLength(vector<int>& nums) {
    unordered_map<int,int> firstOccurrence;
    firstOccurrence[0] = 0;
    int sum = 0, maxLen = 0;
    for (int i = 0; i < nums.size(); i++) {
        sum += (nums[i] == 1) ? 1 : -1;
        if (firstOccurrence.count(sum)) {
            maxLen = max(maxLen, i + 1 - firstOccurrence[sum]);
        } else {
            firstOccurrence[sum] = i + 1;
        }
    }
    return maxLen;
}

Time: O(n), Space: O(n)

Data structure: hash map tracking raw prefix sums (first occurrence).

Subarray Equal Odd/Even Numbers — Same Pattern [algorithm:array]

Front

Find the longest subarray with equal number of odd and even numbers.

Back

Map every even number to +1 and every odd number to -1. The problem becomes: "Find a subarray whose sum equals 0."

Same approach as equal 0s and 1s: prefix sum + hash map storing first occurrence.

This is the same value mapping pattern applied to a different domain.

Subarray Equal Vowels and Consonants [algorithm:array]

Front

Find the longest subarray with equal number of vowels and consonants.

Back

Map: vowel → +1, consonant → -1. The problem becomes: "Find a subarray whose sum equals 0."

Same prefix sum + hash map approach.

This demonstrates the general principle: any binary-counting problem can be reduced to "subarray sum = 0" via value mapping.

Multi-Category Balance — Equal A/B/C Counts [algorithm:array]

Front

Find the longest subarray with equal number of 'A's, 'B's, and 'C's.

Back

You can't use a single scalar (+1/-1) for three categories. Track relative differences between counts.

Maintain running counts: c_A, c_B, c_C. At each step, compute the tuple of differences: (c_A - c_B, c_B - c_C).

If this tuple repeats later in the array, the elements between those indices have perfectly balanced A, B, C counts.

Data structure: hash map where the key is the state tuple: map<pair<int,int>, int> firstOccurrence;

The tuple (diff_AB, diff_BC) captures the full relative state. If two positions share the same tuple, the subarray between them has zero net change in all three relative differences → equal counts.

Time: O(n), Space: O(n)

Subarray Product Equals K — Prefix Product [algorithm:array]

Front

Find the number of subarrays with product equal to K.

Back

Use a Prefix Product array: Product(i..j) = PrefixProduct[j] / PrefixProduct[i-1]

Instead of subtracting, you divide.

Data structure: hash map searching for current_product / K.

Edge case: zeros reset the product to 0. Handle by:

  1. Segmentation — split the array at zeros, solve each segment independently
  2. Track position of last seen zero to reset boundaries

Example: subarray product less than K (all positive):

int numSubarrayProductLessThanK(vector<int>& nums, int k) {
    if (k <= 1) return 0;
    int count = 0, product = 1, left = 0;
    for (int right = 0; right < nums.size(); right++) {
        product *= nums[right];
        while (left <= right && product >= k) product /= nums[left++];
        count += right - left + 1;
    }
    return count;
}

Subarray Product Positive/Negative — Parity Tracking [algorithm:array]

Front

Find the maximum length of a subarray with a positive (or negative) product.

Back

Map: positive → +1, negative → -1, zero → resets the window.

A subarray has positive product if it contains an even number of negatives. A subarray has negative product if it contains an odd number of negatives.

Track the parity (odd/even count) of negative numbers as you traverse:

  • If parity is even at index i and was even at index j (j < i), the subarray (j+1..i) has positive product.
  • If parity is odd at index i and was even at index j, the subarray (j+1..i) has negative product.

Data structure: two hash maps — first occurrence of even-parity index and first occurrence of odd-parity index.

Time: O(n), Space: O(n)

Subarray Bitwise XOR — Prefix XOR [algorithm:array]

Front

Find the number of subarrays with XOR equal to K.

Back

XOR is invertible (XOR is its own inverse), so the prefix pattern works: XOR(i..j) = PrefixXOR[j] ^ PrefixXOR[i-1]

Same hash map pattern as prefix sum:

int subarrayXOR(vector<int>& nums, int k) {
    unordered_map<int,int> prefixCount;
    prefixCount[0] = 1;
    int sum = 0, count = 0;
    for (int num : nums) {
        sum ^= num;
        count += prefixCount[sum ^ k];
        prefixCount[sum]++;
    }
    return count;
}

Time: O(n), Space: O(n)

Subarray Bitwise OR/AND — Non-Invertible [algorithm:array]

Front

Can you use prefix sums for subarray problems with Bitwise OR or AND?

Back

NO. Unlike XOR, OR/AND are not invertible. You cannot "undo" an OR or AND operation.

Exploit the key property: as you expand a subarray, the OR/AND result can only change at most 32 times (for 32-bit integers) because bits only transition 0→1 (OR) or 1→0 (AND).

Strategy: maintain a set of all possible OR results ending at the current index. The set never exceeds size 32.

int subarrayBitwiseORs(vector<int>& arr) {
    unordered_set<int> result, current;
    for (int x : arr) {
        unordered_set<int> next;
        next.insert(x);
        for (int val : current) {
            next.insert(val | x);
        }
        current = next;
        for (int val : current) result.insert(val);
    }
    return result.size();
}

Time: O(n * 32), Space: O(32) per step

Master Keyword-to-Algorithm Mapping [algorithm:interview]

Front

What is the master keyword-to-algorithm mapping for subarray problems?

Back

Problem Phrase Array Property Algorithm
"Continuous subarray + Sum = K" Only positive numbers Sliding Window (O(1) space)
"Continuous subarray + Sum = K" Positive & negative Prefix Sum + Hash Map (O(n) space)
"Divisible by K" or "Multiple of X" Any numbers Prefix Remainder + Hash Map (sum % K)
"Equal number of X and Y" Any numbers Value Mapping (X→1, Y→-1) + Prefix Sum Map
"Maximum / Minimum Sum" Any numbers Kadane's Algorithm (DP)
"Subarray Sum + Frequent Updates" Element mutations Fenwick Tree / Segment Tree
"Subarray product = K" No zeros Prefix Product (division)
"Subarray product positive/negative" Any numbers Parity tracking of negative count
"Subarray XOR = K" Any numbers Prefix XOR + Hash Map
"Subarray OR / AND" Any numbers Set of results (bounded by 32 changes)

Prefix State Generalization — The Unifying Concept [algorithm:concept]

Front

What is the "prefix state" generalization that unifies all subarray patterns?

Back

The core philosophy of prefix sums is: accumulate history as you traverse linearly, and use a hash map to track state.

Problem Mapping Reduces To
Equal 0s and 1s 0→-1, 1→+1 Subarray sum = 0
Equal odd/even even→+1, odd→-1 Subarray sum = 0
Equal vowels/consonants vowel→+1, consonant→-1 Subarray sum = 0
Equal A/B/C counts Track (c_A-c_B, c_B-c_C) Prefix state tuple repeats
Subarray product Prefix product Division (handle zeros)
Subarray XOR Prefix XOR XOR is invertible
Subarray sum Prefix sum Subtraction

The pattern:

  1. Define a state that accumulates as you traverse
  2. Find a way to "undo" or compare states (subtract, XOR, divide, compare tuples)
  3. Use a hash map to find when the same state (or target difference) appears