GeeksforGeeks Hard

Count Subarrays with XOR K

Count Subarrays with XOR K is a GFG problem (Medium), listed there as Count Subarrays with given XOR; it has no LeetCode number of its own. You are given an array arr of non-negative integers and an integer k. Return how many subarrays have a bitwise XOR equal to k.

  • A subarray is a contiguous, non-empty run of elements. Two subarrays with the same values at different positions count separately.
  • The XOR of a subarray is all of its elements combined with ^.
  • The array can hold up to 10⁵ elements. There are about n²/2 subarrays, so listing them is too slow, and the answer itself can exceed the range of a 32-bit int.
Constraints
  • 1 <= arr.length <= 10⁵
  • 0 <= arr[i] <= 10⁵
  • 0 <= k <= 10⁵
arraybit-manipulationhash-table
Open on GeeksforGeeks ↗
02

Intuition

Describe a subarray by two prefixes instead of by its two ends. Let P[j] be the XOR of arr[0..j], with P[-1] = 0 for the empty prefix. Because x ^ x = 0, the elements two prefixes share cancel out:

XOR(arr[i+1..j]) = P[j] ^ P[i]

Setting that equal to k and XOR-ing both sides with P[j] turns it around: P[i] = P[j] ^ k. So the number of good subarrays ending at j is simply how many earlier prefixes equal P[j] ^ k. A hash map from prefix value to how often it has appeared answers that in one lookup, which turns O(n²) pairs into one pass.

How to spot this pattern

"Count subarrays whose combined value equals k" where the combining operation can be undone (+ undone by -, ^ undone by ^) is the prefix + frequency map pattern. To count subarrays with given XOR k, swap - for ^ in the subarray-sum-equals-k solution. The pattern does not apply to AND or OR, because those cannot be undone.

03

Approach

Try it first

Before reading on: write the XOR of arr[i+1..j] using two prefix XORs, solve it for the earlier prefix, and decide what the map must hold before the first element is read. Aim for O(n) time.

1

Seed the map with the empty prefix

seen = {0: 1}, prefix = 0, count = 0. The entry 0: 1 is the empty prefix before index 0. Without it, a subarray that starts at index 0 has no earlier prefix to pair with and is never counted.

2

Extend the prefix XOR

For each x, do prefix ^= x. Now prefix is the XOR of everything from index 0 to here: the P[j] that the lookup pairs with an earlier prefix.

3

Count the subarrays ending here

count += seen.get(prefix ^ k, 0). Every earlier prefix equal to prefix ^ k marks a different start, so add the whole count, not 1.

4

Record this prefix, after the lookup

seen[prefix] += 1. Recording only after the lookup means the current prefix is never paired with itself, which would count an empty subarray when k = 0.

04

Count Subarrays with XOR K solution in Python | C++ | Java

▶1class Solution:
▶2 def subarrayXor(self, arr, k):
▶3 seen = {0: 1}
▶4 prefix = 0
▶5 count = 0
▶6 for x in arr:
▶7 prefix ^= x
▶8 count += seen.get(prefix ^ k, 0)
▶9 seen[prefix] = seen.get(prefix, 0) + 1
▶10 return count
arrprefix0412223644count0seenprefixtimes01k = 6, seen = {0: 1}
seen{0: 1}the empty prefix
k6
count0
Seed seen = {0: 1}. The XOR of nothing is 0, and that empty prefix sits before index 0. A subarray starting at index 0 pairs with it; without this entry such subarrays would never be counted.
arrprefix04412223644lookupprefix1004⊕ k1106need0102count0+0seenprefixtimes012not seennothing ends here
prefix4XOR of arr[0..0]
need2prefix ^ k
count0+0
prefix = 4 after XOR-ing in 4. A subarray ending at index 0 has XOR 6 exactly when the prefix just before it is 4 ⊕ 6 = 2. No earlier prefix had that value, so no subarray ending here works.
arrprefix04412223644count0seenprefixtimes0141record prefix 4
seen[4]1new value
count0
Add prefix 4 to the map. It is recorded only after the lookup, so this position can never pair with itself as an empty subarray.
arrprefix044126223644lookupprefix1106⊕ k1106need0000count1+1seenprefixtimes01411 subarray ends here
prefix6XOR of arr[0..1]
need0prefix ^ k
count1+1
prefix = 6 after XOR-ing in 2. A subarray ending at index 1 has XOR 6 exactly when the prefix just before it is 6 ⊕ 6 = 0. The map says 0 was seen 1 time, so 1 subarray ends here, starting at index 0 (the start at 0 comes from the seeded empty prefix).
arrprefix044126223644count1seenprefixtimes014161record prefix 6
seen[6]1new value
count1
Prefix 6 is new, so it enters the map with tally 1. It now marks a possible start (index 2) for any later subarray whose prefix is 6 ⊕ 6 = 0.
arrprefix0441262243644lookupprefix1004⊕ k1106need0102count1+0seenprefixtimes0141612not seennothing ends here
prefix4XOR of arr[0..2]
need2prefix ^ k
count1+0
prefix = 4 after XOR-ing in 2. A subarray ending at index 2 has XOR 6 exactly when the prefix just before it is 4 ⊕ 6 = 2. No earlier prefix had that value, so no subarray ending here works.
arrprefix0441262243644count1seenprefixtimes014261record prefix 4
seen[4]2seen again
count1
Prefix 4 appeared before, so its tally goes up to 2. A later position that needs 4 will now pair with every one of these, each giving a different start.
arrprefix04412622436244lookupprefix0102⊕ k1106need1004count3+2seenprefixtimes0142612 subarrays end here
prefix2XOR of arr[0..3]
need4prefix ^ k
count3+2
prefix = 2 after XOR-ing in 6. A subarray ending at index 3 has XOR 6 exactly when the prefix just before it is 2 ⊕ 6 = 4. The map says 4 was seen 2 times, so 2 subarrays end here, starting at index 1 and 3. That is why the map keeps counts: a set would add only 1.
arrprefix04412622436244count3seenprefixtimes01426121record prefix 2
seen[2]1new value
count3
Prefix 2 is new, so it enters the map with tally 1. It now marks a possible start (index 4) for any later subarray whose prefix is 2 ⊕ 6 = 4.
arrprefix044126224362446lookupprefix1106⊕ k1106need0000count4+1seenprefixtimes014261211 subarray ends here
prefix6XOR of arr[0..4]
need0prefix ^ k
count4+1
prefix = 6 after XOR-ing in 4. A subarray ending at index 4 has XOR 6 exactly when the prefix just before it is 6 ⊕ 6 = 0. The map says 0 was seen 1 time, so 1 subarray ends here, starting at index 0 (the start at 0 comes from the seeded empty prefix).
arrprefix044126224362446count4seenprefixtimes01426221record prefix 6
seen[6]2seen again
count4
Prefix 6 appeared before, so its tally goes up to 2. A later position that needs 6 will now pair with every one of these, each giving a different start.
arrprefix044126224362446count4seenprefixtimes01426221return 4
result4
4 subarrays have XOR 6; the brackets mark every one. Each was found once, at its right end, by one lookup. One pass and one map: O(n) time instead of checking all 15 subarrays.
05

Brute force with a running XOR

For every start index, the inner loop extends the subarray one element at a time and keeps its XOR up to date, so each subarray is checked in O(1).

▶1class Solution:
▶2 def subarrayXor(self, arr, k):
▶3 count = 0
▶4 for i in range(len(arr)):
▶5 xor = 0
▶6 for j in range(i, len(arr)):
▶7 xor ^= arr[j]
▶8 if xor == k:
▶9 count += 1
▶10 return count
06

Common pitfalls

Starting with an empty map

✗ Wrong
seen = {}
✓ Right
seen = {0: 1}

A subarray starting at index 0 has XOR equal to the prefix itself, so it needs P[-1] = 0 as its partner. Without the seed, [6] with k = 6 returns 0 instead of 1.

Using a set instead of a counter

✗ Wrong
if prefix ^ k in seen_set:
    count += 1
✓ Right
count += seen.get(prefix ^ k, 0)

If the needed prefix appeared at three earlier positions, three different subarrays end here. A set can only say yes or no, so it undercounts whenever a prefix value repeats, which is common with small values.

Updating the map before the lookup

✗ Wrong
prefix ^= x
seen[prefix] = seen.get(prefix, 0) + 1
count += seen.get(prefix ^ k, 0)
✓ Right
prefix ^= x
count += seen.get(prefix ^ k, 0)
seen[prefix] = seen.get(prefix, 0) + 1

When k = 0, prefix ^ k is prefix, so the prefix just added matches itself and every position counts one extra empty subarray. For other k the order happens not to matter, which hides the bug.

Keeping the answer in a 32-bit int

✗ Wrong
int count = 0;
✓ Right
long count = 0;

With n = 10⁵ and every element 0, k = 0, every one of the n(n + 1)/2 ≈ 5 × 10⁹ subarrays counts. That overflows int in C++ and Java; the map's counts can stay int, the running total cannot.

07

Complexity

Time
O(n)
Space
O(n)
One pass, one hash lookup and one hash update per element (average O(1) each). The map holds at most n + 1 distinct prefix values.
08

Count subarrays with XOR k vs. its look-alikes

These share the prefix + hash map idea but differ in the operator, what the map stores, and the seed.

ProblemPartner prefixMap storesSeed
Count subarrays with XOR kprefix ^ khow many times seen{0: 1}
Subarray Sum Equals K (LeetCode 560)prefix − khow many times seen{0: 1}
Longest subarray with sum kprefix − kfirst index seen{0: −1}
09

Count Subarrays with XOR K FAQ

Is there a count subarrays with xor k LeetCode problem?

Not under that name; it comes from GFG and Striver's A2Z sheet. The closest LeetCode problems are 560 Subarray Sum Equals K (same pattern with -) and 1442 Count Triplets That Can Form Two Arrays of Equal XOR, which counts pairs of equal prefix XORs, the k = 0 case.

What does the count subarrays with xor k Python code look like with a Counter?

Use collections.Counter: seen = Counter({0: 1}), then in the loop prefix ^= x, count += seen[prefix ^ k], seen[prefix] += 1. A Counter returns 0 for missing keys, so the .get(..., 0) calls disappear.