We want to find the maximum number of characters we can remove from s (in the order given by removable) while keeping p as a subsequence of s.
The simplest approach is to remove characters one at a time. After each removal, check if p is still a subsequence. Once p is no longer a subsequence, stop and return the count of successful removals.
marked of indices that have been removed.removable:marked.p is a subsequence of s (skipping marked indices).p is still a subsequence, increment the result counter.class Solution:
def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int:
n, m = len(s), len(p)
marked = set()
res = 0
for removeIdx in removable:
marked.add(removeIdx)
sIdx = pIdx = 0
while pIdx < m and sIdx < n:
if sIdx not in marked and s[sIdx] == p[pIdx]:
pIdx += 1
sIdx += 1
if pIdx != m:
break
res += 1
return resWhere and are the lengths of the given strings and respectively. is the size of the array .
If removing the first k characters still allows p to be a subsequence, then removing fewer than k characters will also work. Conversely, if removing k characters breaks the subsequence property, removing more will certainly break it too.
This monotonic property makes binary search applicable. We search for the largest k such that after removing removable[0..k], p remains a subsequence.
k (range: 0 to length of removable - 1).m:removable[0..m].p is a subsequence of s (skipping removed indices).k found.class Solution:
def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int:
def isSubseq(s, subseq, removed):
i1 = i2 = 0
while i1 < len(s) and i2 < len(subseq):
if i1 in removed or s[i1] != subseq[i2]:
i1 += 1
continue
i1 += 1
i2 += 1
return i2 == len(subseq)
res = 0
l, r = 0, len(removable) - 1
while l <= r:
m = (l + r) // 2
removed = set(removable[:m + 1])
if isSubseq(s, p, removed):
res = max(res, m + 1)
l = m + 1
else:
r = m - 1
return resWhere and are the lengths of the given strings and respectively. is the size of the array .
Instead of using a hash set to track removed indices (which adds overhead), we can directly modify the string by replacing removed characters with a placeholder character (like '#'). This avoids hash lookups during the subsequence check.
The binary search logic remains the same, but the subsequence check becomes simpler since we just compare characters, skipping any '#' naturally by checking for equality.
l = 0 and r = length of removable.mid:s as a character array.removable[0..mid] as '#'.p is a subsequence (characters equal to '#' will never match).l = mid + 1.r = mid.l as the maximum number of removals.class Solution:
def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int:
l, r = 0, len(removable)
n, m = len(s), len(p)
def isSubseq(tmpS):
i1 = i2 = 0
while i1 < n and i2 < m:
if tmpS[i1] == p[i2]:
i2 += 1
i1 += 1
return i2 == m
while l < r:
mid = l + (r - l) // 2
tmpS = list(s)
for i in range(mid + 1):
tmpS[removable[i]] = '#'
if isSubseq(tmpS):
l = mid + 1
else:
r = mid
return lWhere and are the lengths of the given strings and respectively. is the size of the array .