| tags |
|
|
|---|---|---|
| title | MEX (minimal excluded) of a sequence |
Given an array
Notice, that the MEX of an array of size
The easiest approach is to create a set of all elements in the array
The following algorithm runs in
int mex(vector<int> const& A) {
set<int> b(A.begin(), A.end());
int result = 0;
while (b.count(result))
++result;
return result;
}If an algorithm requires a
int mex(vector<int> const& A) {
static bool used[MAX_N+1] = { 0 };
// mark the given numbers
for (int x : A) {
if (x <= MAX_N)
used[x] = true;
}
// find the mex
int result = 0;
while (used[result])
++result;
// clear the array again
for (int x : A) {
if (x <= MAX_N)
used[x] = false;
}
return result;
}This approach is fast, but only works well if you have to compute the MEX once. If you need to compute the MEX over and over, e.g. because your array keeps changing, then it is not effective. For that, we need something better.
In the problem you need to change individual numbers in the array, and compute the new MEX of the array after each such update.
There is a need for a better data structure that handles such queries efficiently.
One approach would be take the frequency of each number from
It's also possible to use the standard library data structures map and set (based on an approach explained here).
With a map we will remember the frequency of each number, and with the set we represent the numbers that are currently missing from the array.
Since a set is ordered, *set.begin() will be the MEX.
In total we need
class Mex {
private:
map<int, int> frequency;
set<int> missing_numbers;
vector<int> A;
public:
Mex(vector<int> const& A) : A(A) {
for (int i = 0; i <= A.size(); i++)
missing_numbers.insert(i);
for (int x : A) {
++frequency[x];
missing_numbers.erase(x);
}
}
int mex() {
return *missing_numbers.begin();
}
void update(int idx, int new_value) {
if (--frequency[A[idx]] == 0)
missing_numbers.insert(A[idx]);
A[idx] = new_value;
++frequency[new_value];
missing_numbers.erase(new_value);
}
};