可移除字符的最大数目
难度:
标签:
题目描述
代码结果
运行时间: 649 ms, 内存: 26.3 MB
/*
* 思路:
* 1. 使用二分查找法来确定最大的k值。
* 2. 对于每一个k值,移除前k个removable中的字符,并检查p是否仍然是s的子序列。
* 3. 为了高效地检查p是否是s的子序列,使用一个辅助函数isSubsequence。
* 4. 使用Java Stream API来实现这一逻辑。
*/
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
public class Solution {
public int maximumRemovals(String s, String p, int[] removable) {
int left = 0, right = removable.length;
while (left < right) {
int mid = (left + right + 1) / 2;
if (isSubsequence(s, p, removable, mid)) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
private boolean isSubsequence(String s, String p, int[] removable, int k) {
Set<Integer> removedIndices = Arrays.stream(removable, 0, k).boxed().collect(Collectors.toSet());
String filteredS = s.chars()
.filter(i -> !removedIndices.contains(i))
.mapToObj(c -> String.valueOf((char)c))
.collect(Collectors.joining());
return isSubsequence(filteredS, p);
}
private boolean isSubsequence(String s, String p) {
int j = 0;
for (int i = 0; i < s.length() && j < p.length(); i++) {
if (s.charAt(i) == p.charAt(j)) {
j++;
}
}
return j == p.length();
}
}
解释
方法:
本题解采用二分查找来确定最大的 k 值。我们定义两个边界:left 和 right,初始化 left 为 0,right 为 removable.length + 1。我们在这个范围内进行二分搜索,检查每一个中间值 mid。对于每个 mid,我们尝试从字符串 s 中移除前 mid 个在 removable 数组中指定的字符。移除后,我们检查 p 是否仍然是新字符串的子序列。如果是,我们将搜索范围的左边界移动到 mid + 1;如果不是,我们将右边界设置为 mid。继续这个过程,直到 left 和 right 相遇。最终,left - 1 将是满足条件的最大 k 值。
时间复杂度:
O(removable.length * s.length * log(removable.length))
空间复杂度:
O(s.length)
代码细节讲解
🦆
在二分查找中,为什么初始设置`right`为`removable.length + 1`而不是`removable.length`?这样的设置对算法有何影响?
▷🦆
在二分查找过程中,每次修改字符串后都要检查`p`是否是新字符串`s2`的子序列。这个检查过程是否可以优化以减少不必要的计算?
▷🦆
题解采用了直接修改字符串并重新检查子序列的方法,这种方法在实际应用中是否最优?是否存在其他可能的策略来提高算法的效率?
▷🦆
在算法最后返回`left - 1`作为结果,这种处理方式是否可能在某些边界情况下返回错误的结果?请解释这种情况可能发生的原因。
▷