Maximum Number of Removable Characters
update Jun 13, 2021

Basic Idea:
这道题目数据量比较大,如果是N^2的话肯定TLE,但是如果可以做到NlogN就可以。由此可以想到二分法。如果直接做的话,从左到右尝试每个长度的removable中的index,然后验证移除这些index之后P是否仍是S的subsequence,每次验证需要O(N), 总时间O(N^2)。利用二分法,我们可以对验证次数进行优化,最终做到O(NlogN)。
需要注意的是,每次验证时将 removable[0 ~ i]
的index在S中移除的操作可能会比较耗时,如果采用 HashSet 标记每个index,则这一步就需要 O(i) 。在推荐答案中我看到一个优化的做法,利用一个数组orders存储S中index在removable数组中的index,例如对于s长度为4,removable=[3,1,0]
,则orders=[2,1,4,0]
,即index 0 对应removable中index=2的位置,index 2因为不在removable中,让它等于 4 即大于s中的最大index 3 (也表示index2不会被删除). 这样在之后验证的时候,如果我们要验证 removable 中的前 k 个 index 被删掉之后是否仍满足条件,我们只需要保证在比较 s 和 p 的时候跳过 s 中 index 在 removable 中 order 小于等于 k 的就可以了。
Java Code after Optimization
class Solution {
public int maximumRemovals(String s, String p, int[] removable) {
int[] removeOrder = new int[s.length()];
Arrays.fill(removeOrder, s.length());
for (int i = 0; i < removable.length; ++i) {
removeOrder[removable[i]] = i; // 记录每个index在removable数组中的index
}
int left = 0, right = removable.length;
while (left + 1 < right) {
int mid = (left + right) / 2;
if (check(s, p, removeOrder, mid)) {
left = mid;
} else {
right = mid;
}
}
if (check(s, p, removeOrder, right)) {
return right;
} else {
return left;
}
}
// 检查 removable 数组中前 len 个index 能否被remove
private boolean check(String s, String p, int[] removeOrder, int len) {
int j = 0;
for (int i = 0; i < s.length() && j < p.length(); ++i) {
if (removeOrder[i] < len) {
// 表示当前s中的index i位于removable中前len个位置,需要删掉,所以不和p比较直接跳过
continue;
}
if (s.charAt(i) == p.charAt(j)) {
j++;
}
}
if (j == p.length()) {
return true;
}
return false;
}
}
Last updated