Topics
This problem asks us to find the maximum number of characters Nastya can remove from string such that the remaining string can still be reduced to string . Nastya removes characters according to a given permutation.
Idea
The key observation is that if Nastya can remove characters and still obtain , she can also remove any number of characters less than and still obtain . This monotonicity allows us to use binary search boolean array framework on the number of chars Nastya removes, say .
Now, we need to check if the string is a subsequence of the string after removals. This can be done through standard string subsequence check algorithm:
- Iterate through both strings, and , with pointers, say and respectively
- If is marked as removed (
removed[a]
is true), we simply skip it and increment - If it’s not removed, we compare with . If they match, we increment both and
- If they don’t match, we only increment
- If we have reached the end of i.e., , it means is a subsequence
Note
We initialize the search range from (it’s a possibility that we shouldn’t remove any character) to .
For each mid value in binary search, we call the check
function. If check(mid)
is true, it means Nastya can remove at least mid
characters, so we try for a larger number of removals by setting the lower bound of binary search to . Otherwise, if check(mid)
is false, it means Nastya cannot remove mid
characters and still get , so we reduce the upper bound of binary search to . The largest value of mid
for which check(mid)
is true is our answer.
Time Complexity:
The check
function involves:
- Initializing the
removed
array usingfill
: - Subsequence check: (worst case we iterate over entire )
Thus, each call to check
takes time. The binary search performs calls to check
. Therefore, the overall time complexity is
Space Complexity:
The space complexity is determined by the storage used:
- Strings and :
perm
vector:removed
vector:
Code
bool check(string &t, string &p, int r, vector<int> &perm,
vector<int> &removed) {
fill(all(removed), 0);
for (int i = 1; i <= r; ++i) {
removed[perm[i - 1] - 1] = 1;
}
int a = 0, b = 0;
int amax = t.size();
int bmax = p.size();
// modified string subsequence check
while (a < amax && b < bmax) {
if (removed[a] == 1) {
a++;
continue;
}
if (t[a] == p[b]) {
a++;
b++;
} else {
a++;
}
}
return b == bmax;
}
void solve() {
string t, p;
cin >> t >> p;
int n = t.size();
vector<int> perm(n);
vector<int> removed(n, 0);
for (int i = 0; i < n; ++i)
cin >> perm[i];
int lo = 0;
int hi = n;
int ans = 0;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (check(t, p, mid, perm, removed)) {
ans = mid;
lo = mid + 1;
} else
hi = mid - 1;
}
cout << ans << endl;
}