3. Substring XOR queries
class Solution {
public:
struct Index{
int left;
int right;
};
// Note: val ^ first = second is the same as finding val = first ^ second;
vector<vector<int>> substringXorQueries(string s, vector<vector<int>>& queries) {
std::vector<int> zero_indexes;
std::vector<int> one_indexes;
int size = s.size();
for(int index = 0; index < size; index++) {
if (s[index] == '1') {
one_indexes.push_back(index);
continue;
}
zero_indexes.push_back(index);
}
// Map of "value" obtained by evaluating substrings of (s) between (i and j).
std::unordered_map<long long, Index> _map;
if (!zero_indexes.empty()) {
_map[0] = Index{
.left = zero_indexes[0],
.right = zero_indexes[0]
};
}
// Instead of looping over all the indexes of s, we can loop over the the indexes where the value is 1
for(auto i : one_indexes) {
int running_val = 0;
for(int j = i; j < std::min(size, i + 64); j++) {
long long digit = 0;
if(s[j] == '1') {
digit = 1;
}
running_val <<= 1;
running_val |= digit;
if (!_map.contains(running_val)) {
_map[running_val] = Index{
.left = i,
.right = j
};
continue;
}
int existing_len = _map[running_val].right - _map[running_val].left + 1;
int current_len = j - i + 1;
if (current_len < existing_len) {
_map[running_val] = Index{
.left = i,
.right = j
};
continue;
}
}
}
std::vector<std::vector<int>> answers;
for(auto query : queries) {
long long val = query[0] ^ query[1];
if (!_map.contains(val)) {
answers.push_back({-1, -1});
continue;
}
Index indexes = _map[val];
answers.push_back({
indexes.left,
indexes.right
}
);
continue;
}
return answers;
}
};