The problem is to find all the subarrays of the given array with xor of all its elements equal to zero.
For example, if array contains elements [13,8,5,3,3]
, the solution should give the indices of all subarrays like 0-2
, 3-4
, 0-4
, etc.
The question is similar to the one asked here
The only difference is that I want the indices of all the subarrays that satisfies the equation A0 xor A1 xor...xor An = 0
This is a fairly straightforward extension of the linked question. In Python,
# Multivalued map from the XOR of array[:i] to i for all i.
prefix_xor_to_stops = {0: [0]}
prefix_xor = 0
for j, x in range(array):
prefix_xor ^= x
# Returns the value associated with prefix_xor. Inserts [] if not present.
stops = prefix_xor_to_stops.setdefault(prefix_xor, [])
for i in stops:
yield (i, j+1)
stops.append(j+1)
As before, the idea is that a subarray array[i:j]
has XOR zero if and only if the XOR of array[:i]
equals the XOR of array[:j]
. For each subsequent element of the array, we compute the XOR of the prefix ending at that element from the XOR of the prefix ending at the previous element, then look up all of the solutions i
to the above equation. Then we insert the new association and continue.
If you have two different prefixes of the array with equal xor, let's say prefix of length x1 and prefix of length x2, then subarray from x1 + 1 to x2 has xor equal to 0. Make a dictionary (BST, hash table, whatever similar) and store there pairs (value of prefix sum, prefixes that gives that value). Any two elements with the same value give you one subarray. You can also find it using Trie if you like.
Using Trie:
At the beginning Trie consists of single node and no edges. We want to add to it numbers. It would also be convenient to index them, since we want to find all subarrays. Each node that represents some numbers (multiple in case of duplicates) in Trie will store list of their indices, so we can easily get the subarrays.
When we add a number n with an index i we write n as a binary number. We start from the initial node. If the most significant bit of n equals 0, if there exists an edge labelled 0 from our start then we move to a corresponding vertex, if not we create a new edge labelled 0 pointing to a new node, then we move to this newly created one (same thing for 1). Then we keep doing this until we iterated through every bit of n. We add index i to a list of indices in a node that we ended up in.
- Make variable prefsum = 0
- For each i = 1 to n:
- add prefsum to Trie with index i
- set prefsum = prefsum ^ array[i]
- check if there exists value prefsum in Trie. For each such value v, the subarray of xor equal to 0 is between indices v-th and i-th.
Total complexity is O(n * log(max value in array))
It may not be better than using BST or hash array, but it is a popular trick that especially shines in some problems with XOR operation.
If you want to modify the answer mentioned in the post then i hope you have understood that solution very well. Now the thing which is missing in that solution is that its only storing the first index occurrence of a particular prefix xor sum. Other indexes where the same xorSum occurs are not tracked. So what you have to do is modify map to keep a list(vector in C++) of indexes for each xorSum.
I will write the code blocks in Python 3.7
let l be list of tuples of (i,j)
The most efficient and simple way to deal with is problem is:
Step 1: calculate the xor of prefixes :
xorArr[0] = arr[0] #here arr = [13,8,5,3,3]
for i in range(1, n):
xorArr[i] = xorArr[i - 1] ^ arr[i]
Step 2: Check if at any point xorArr[i]=0, if yes then arr[:i+1] is one subarray whose xor is zero:
for i in range(1, n):
xorArr[i] = xorArr[i - 1] ^ arr[i]
if xorArr[i]==0:
l.append((0,i))
Step 3: Now make a dictionary to store list of indexes of each element occuring in xorArr
d = {xorArr[0]:[0]}
for x in range(1,n):
if xorArr[x] in d.keys():
d[xorArr[x]].append(x)
else:
d[xorArr[x]] = [x]
Step 4: Make a function that will pair up(i,j) for every element in d[xorArr[x]] and add it to l:
from itertools import combinations
def pair_up(arr):
return list(combinations(arr,2))
for x in d.values():
if len(x)==1: #you don't have to worry about elements that occur only once
continue
else: # if same element is present at i and j (i<j) then
l+=pair_up(x) # all pairs of (i,j) are valid (xor(arr[i:j]) = 0)
P.S : You don't have to worry about sorting as all the value in d will obviously be sorted. Hope this Helps. Do upvote. Cheers!
Edit :
Complexity of code : O(n*((frequency of element with maximum frequency in xorArr) chooses 2)) or O(n*(max_freq C 2)).
来源:https://stackoverflow.com/questions/57365476/how-to-find-all-the-subarrays-with-xor-0