LeetCode 1898. Maximum Number of Removable Characters- 二分查找(Binary Search)系列题21

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 removablep 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.

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 of s.
  • s and p 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值