You are given two strings s
and p
where p
is a subsequence of s
. You are also given a distinct 0-indexed integer array removable
containing a subset of indices of s
(s
is also 0-indexed).
You want to choose an integer k
(0 <= k <= removable.length
) such that, after removing k
characters from s
using the first k
indices in removable
, p
is still a subsequence of s
. More formally, you will mark the character at s[removable[i]]
for each 0 <= i < k
, then remove all marked characters and check if p
is still a subsequence.
Return the maximum k
you can choose such that p
is still a subsequence of s
after the removals.
A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.
Example 1:
Input: s = "abcacb", p = "ab", removable = [3,1,0] Output: 2 Explanation: After removing the characters at indices 3 and 1, "abcacb" becomes "accb". "ab" is a subsequence of "accb". If we remove the characters at indices 3, 1, and 0, "abcacb" becomes "ccb", and "ab" is no longer a subsequence. Hence, the maximum k is 2.
Example 2:
Input: s = "abcbddddd", p = "abcd", removable = [3,2,1,4,5,6] Output: 1 Explanation: After removing the character at index 3, "abcbddddd" becomes "abcddddd". "abcd" is a subsequence of "abcddddd".
Example 3:
Input: s = "abcab", p = "abc", removable = [0,1,2,3,4] Output: 0 Explanation: If you remove the first index in the array removable, "abc" is no longer a subsequence.
Constraints:
1 <= p.length <= s.length <= 105
0 <= removable.length < s.length
0 <= removable[i] < s.length
p
is a subsequence ofs
.s
andp
both consist of lowercase English letters.- The elements in
removable
are distinct.
这题跟前面刷过的一系列题比如LeetCode 875. Koko Eating Bananas 类似,也是先确定查找的边界,然后用二分查找法快速查找一个最合适的值。
题目大意是:有两个字符串s和p,字符串p是字符串s的一个子序列,现在给定一个数组removable表示字符串s中可以删除的字符,数组元素值对应的是字符串s里字符索引。现在对字符串s按数组removable里的顺序挨个删除k(0<=k<=len(removable))个字符后要保证字符串p仍然是s的子序列,让我们求出k的最大值。
根据题意可以马上知道二分查找的边界,就是在[0,len(removable)]的区间范围内找到最大的满足条件的k。取中点mid=(left+right)//2把区间分成左右两个区间,把按removable里的前mid个数值对应到s里的mid个字符删掉后得到一个新字符串,判断字符串p是否是新字符串的子序列,如果是则继续查找右半区间看看能不能删更多的字符;如果p不是新字符串的子序列,说明要少删些字符也就是继续在左半区间查找。
这题还需要注意的地方是,如果每次都要删除s里的字符形成一个新字符串就会浪费很多时间和空间,其实不需要每次都真正删除字符,只需要在比较s和p时判断一下s的当前字符是否会被删掉。那该如何判断呢?可以对removable做个预处理,用一个map来存储removable里的数值(s的索引)到removable的索引的映射关系,在判断s的当前字符时判断它的索引是否在映射里并且其映射的removable的索引是否小于k,如果是表示它会被删掉。
class Solution:
def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int:
#map s index to removable index
s2re = [len(s)] * len(s)
for i in range(len(removable)):
s2re[removable[i]] = i
l, r = 0, len(removable)
while l <= r:
mid = (l + r) // 2
i, j = 0, 0
while i < len(s) and j < len(p):
if (s2re[i] > mid - 1) and s[i] == p[j]:
j += 1
i += 1
if j == len(p):
l = mid + 1
else:
r = mid - 1
return l - 1