From 0f9b96d48b1fa486e25bc9e957bef57543adf5a6 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Wed, 20 Nov 2024 19:38:40 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1898 No.1898.Maximum Number of Removable Characters --- .../README.md | 396 ++++++++---------- .../README_EN.md | 351 ++++++++-------- .../Solution.cpp | 48 ++- .../Solution.go | 30 +- .../Solution.java | 39 +- .../Solution.js | 53 ++- .../Solution.kt | 60 +-- .../Solution.py | 25 +- .../Solution.rs | 32 +- .../Solution.ts | 48 ++- 10 files changed, 539 insertions(+), 543 deletions(-) diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/README.md b/solution/1800-1899/1898.Maximum Number of Removable Characters/README.md index 9373f47ff1290..fe46665caf096 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/README.md +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/README.md @@ -78,60 +78,15 @@ tags: -### 方法一:二分查找 + 判断子序列 +### 方法一:二分查找 -二分枚举整数 k,找到满足要求的最大 k 即可。 +我们注意到,如果移除 $\textit{removable}$ 前 $k$ 个下标对应的字符后,满足 $p$ 仍然是 $s$ 的一个子序列,那么移除 $k \lt k' \leq \textit{removable.length}$ 个下标对应的字符后,依然满足条件,这存在着单调性。因此,我们可以使用二分查找,找到最大的 $k$。 -以下是二分查找的两个通用模板: +我们定义二分查找的左边界 $l = 0$,右边界 $r = \textit{removable.length}$,然后进行二分查找。在每次查找中,我们取中间值 $mid = \left\lfloor \frac{l + r + 1}{2} \right\rfloor$,然后检查移除 $\textit{removable}$ 的前 $mid$ 个下标对应的字符后,是否满足 $p$ 仍然是 $s$ 的一个子序列。如果满足,我们更新左边界 $l = mid$,否则更新右边界 $r = mid - 1$。 -模板 1: +二分查找结束后,返回左边界 $l$ 即可。 -```java -boolean check(int x) { -} - -int search(int left, int right) { - while (left < right) { - int mid = (left + right) >> 1; - if (check(mid)) { - right = mid; - } else { - left = mid + 1; - } - } - return left; -} -``` - -模板 2: - -```java -boolean check(int x) { -} - -int search(int left, int right) { - while (left < right) { - int mid = (left + right + 1) >> 1; - if (check(mid)) { - left = mid; - } else { - right = mid - 1; - } - } - return left; -} -``` - -做二分题目时,可以按照以下套路: - -1. 写出循环条件 $left < right$; -1. 循环体内,不妨先写 $mid = \lfloor \frac{left + right}{2} \rfloor$; -1. 根据具体题目,实现 $check()$ 函数(有时很简单的逻辑,可以不定义 $check$),想一下究竟要用 $right = mid$(模板 $1$) 还是 $left = mid$(模板 $2$); -     - 如果 $right = mid$,那么写出 else 语句 $left = mid + 1$,并且不需要更改 mid 的计算,即保持 $mid = \lfloor \frac{left + right}{2} \rfloor$; -     - 如果 $left = mid$,那么写出 else 语句 $right = mid - 1$,并且在 $mid$ 计算时补充 +1,即 $mid = \lfloor \frac{left + right + 1}{2} \rfloor$; -1. 循环结束时,$left$ 与 $right$ 相等。 - -注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 $left$ 或者 $right$ 是否满足题意即可。 +时间复杂度 $O(k \times \log k)$,空间复杂度 $O(n)$。其中 $n$ 是字符串 $s$ 的长度,而 $k$ 是 $\textit{removable}$ 的长度。 @@ -140,56 +95,64 @@ int search(int left, int right) { ```python class Solution: def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int: - def check(k): + def check(k: int) -> bool: + rem = [False] * len(s) + for i in removable[:k]: + rem[i] = True i = j = 0 - ids = set(removable[:k]) - while i < m and j < n: - if i not in ids and s[i] == p[j]: + while i < len(s) and j < len(p): + if not rem[i] and p[j] == s[i]: j += 1 i += 1 - return j == n + return j == len(p) - m, n = len(s), len(p) - left, right = 0, len(removable) - while left < right: - mid = (left + right + 1) >> 1 + l, r = 0, len(removable) + while l < r: + mid = (l + r + 1) >> 1 if check(mid): - left = mid + l = mid else: - right = mid - 1 - return left + r = mid - 1 + return l ``` #### Java ```java class Solution { + private char[] s; + private char[] p; + private int[] removable; + public int maximumRemovals(String s, String p, int[] removable) { - int left = 0, right = removable.length; - while (left < right) { - int mid = (left + right + 1) >> 1; - if (check(s, p, removable, mid)) { - left = mid; + int l = 0, r = removable.length; + this.s = s.toCharArray(); + this.p = p.toCharArray(); + this.removable = removable; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; } else { - right = mid - 1; + r = mid - 1; } } - return left; + return l; } - private boolean check(String s, String p, int[] removable, int mid) { - int m = s.length(), n = p.length(), i = 0, j = 0; - Set ids = new HashSet<>(); - for (int k = 0; k < mid; ++k) { - ids.add(removable[k]); + private boolean check(int k) { + boolean[] rem = new boolean[s.length]; + for (int i = 0; i < k; ++i) { + rem[removable[i]] = true; } - while (i < m && j < n) { - if (!ids.contains(i) && s.charAt(i) == p.charAt(j)) { + int i = 0, j = 0; + while (i < s.length && j < p.length) { + if (!rem[i] && p[j] == s[i]) { ++j; } ++i; } - return j == n; + return j == p.length; } } ``` @@ -200,31 +163,33 @@ class Solution { class Solution { public: int maximumRemovals(string s, string p, vector& removable) { - int left = 0, right = removable.size(); - while (left < right) { - int mid = left + right + 1 >> 1; - if (check(s, p, removable, mid)) { - left = mid; - } else { - right = mid - 1; + int m = s.size(), n = p.size(); + int l = 0, r = removable.size(); + bool rem[m]; + + auto check = [&](int k) { + memset(rem, false, sizeof(rem)); + for (int i = 0; i < k; i++) { + rem[removable[i]] = true; } - } - return left; - } - - bool check(string s, string p, vector& removable, int mid) { - int m = s.size(), n = p.size(), i = 0, j = 0; - unordered_set ids; - for (int k = 0; k < mid; ++k) { - ids.insert(removable[k]); - } - while (i < m && j < n) { - if (ids.count(i) == 0 && s[i] == p[j]) { - ++j; + int i = 0, j = 0; + while (i < m && j < n) { + if (!rem[i] && s[i] == p[j]) { + ++j; + } + ++i; + } + return j == n; + }; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; } - ++i; } - return j == n; + return l; } }; ``` @@ -233,31 +198,31 @@ public: ```go func maximumRemovals(s string, p string, removable []int) int { + m, n := len(s), len(p) + l, r := 0, len(removable) check := func(k int) bool { - ids := make(map[int]bool) - for _, r := range removable[:k] { - ids[r] = true + rem := make([]bool, m) + for i := 0; i < k; i++ { + rem[removable[i]] = true } - var i, j int - for i < len(s) && j < len(p) { - if !ids[i] && s[i] == p[j] { + i, j := 0, 0 + for i < m && j < n { + if !rem[i] && s[i] == p[j] { j++ } i++ } - return j == len(p) + return j == n } - - left, right := 0, len(removable) - for left < right { - mid := (left + right + 1) >> 1 + for l < r { + mid := (l + r + 1) >> 1 if check(mid) { - left = mid + l = mid } else { - right = mid - 1 + r = mid - 1 } } - return left + return l } ``` @@ -265,52 +230,61 @@ func maximumRemovals(s string, p string, removable []int) int { ```ts function maximumRemovals(s: string, p: string, removable: number[]): number { - let left = 0, - right = removable.length; - while (left < right) { - let mid = (left + right + 1) >> 1; - if (isSub(s, p, new Set(removable.slice(0, mid)))) { - left = mid; - } else { - right = mid - 1; + const [m, n] = [s.length, p.length]; + let [l, r] = [0, removable.length]; + const rem: boolean[] = Array(m); + + const check = (k: number): boolean => { + rem.fill(false); + for (let i = 0; i < k; i++) { + rem[removable[i]] = true; } - } - return left; -} -function isSub(str: string, sub: string, idxes: Set): boolean { - let m = str.length, - n = sub.length; - let i = 0, - j = 0; - while (i < m && j < n) { - if (!idxes.has(i) && str.charAt(i) == sub.charAt(j)) { - ++j; + let i = 0, + j = 0; + while (i < m && j < n) { + if (!rem[i] && s[i] === p[j]) { + j++; + } + i++; + } + return j === n; + }; + + while (l < r) { + const mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; } - ++i; } - return j == n; + + return l; } ``` #### Rust ```rust -use std::collections::HashSet; - impl Solution { pub fn maximum_removals(s: String, p: String, removable: Vec) -> i32 { let m = s.len(); let n = p.len(); - let s = s.as_bytes(); - let p = p.as_bytes(); - - let check = |k| { + let s: Vec = s.chars().collect(); + let p: Vec = p.chars().collect(); + let mut l = 0; + let mut r = removable.len(); + + let check = |k: usize| -> bool { + let mut rem = vec![false; m]; + for i in 0..k { + rem[removable[i] as usize] = true; + } let mut i = 0; let mut j = 0; - let ids: HashSet = removable[..k].iter().cloned().collect(); while i < m && j < n { - if !ids.contains(&(i as i32)) && s[i] == p[j] { + if !rem[i] && s[i] == p[j] { j += 1; } i += 1; @@ -318,21 +292,16 @@ impl Solution { j == n }; - let mut left = 0; - let mut right = removable.len(); - while left + 1 < right { - let mid = left + (right - left) / 2; + while l < r { + let mid = (l + r + 1) / 2; if check(mid) { - left = mid; + l = mid; } else { - right = mid; + r = mid - 1; } } - if check(right) { - return right as i32; - } - left as i32 + l as i32 } } ``` @@ -346,81 +315,78 @@ impl Solution { * @param {number[]} removable * @return {number} */ -function maximumRemovals(s, p, removable) { - const str_len = s.length; - const sub_len = p.length; - - /** - * @param {number} k - * @return {boolean} - */ - function isSub(k) { - const removed = new Set(removable.slice(0, k)); - - let sub_i = 0; - for (let str_i = 0; str_i < str_len; ++str_i) { - if (s.charAt(str_i) === p.charAt(sub_i) && !removed.has(str_i)) { - ++sub_i; - if (sub_i >= sub_len) { - break; - } - } +var maximumRemovals = function (s, p, removable) { + const [m, n] = [s.length, p.length]; + let [l, r] = [0, removable.length]; + const rem = Array(m); + + const check = k => { + rem.fill(false); + for (let i = 0; i < k; i++) { + rem[removable[i]] = true; } - return sub_i === sub_len; - } - let left = 0; - let right = removable.length; + let i = 0, + j = 0; + while (i < m && j < n) { + if (!rem[i] && s[i] === p[j]) { + j++; + } + i++; + } + return j === n; + }; - while (left < right) { - const middle = (left + right) >> 1; - if (isSub(middle + 1)) { - left = middle + 1; + while (l < r) { + const mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; } else { - right = middle; + r = mid - 1; } } - return left; -} + + return l; +}; ``` #### Kotlin ```kotlin class Solution { - fun maximumRemovals(s: String, p: String, removable: IntArray): Int { - val strLen = s.length - val subLen = p.length - - fun isSub(k: Int): Boolean { - val removed = removable.sliceArray(0 ..< k).toHashSet() - - var subIndex = 0 - for (strIndex in 0 ..< strLen) { - if (s[strIndex] == p[subIndex] && !removed.contains(strIndex)) { - ++subIndex - if (subIndex >= subLen) { - break - } - } - } - - return subIndex == subLen - } - - var left = 0 - var right = removable.size - - while (left < right) { - val middle = (left + right) / 2 - if (isSub(middle + 1)) { - left = middle + 1 - } else { - right = middle - } - } - return left - } + fun maximumRemovals(s: String, p: String, removable: IntArray): Int { + val m = s.length + val n = p.length + var l = 0 + var r = removable.size + + fun check(k: Int): Boolean { + val rem = BooleanArray(m) + for (i in 0 until k) { + rem[removable[i]] = true + } + var i = 0 + var j = 0 + while (i < m && j < n) { + if (!rem[i] && s[i] == p[j]) { + j++ + } + i++ + } + return j == n + } + + while (l < r) { + val mid = (l + r + 1) / 2 + if (check(mid)) { + l = mid + } else { + r = mid - 1 + } + } + + return l + } } ``` diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/README_EN.md b/solution/1800-1899/1898.Maximum Number of Removable Characters/README_EN.md index dc05c1020296d..00ff3526e3553 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/README_EN.md +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/README_EN.md @@ -76,7 +76,15 @@ Hence, the maximum k is 2. -### Solution 1 +### Solution 1: Binary Search + +We notice that if removing the characters at the first $k$ indices in $\textit{removable}$ still makes $p$ a subsequence of $s$, then removing the characters at $k \lt k' \leq \textit{removable.length}$ indices will also satisfy the condition. This monotonicity allows us to use binary search to find the maximum $k$. + +We define the left boundary of the binary search as $l = 0$ and the right boundary as $r = \textit{removable.length}$. Then we perform binary search. In each search, we take the middle value $mid = \left\lfloor \frac{l + r + 1}{2} \right\rfloor$ and check if removing the characters at the first $mid$ indices in $\textit{removable}$ still makes $p$ a subsequence of $s$. If it does, we update the left boundary $l = mid$; otherwise, we update the right boundary $r = mid - 1$. + +After the binary search ends, we return the left boundary $l$. + +The time complexity is $O(k \times \log k)$, and the space complexity is $O(n)$. Here, $n$ is the length of the string $s$, and $k$ is the length of $\textit{removable}$. @@ -85,56 +93,64 @@ Hence, the maximum k is 2. ```python class Solution: def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int: - def check(k): + def check(k: int) -> bool: + rem = [False] * len(s) + for i in removable[:k]: + rem[i] = True i = j = 0 - ids = set(removable[:k]) - while i < m and j < n: - if i not in ids and s[i] == p[j]: + while i < len(s) and j < len(p): + if not rem[i] and p[j] == s[i]: j += 1 i += 1 - return j == n + return j == len(p) - m, n = len(s), len(p) - left, right = 0, len(removable) - while left < right: - mid = (left + right + 1) >> 1 + l, r = 0, len(removable) + while l < r: + mid = (l + r + 1) >> 1 if check(mid): - left = mid + l = mid else: - right = mid - 1 - return left + r = mid - 1 + return l ``` #### Java ```java class Solution { + private char[] s; + private char[] p; + private int[] removable; + public int maximumRemovals(String s, String p, int[] removable) { - int left = 0, right = removable.length; - while (left < right) { - int mid = (left + right + 1) >> 1; - if (check(s, p, removable, mid)) { - left = mid; + int l = 0, r = removable.length; + this.s = s.toCharArray(); + this.p = p.toCharArray(); + this.removable = removable; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; } else { - right = mid - 1; + r = mid - 1; } } - return left; + return l; } - private boolean check(String s, String p, int[] removable, int mid) { - int m = s.length(), n = p.length(), i = 0, j = 0; - Set ids = new HashSet<>(); - for (int k = 0; k < mid; ++k) { - ids.add(removable[k]); + private boolean check(int k) { + boolean[] rem = new boolean[s.length]; + for (int i = 0; i < k; ++i) { + rem[removable[i]] = true; } - while (i < m && j < n) { - if (!ids.contains(i) && s.charAt(i) == p.charAt(j)) { + int i = 0, j = 0; + while (i < s.length && j < p.length) { + if (!rem[i] && p[j] == s[i]) { ++j; } ++i; } - return j == n; + return j == p.length; } } ``` @@ -145,31 +161,33 @@ class Solution { class Solution { public: int maximumRemovals(string s, string p, vector& removable) { - int left = 0, right = removable.size(); - while (left < right) { - int mid = left + right + 1 >> 1; - if (check(s, p, removable, mid)) { - left = mid; - } else { - right = mid - 1; + int m = s.size(), n = p.size(); + int l = 0, r = removable.size(); + bool rem[m]; + + auto check = [&](int k) { + memset(rem, false, sizeof(rem)); + for (int i = 0; i < k; i++) { + rem[removable[i]] = true; } - } - return left; - } - - bool check(string s, string p, vector& removable, int mid) { - int m = s.size(), n = p.size(), i = 0, j = 0; - unordered_set ids; - for (int k = 0; k < mid; ++k) { - ids.insert(removable[k]); - } - while (i < m && j < n) { - if (ids.count(i) == 0 && s[i] == p[j]) { - ++j; + int i = 0, j = 0; + while (i < m && j < n) { + if (!rem[i] && s[i] == p[j]) { + ++j; + } + ++i; + } + return j == n; + }; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; } - ++i; } - return j == n; + return l; } }; ``` @@ -178,31 +196,31 @@ public: ```go func maximumRemovals(s string, p string, removable []int) int { + m, n := len(s), len(p) + l, r := 0, len(removable) check := func(k int) bool { - ids := make(map[int]bool) - for _, r := range removable[:k] { - ids[r] = true + rem := make([]bool, m) + for i := 0; i < k; i++ { + rem[removable[i]] = true } - var i, j int - for i < len(s) && j < len(p) { - if !ids[i] && s[i] == p[j] { + i, j := 0, 0 + for i < m && j < n { + if !rem[i] && s[i] == p[j] { j++ } i++ } - return j == len(p) + return j == n } - - left, right := 0, len(removable) - for left < right { - mid := (left + right + 1) >> 1 + for l < r { + mid := (l + r + 1) >> 1 if check(mid) { - left = mid + l = mid } else { - right = mid - 1 + r = mid - 1 } } - return left + return l } ``` @@ -210,52 +228,61 @@ func maximumRemovals(s string, p string, removable []int) int { ```ts function maximumRemovals(s: string, p: string, removable: number[]): number { - let left = 0, - right = removable.length; - while (left < right) { - let mid = (left + right + 1) >> 1; - if (isSub(s, p, new Set(removable.slice(0, mid)))) { - left = mid; - } else { - right = mid - 1; + const [m, n] = [s.length, p.length]; + let [l, r] = [0, removable.length]; + const rem: boolean[] = Array(m); + + const check = (k: number): boolean => { + rem.fill(false); + for (let i = 0; i < k; i++) { + rem[removable[i]] = true; } - } - return left; -} -function isSub(str: string, sub: string, idxes: Set): boolean { - let m = str.length, - n = sub.length; - let i = 0, - j = 0; - while (i < m && j < n) { - if (!idxes.has(i) && str.charAt(i) == sub.charAt(j)) { - ++j; + let i = 0, + j = 0; + while (i < m && j < n) { + if (!rem[i] && s[i] === p[j]) { + j++; + } + i++; + } + return j === n; + }; + + while (l < r) { + const mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; } - ++i; } - return j == n; + + return l; } ``` #### Rust ```rust -use std::collections::HashSet; - impl Solution { pub fn maximum_removals(s: String, p: String, removable: Vec) -> i32 { let m = s.len(); let n = p.len(); - let s = s.as_bytes(); - let p = p.as_bytes(); - - let check = |k| { + let s: Vec = s.chars().collect(); + let p: Vec = p.chars().collect(); + let mut l = 0; + let mut r = removable.len(); + + let check = |k: usize| -> bool { + let mut rem = vec![false; m]; + for i in 0..k { + rem[removable[i] as usize] = true; + } let mut i = 0; let mut j = 0; - let ids: HashSet = removable[..k].iter().cloned().collect(); while i < m && j < n { - if !ids.contains(&(i as i32)) && s[i] == p[j] { + if !rem[i] && s[i] == p[j] { j += 1; } i += 1; @@ -263,21 +290,16 @@ impl Solution { j == n }; - let mut left = 0; - let mut right = removable.len(); - while left + 1 < right { - let mid = left + (right - left) / 2; + while l < r { + let mid = (l + r + 1) / 2; if check(mid) { - left = mid; + l = mid; } else { - right = mid; + r = mid - 1; } } - if check(right) { - return right as i32; - } - left as i32 + l as i32 } } ``` @@ -291,81 +313,78 @@ impl Solution { * @param {number[]} removable * @return {number} */ -function maximumRemovals(s, p, removable) { - const str_len = s.length; - const sub_len = p.length; - - /** - * @param {number} k - * @return {boolean} - */ - function isSub(k) { - const removed = new Set(removable.slice(0, k)); - - let sub_i = 0; - for (let str_i = 0; str_i < str_len; ++str_i) { - if (s.charAt(str_i) === p.charAt(sub_i) && !removed.has(str_i)) { - ++sub_i; - if (sub_i >= sub_len) { - break; - } - } +var maximumRemovals = function (s, p, removable) { + const [m, n] = [s.length, p.length]; + let [l, r] = [0, removable.length]; + const rem = Array(m); + + const check = k => { + rem.fill(false); + for (let i = 0; i < k; i++) { + rem[removable[i]] = true; } - return sub_i === sub_len; - } - let left = 0; - let right = removable.length; + let i = 0, + j = 0; + while (i < m && j < n) { + if (!rem[i] && s[i] === p[j]) { + j++; + } + i++; + } + return j === n; + }; - while (left < right) { - const middle = (left + right) >> 1; - if (isSub(middle + 1)) { - left = middle + 1; + while (l < r) { + const mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; } else { - right = middle; + r = mid - 1; } } - return left; -} + + return l; +}; ``` #### Kotlin ```kotlin class Solution { - fun maximumRemovals(s: String, p: String, removable: IntArray): Int { - val strLen = s.length - val subLen = p.length - - fun isSub(k: Int): Boolean { - val removed = removable.sliceArray(0 ..< k).toHashSet() - - var subIndex = 0 - for (strIndex in 0 ..< strLen) { - if (s[strIndex] == p[subIndex] && !removed.contains(strIndex)) { - ++subIndex - if (subIndex >= subLen) { - break - } - } - } - - return subIndex == subLen - } - - var left = 0 - var right = removable.size - - while (left < right) { - val middle = (left + right) / 2 - if (isSub(middle + 1)) { - left = middle + 1 - } else { - right = middle - } - } - return left - } + fun maximumRemovals(s: String, p: String, removable: IntArray): Int { + val m = s.length + val n = p.length + var l = 0 + var r = removable.size + + fun check(k: Int): Boolean { + val rem = BooleanArray(m) + for (i in 0 until k) { + rem[removable[i]] = true + } + var i = 0 + var j = 0 + while (i < m && j < n) { + if (!rem[i] && s[i] == p[j]) { + j++ + } + i++ + } + return j == n + } + + while (l < r) { + val mid = (l + r + 1) / 2 + if (check(mid)) { + l = mid + } else { + r = mid - 1 + } + } + + return l + } } ``` diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.cpp b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.cpp index 8b3c2a8a94ef6..9f5b6f584ee81 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.cpp +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.cpp @@ -1,30 +1,32 @@ class Solution { public: int maximumRemovals(string s, string p, vector& removable) { - int left = 0, right = removable.size(); - while (left < right) { - int mid = left + right + 1 >> 1; - if (check(s, p, removable, mid)) { - left = mid; - } else { - right = mid - 1; - } - } - return left; - } + int m = s.size(), n = p.size(); + int l = 0, r = removable.size(); + bool rem[m]; - bool check(string s, string p, vector& removable, int mid) { - int m = s.size(), n = p.size(), i = 0, j = 0; - unordered_set ids; - for (int k = 0; k < mid; ++k) { - ids.insert(removable[k]); - } - while (i < m && j < n) { - if (ids.count(i) == 0 && s[i] == p[j]) { - ++j; + auto check = [&](int k) { + memset(rem, false, sizeof(rem)); + for (int i = 0; i < k; i++) { + rem[removable[i]] = true; + } + int i = 0, j = 0; + while (i < m && j < n) { + if (!rem[i] && s[i] == p[j]) { + ++j; + } + ++i; + } + return j == n; + }; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; } - ++i; } - return j == n; + return l; } -}; \ No newline at end of file +}; diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.go b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.go index 5dc857b795913..30f1f2b81df7a 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.go +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.go @@ -1,27 +1,27 @@ func maximumRemovals(s string, p string, removable []int) int { + m, n := len(s), len(p) + l, r := 0, len(removable) check := func(k int) bool { - ids := make(map[int]bool) - for _, r := range removable[:k] { - ids[r] = true + rem := make([]bool, m) + for i := 0; i < k; i++ { + rem[removable[i]] = true } - var i, j int - for i < len(s) && j < len(p) { - if !ids[i] && s[i] == p[j] { + i, j := 0, 0 + for i < m && j < n { + if !rem[i] && s[i] == p[j] { j++ } i++ } - return j == len(p) + return j == n } - - left, right := 0, len(removable) - for left < right { - mid := (left + right + 1) >> 1 + for l < r { + mid := (l + r + 1) >> 1 if check(mid) { - left = mid + l = mid } else { - right = mid - 1 + r = mid - 1 } } - return left -} \ No newline at end of file + return l +} diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.java b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.java index 4e970a3a0318d..a31fed19ff523 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.java +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.java @@ -1,29 +1,36 @@ class Solution { + private char[] s; + private char[] p; + private int[] removable; + public int maximumRemovals(String s, String p, int[] removable) { - int left = 0, right = removable.length; - while (left < right) { - int mid = (left + right + 1) >> 1; - if (check(s, p, removable, mid)) { - left = mid; + int l = 0, r = removable.length; + this.s = s.toCharArray(); + this.p = p.toCharArray(); + this.removable = removable; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; } else { - right = mid - 1; + r = mid - 1; } } - return left; + return l; } - private boolean check(String s, String p, int[] removable, int mid) { - int m = s.length(), n = p.length(), i = 0, j = 0; - Set ids = new HashSet<>(); - for (int k = 0; k < mid; ++k) { - ids.add(removable[k]); + private boolean check(int k) { + boolean[] rem = new boolean[s.length]; + for (int i = 0; i < k; ++i) { + rem[removable[i]] = true; } - while (i < m && j < n) { - if (!ids.contains(i) && s.charAt(i) == p.charAt(j)) { + int i = 0, j = 0; + while (i < s.length && j < p.length) { + if (!rem[i] && p[j] == s[i]) { ++j; } ++i; } - return j == n; + return j == p.length; } -} \ No newline at end of file +} diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.js b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.js index 7201892aa9e94..221f8ebd95536 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.js +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.js @@ -4,39 +4,36 @@ * @param {number[]} removable * @return {number} */ -function maximumRemovals(s, p, removable) { - const str_len = s.length; - const sub_len = p.length; +var maximumRemovals = function (s, p, removable) { + const [m, n] = [s.length, p.length]; + let [l, r] = [0, removable.length]; + const rem = Array(m); - /** - * @param {number} k - * @return {boolean} - */ - function isSub(k) { - const removed = new Set(removable.slice(0, k)); + const check = k => { + rem.fill(false); + for (let i = 0; i < k; i++) { + rem[removable[i]] = true; + } - let sub_i = 0; - for (let str_i = 0; str_i < str_len; ++str_i) { - if (s.charAt(str_i) === p.charAt(sub_i) && !removed.has(str_i)) { - ++sub_i; - if (sub_i >= sub_len) { - break; - } + let i = 0, + j = 0; + while (i < m && j < n) { + if (!rem[i] && s[i] === p[j]) { + j++; } + i++; } - return sub_i === sub_len; - } + return j === n; + }; - let left = 0; - let right = removable.length; - - while (left < right) { - const middle = (left + right) >> 1; - if (isSub(middle + 1)) { - left = middle + 1; + while (l < r) { + const mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; } else { - right = middle; + r = mid - 1; } } - return left; -} + + return l; +}; diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.kt b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.kt index 296600b5050b4..e7ae15cab5743 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.kt +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.kt @@ -1,35 +1,35 @@ class Solution { - fun maximumRemovals(s: String, p: String, removable: IntArray): Int { - val strLen = s.length - val subLen = p.length + fun maximumRemovals(s: String, p: String, removable: IntArray): Int { + val m = s.length + val n = p.length + var l = 0 + var r = removable.size - fun isSub(k: Int): Boolean { - val removed = removable.sliceArray(0 ..< k).toHashSet() + fun check(k: Int): Boolean { + val rem = BooleanArray(m) + for (i in 0 until k) { + rem[removable[i]] = true + } + var i = 0 + var j = 0 + while (i < m && j < n) { + if (!rem[i] && s[i] == p[j]) { + j++ + } + i++ + } + return j == n + } - var subIndex = 0 - for (strIndex in 0 ..< strLen) { - if (s[strIndex] == p[subIndex] && !removed.contains(strIndex)) { - ++subIndex - if (subIndex >= subLen) { - break - } - } - } + while (l < r) { + val mid = (l + r + 1) / 2 + if (check(mid)) { + l = mid + } else { + r = mid - 1 + } + } - return subIndex == subLen - } - - var left = 0 - var right = removable.size - - while (left < right) { - val middle = (left + right) / 2 - if (isSub(middle + 1)) { - left = middle + 1 - } else { - right = middle - } - } - return left - } + return l + } } diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.py b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.py index f454369f58e30..76388c76deb92 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.py +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.py @@ -1,20 +1,21 @@ class Solution: def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int: - def check(k): + def check(k: int) -> bool: + rem = [False] * len(s) + for i in removable[:k]: + rem[i] = True i = j = 0 - ids = set(removable[:k]) - while i < m and j < n: - if i not in ids and s[i] == p[j]: + while i < len(s) and j < len(p): + if not rem[i] and p[j] == s[i]: j += 1 i += 1 - return j == n + return j == len(p) - m, n = len(s), len(p) - left, right = 0, len(removable) - while left < right: - mid = (left + right + 1) >> 1 + l, r = 0, len(removable) + while l < r: + mid = (l + r + 1) >> 1 if check(mid): - left = mid + l = mid else: - right = mid - 1 - return left + r = mid - 1 + return l diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.rs b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.rs index 4e389493b78b2..d4076ee841a16 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.rs +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.rs @@ -1,18 +1,21 @@ -use std::collections::HashSet; - impl Solution { pub fn maximum_removals(s: String, p: String, removable: Vec) -> i32 { let m = s.len(); let n = p.len(); - let s = s.as_bytes(); - let p = p.as_bytes(); + let s: Vec = s.chars().collect(); + let p: Vec = p.chars().collect(); + let mut l = 0; + let mut r = removable.len(); - let check = |k| { + let check = |k: usize| -> bool { + let mut rem = vec![false; m]; + for i in 0..k { + rem[removable[i] as usize] = true; + } let mut i = 0; let mut j = 0; - let ids: HashSet = removable[..k].iter().cloned().collect(); while i < m && j < n { - if !ids.contains(&(i as i32)) && s[i] == p[j] { + if !rem[i] && s[i] == p[j] { j += 1; } i += 1; @@ -20,20 +23,15 @@ impl Solution { j == n }; - let mut left = 0; - let mut right = removable.len(); - while left + 1 < right { - let mid = left + (right - left) / 2; + while l < r { + let mid = (l + r + 1) / 2; if check(mid) { - left = mid; + l = mid; } else { - right = mid; + r = mid - 1; } } - if check(right) { - return right as i32; - } - left as i32 + l as i32 } } diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.ts b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.ts index a5663d1e97928..d53d4b03717ff 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.ts +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/Solution.ts @@ -1,27 +1,33 @@ function maximumRemovals(s: string, p: string, removable: number[]): number { - let left = 0, - right = removable.length; - while (left < right) { - let mid = (left + right + 1) >> 1; - if (isSub(s, p, new Set(removable.slice(0, mid)))) { - left = mid; - } else { - right = mid - 1; + const [m, n] = [s.length, p.length]; + let [l, r] = [0, removable.length]; + const rem: boolean[] = Array(m); + + const check = (k: number): boolean => { + rem.fill(false); + for (let i = 0; i < k; i++) { + rem[removable[i]] = true; } - } - return left; -} -function isSub(str: string, sub: string, idxes: Set): boolean { - let m = str.length, - n = sub.length; - let i = 0, - j = 0; - while (i < m && j < n) { - if (!idxes.has(i) && str.charAt(i) == sub.charAt(j)) { - ++j; + let i = 0, + j = 0; + while (i < m && j < n) { + if (!rem[i] && s[i] === p[j]) { + j++; + } + i++; + } + return j === n; + }; + + while (l < r) { + const mid = (l + r + 1) >> 1; + if (check(mid)) { + l = mid; + } else { + r = mid - 1; } - ++i; } - return j == n; + + return l; }