From ba719eb3130e99610d358adcb3da5bddb1b9b2e7 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Sat, 13 Apr 2024 16:37:23 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.2516 No.2516.Take K of Each Character From Left and Right --- .../README.md | 116 ++++++++-------- .../README_EN.md | 124 +++++++++++------- .../Solution.cpp | 20 ++- .../Solution.go | 16 +-- .../Solution.java | 12 +- .../Solution.py | 6 +- .../Solution.rs | 34 ++--- .../Solution.ts | 24 ++-- 8 files changed, 199 insertions(+), 153 deletions(-) diff --git a/solution/2500-2599/2516.Take K of Each Character From Left and Right/README.md b/solution/2500-2599/2516.Take K of Each Character From Left and Right/README.md index b5109394b89ba..4a084aa5b33cb 100644 --- a/solution/2500-2599/2516.Take K of Each Character From Left and Right/README.md +++ b/solution/2500-2599/2516.Take K of Each Character From Left and Right/README.md @@ -48,7 +48,7 @@ ### 方法一:滑动窗口 -我们先用哈希表或者一个长度为 $3$ 的数组 `cnt` 统计字符串 $s$ 中每个字符的个数,如果有字符的个数小于 $k$ 个,则无法取到,提前返回 $-1$。 +我们先用哈希表或者一个长度为 $3$ 的数组 $cnt$ 统计字符串 $s$ 中每个字符的个数,如果有字符的个数小于 $k$ 个,则无法取到,提前返回 $-1$。 题目要我们在字符串左侧以及右侧取走字符,最终取到的每种字符的个数都不少于 $k$ 个。我们不妨反着考虑问题,取走中间某个窗口大小的字符串,使得剩下的两侧字符串中,每种字符的个数都不少于 $k$ 个。 @@ -56,7 +56,7 @@ 最终的答案就是字符串 $s$ 的长度减去最大窗口的大小。 -时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为字符串 $s$ 的长度。 +时间复杂度 $O(n)$,其中 $n$ 为字符串 $s$ 的长度。空间复杂度 $O(1)$。 @@ -66,14 +66,14 @@ class Solution: cnt = Counter(s) if any(cnt[c] < k for c in "abc"): return -1 - ans = j = 0 + mx = j = 0 for i, c in enumerate(s): cnt[c] -= 1 while cnt[c] < k: cnt[s[j]] += 1 j += 1 - ans = max(ans, i - j + 1) - return len(s) - ans + mx = max(mx, i - j + 1) + return len(s) - mx ``` ```java @@ -84,19 +84,21 @@ class Solution { for (int i = 0; i < n; ++i) { ++cnt[s.charAt(i) - 'a']; } - if (cnt[0] < k || cnt[1] < k || cnt[2] < k) { - return -1; + for (int x : cnt) { + if (x < k) { + return -1; + } } - int ans = 0, j = 0; + int mx = 0, j = 0; for (int i = 0; i < n; ++i) { int c = s.charAt(i) - 'a'; --cnt[c]; while (cnt[c] < k) { ++cnt[s.charAt(j++) - 'a']; } - ans = Math.max(ans, i - j + 1); + mx = Math.max(mx, i - j + 1); } - return n - ans; + return n - mx; } } ``` @@ -105,20 +107,26 @@ class Solution { class Solution { public: int takeCharacters(string s, int k) { - int cnt[3] = {0}; - for (char& c : s) ++cnt[c - 'a']; - if (cnt[0] < k || cnt[1] < k || cnt[2] < k) return -1; - int ans = 0, j = 0; - int n = s.size(); + int cnt[3]{}; + int n = s.length(); + for (int i = 0; i < n; ++i) { + ++cnt[s[i] - 'a']; + } + for (int x : cnt) { + if (x < k) { + return -1; + } + } + int mx = 0, j = 0; for (int i = 0; i < n; ++i) { int c = s[i] - 'a'; --cnt[c]; while (cnt[c] < k) { ++cnt[s[j++] - 'a']; } - ans = max(ans, i - j + 1); + mx = max(mx, i - j + 1); } - return n - ans; + return n - mx; } }; ``` @@ -129,70 +137,74 @@ func takeCharacters(s string, k int) int { for _, c := range s { cnt[c-'a']++ } - if cnt[0] < k || cnt[1] < k || cnt[2] < k { - return -1 + for _, x := range cnt { + if x < k { + return -1 + } } - ans, j := 0, 0 + mx, j := 0, 0 for i, c := range s { c -= 'a' - cnt[c]-- - for cnt[c] < k { + for cnt[c]--; cnt[c] < k; j++ { cnt[s[j]-'a']++ - j++ } - ans = max(ans, i-j+1) + mx = max(mx, i-j+1) } - return len(s) - ans + return len(s) - mx } ``` ```ts function takeCharacters(s: string, k: number): number { - const getIndex = (c: string) => c.charCodeAt(0) - 'a'.charCodeAt(0); - const count = [0, 0, 0]; + const idx = (c: string) => c.charCodeAt(0) - 97; + const cnt: number[] = Array(3).fill(0); for (const c of s) { - count[getIndex(c)]++; + ++cnt[idx(c)]; } - if (count.some(v => v < k)) { + if (cnt.some(v => v < k)) { return -1; } const n = s.length; - let ans = 0; - for (let i = 0, j = 0; j < n; j++) { - count[getIndex(s[j])]--; - while (count[getIndex(s[j])] < k) { - count[getIndex(s[i])]++; - i++; + let [mx, j] = [0, 0]; + for (let i = 0; i < n; ++i) { + const c = idx(s[i]); + --cnt[c]; + while (cnt[c] < k) { + ++cnt[idx(s[j++])]; } - ans = Math.max(ans, j - i + 1); + mx = Math.max(mx, i - j + 1); } - return n - ans; + return n - mx; } ``` ```rust +use std::collections::HashMap; + impl Solution { pub fn take_characters(s: String, k: i32) -> i32 { - let s = s.as_bytes(); - let mut count = vec![0; 3]; - for c in s.iter() { - count[(c - b'a') as usize] += 1; + let mut cnt: HashMap = HashMap::new(); + for c in s.chars() { + *cnt.entry(c).or_insert(0) += 1; } - if count.iter().any(|v| *v < k) { + + if "abc".chars().any(|c| cnt.get(&c).unwrap_or(&0) < &k) { return -1; } - let n = s.len(); - let mut ans = 0; - let mut i = 0; - for j in 0..n { - count[(s[j] - b'a') as usize] -= 1; - while count[(s[j] - b'a') as usize] < k { - count[(s[i] - b'a') as usize] += 1; - i += 1; + + let mut mx = 0; + let mut j = 0; + let mut cs = s.chars().collect::>(); + for i in 0..cs.len() { + let c = cs[i]; + *cnt.get_mut(&c).unwrap() -= 1; + while cnt.get(&c).unwrap() < &k { + *cnt.get_mut(&cs[j]).unwrap() += 1; + j += 1; } - ans = ans.max(j - i + 1); + mx = mx.max(i - j + 1); } - (n - ans) as i32 + (cs.len() as i32) - (mx as i32) } } ``` diff --git a/solution/2500-2599/2516.Take K of Each Character From Left and Right/README_EN.md b/solution/2500-2599/2516.Take K of Each Character From Left and Right/README_EN.md index bbaee041e682f..02001e679c4ef 100644 --- a/solution/2500-2599/2516.Take K of Each Character From Left and Right/README_EN.md +++ b/solution/2500-2599/2516.Take K of Each Character From Left and Right/README_EN.md @@ -42,7 +42,17 @@ It can be proven that 8 is the minimum number of minutes needed. ## Solutions -### Solution 1 +### Solution 1: Sliding Window + +First, we use a hash table or an array of length $3$, denoted as $cnt$, to count the number of each character in string $s$. If any character appears less than $k$ times, it cannot be obtained, so we return $-1$ in advance. + +The problem asks us to remove characters from the left and right sides of the string, so that the number of each remaining character is not less than $k$. We can consider the problem in reverse: remove a substring of certain size in the middle, so that in the remaining string on both sides, the number of each character is not less than $k$. + +Therefore, we maintain a sliding window, with pointers $j$ and $i$ representing the left and right boundaries of the window, respectively. The string within the window is what we want to remove. Each time we move the right boundary $i$, we add the corresponding character $s[i]$ to the window (i.e., remove one character $s[i]$). If the count of $cnt[s[i]]$ is less than $k$, then we move the left boundary $j$ in a loop until the count of $cnt[s[i]]$ is not less than $k$. The size of the window at this time is $i - j + 1$, and we update the maximum window size. + +The final answer is the length of string $s$ minus the size of the maximum window. + +The time complexity is $O(n)$, where $n$ is the length of string $s$. The space complexity is $O(1)$. @@ -52,14 +62,14 @@ class Solution: cnt = Counter(s) if any(cnt[c] < k for c in "abc"): return -1 - ans = j = 0 + mx = j = 0 for i, c in enumerate(s): cnt[c] -= 1 while cnt[c] < k: cnt[s[j]] += 1 j += 1 - ans = max(ans, i - j + 1) - return len(s) - ans + mx = max(mx, i - j + 1) + return len(s) - mx ``` ```java @@ -70,19 +80,21 @@ class Solution { for (int i = 0; i < n; ++i) { ++cnt[s.charAt(i) - 'a']; } - if (cnt[0] < k || cnt[1] < k || cnt[2] < k) { - return -1; + for (int x : cnt) { + if (x < k) { + return -1; + } } - int ans = 0, j = 0; + int mx = 0, j = 0; for (int i = 0; i < n; ++i) { int c = s.charAt(i) - 'a'; --cnt[c]; while (cnt[c] < k) { ++cnt[s.charAt(j++) - 'a']; } - ans = Math.max(ans, i - j + 1); + mx = Math.max(mx, i - j + 1); } - return n - ans; + return n - mx; } } ``` @@ -91,20 +103,26 @@ class Solution { class Solution { public: int takeCharacters(string s, int k) { - int cnt[3] = {0}; - for (char& c : s) ++cnt[c - 'a']; - if (cnt[0] < k || cnt[1] < k || cnt[2] < k) return -1; - int ans = 0, j = 0; - int n = s.size(); + int cnt[3]{}; + int n = s.length(); + for (int i = 0; i < n; ++i) { + ++cnt[s[i] - 'a']; + } + for (int x : cnt) { + if (x < k) { + return -1; + } + } + int mx = 0, j = 0; for (int i = 0; i < n; ++i) { int c = s[i] - 'a'; --cnt[c]; while (cnt[c] < k) { ++cnt[s[j++] - 'a']; } - ans = max(ans, i - j + 1); + mx = max(mx, i - j + 1); } - return n - ans; + return n - mx; } }; ``` @@ -115,70 +133,74 @@ func takeCharacters(s string, k int) int { for _, c := range s { cnt[c-'a']++ } - if cnt[0] < k || cnt[1] < k || cnt[2] < k { - return -1 + for _, x := range cnt { + if x < k { + return -1 + } } - ans, j := 0, 0 + mx, j := 0, 0 for i, c := range s { c -= 'a' - cnt[c]-- - for cnt[c] < k { + for cnt[c]--; cnt[c] < k; j++ { cnt[s[j]-'a']++ - j++ } - ans = max(ans, i-j+1) + mx = max(mx, i-j+1) } - return len(s) - ans + return len(s) - mx } ``` ```ts function takeCharacters(s: string, k: number): number { - const getIndex = (c: string) => c.charCodeAt(0) - 'a'.charCodeAt(0); - const count = [0, 0, 0]; + const idx = (c: string) => c.charCodeAt(0) - 97; + const cnt: number[] = Array(3).fill(0); for (const c of s) { - count[getIndex(c)]++; + ++cnt[idx(c)]; } - if (count.some(v => v < k)) { + if (cnt.some(v => v < k)) { return -1; } const n = s.length; - let ans = 0; - for (let i = 0, j = 0; j < n; j++) { - count[getIndex(s[j])]--; - while (count[getIndex(s[j])] < k) { - count[getIndex(s[i])]++; - i++; + let [mx, j] = [0, 0]; + for (let i = 0; i < n; ++i) { + const c = idx(s[i]); + --cnt[c]; + while (cnt[c] < k) { + ++cnt[idx(s[j++])]; } - ans = Math.max(ans, j - i + 1); + mx = Math.max(mx, i - j + 1); } - return n - ans; + return n - mx; } ``` ```rust +use std::collections::HashMap; + impl Solution { pub fn take_characters(s: String, k: i32) -> i32 { - let s = s.as_bytes(); - let mut count = vec![0; 3]; - for c in s.iter() { - count[(c - b'a') as usize] += 1; + let mut cnt: HashMap = HashMap::new(); + for c in s.chars() { + *cnt.entry(c).or_insert(0) += 1; } - if count.iter().any(|v| *v < k) { + + if "abc".chars().any(|c| cnt.get(&c).unwrap_or(&0) < &k) { return -1; } - let n = s.len(); - let mut ans = 0; - let mut i = 0; - for j in 0..n { - count[(s[j] - b'a') as usize] -= 1; - while count[(s[j] - b'a') as usize] < k { - count[(s[i] - b'a') as usize] += 1; - i += 1; + + let mut mx = 0; + let mut j = 0; + let mut cs = s.chars().collect::>(); + for i in 0..cs.len() { + let c = cs[i]; + *cnt.get_mut(&c).unwrap() -= 1; + while cnt.get(&c).unwrap() < &k { + *cnt.get_mut(&cs[j]).unwrap() += 1; + j += 1; } - ans = ans.max(j - i + 1); + mx = mx.max(i - j + 1); } - (n - ans) as i32 + (cs.len() as i32) - (mx as i32) } } ``` diff --git a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.cpp b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.cpp index ed66d1adef988..562bda67c0f81 100644 --- a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.cpp +++ b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.cpp @@ -1,19 +1,25 @@ class Solution { public: int takeCharacters(string s, int k) { - int cnt[3] = {0}; - for (char& c : s) ++cnt[c - 'a']; - if (cnt[0] < k || cnt[1] < k || cnt[2] < k) return -1; - int ans = 0, j = 0; - int n = s.size(); + int cnt[3]{}; + int n = s.length(); + for (int i = 0; i < n; ++i) { + ++cnt[s[i] - 'a']; + } + for (int x : cnt) { + if (x < k) { + return -1; + } + } + int mx = 0, j = 0; for (int i = 0; i < n; ++i) { int c = s[i] - 'a'; --cnt[c]; while (cnt[c] < k) { ++cnt[s[j++] - 'a']; } - ans = max(ans, i - j + 1); + mx = max(mx, i - j + 1); } - return n - ans; + return n - mx; } }; \ No newline at end of file diff --git a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.go b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.go index f444f00eee1a3..384b65f5a44d1 100644 --- a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.go +++ b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.go @@ -3,18 +3,18 @@ func takeCharacters(s string, k int) int { for _, c := range s { cnt[c-'a']++ } - if cnt[0] < k || cnt[1] < k || cnt[2] < k { - return -1 + for _, x := range cnt { + if x < k { + return -1 + } } - ans, j := 0, 0 + mx, j := 0, 0 for i, c := range s { c -= 'a' - cnt[c]-- - for cnt[c] < k { + for cnt[c]--; cnt[c] < k; j++ { cnt[s[j]-'a']++ - j++ } - ans = max(ans, i-j+1) + mx = max(mx, i-j+1) } - return len(s) - ans + return len(s) - mx } \ No newline at end of file diff --git a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.java b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.java index 93045a6d74556..9960a521b13f6 100644 --- a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.java +++ b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.java @@ -5,18 +5,20 @@ public int takeCharacters(String s, int k) { for (int i = 0; i < n; ++i) { ++cnt[s.charAt(i) - 'a']; } - if (cnt[0] < k || cnt[1] < k || cnt[2] < k) { - return -1; + for (int x : cnt) { + if (x < k) { + return -1; + } } - int ans = 0, j = 0; + int mx = 0, j = 0; for (int i = 0; i < n; ++i) { int c = s.charAt(i) - 'a'; --cnt[c]; while (cnt[c] < k) { ++cnt[s.charAt(j++) - 'a']; } - ans = Math.max(ans, i - j + 1); + mx = Math.max(mx, i - j + 1); } - return n - ans; + return n - mx; } } \ No newline at end of file diff --git a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.py b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.py index 99bfb1bd96254..2fa4cce7d5682 100644 --- a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.py +++ b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.py @@ -3,11 +3,11 @@ def takeCharacters(self, s: str, k: int) -> int: cnt = Counter(s) if any(cnt[c] < k for c in "abc"): return -1 - ans = j = 0 + mx = j = 0 for i, c in enumerate(s): cnt[c] -= 1 while cnt[c] < k: cnt[s[j]] += 1 j += 1 - ans = max(ans, i - j + 1) - return len(s) - ans + mx = max(mx, i - j + 1) + return len(s) - mx diff --git a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.rs b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.rs index 331ae879da9ba..d6e38f5680195 100644 --- a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.rs +++ b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.rs @@ -1,24 +1,28 @@ +use std::collections::HashMap; + impl Solution { pub fn take_characters(s: String, k: i32) -> i32 { - let s = s.as_bytes(); - let mut count = vec![0; 3]; - for c in s.iter() { - count[(c - b'a') as usize] += 1; + let mut cnt: HashMap = HashMap::new(); + for c in s.chars() { + *cnt.entry(c).or_insert(0) += 1; } - if count.iter().any(|v| *v < k) { + + if "abc".chars().any(|c| cnt.get(&c).unwrap_or(&0) < &k) { return -1; } - let n = s.len(); - let mut ans = 0; - let mut i = 0; - for j in 0..n { - count[(s[j] - b'a') as usize] -= 1; - while count[(s[j] - b'a') as usize] < k { - count[(s[i] - b'a') as usize] += 1; - i += 1; + + let mut mx = 0; + let mut j = 0; + let mut cs = s.chars().collect::>(); + for i in 0..cs.len() { + let c = cs[i]; + *cnt.get_mut(&c).unwrap() -= 1; + while cnt.get(&c).unwrap() < &k { + *cnt.get_mut(&cs[j]).unwrap() += 1; + j += 1; } - ans = ans.max(j - i + 1); + mx = mx.max(i - j + 1); } - (n - ans) as i32 + (cs.len() as i32) - (mx as i32) } } diff --git a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.ts b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.ts index ef173ba25862f..611d3226c8c1c 100644 --- a/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.ts +++ b/solution/2500-2599/2516.Take K of Each Character From Left and Right/Solution.ts @@ -1,21 +1,21 @@ function takeCharacters(s: string, k: number): number { - const getIndex = (c: string) => c.charCodeAt(0) - 'a'.charCodeAt(0); - const count = [0, 0, 0]; + const idx = (c: string) => c.charCodeAt(0) - 97; + const cnt: number[] = Array(3).fill(0); for (const c of s) { - count[getIndex(c)]++; + ++cnt[idx(c)]; } - if (count.some(v => v < k)) { + if (cnt.some(v => v < k)) { return -1; } const n = s.length; - let ans = 0; - for (let i = 0, j = 0; j < n; j++) { - count[getIndex(s[j])]--; - while (count[getIndex(s[j])] < k) { - count[getIndex(s[i])]++; - i++; + let [mx, j] = [0, 0]; + for (let i = 0; i < n; ++i) { + const c = idx(s[i]); + --cnt[c]; + while (cnt[c] < k) { + ++cnt[idx(s[j++])]; } - ans = Math.max(ans, j - i + 1); + mx = Math.max(mx, i - j + 1); } - return n - ans; + return n - mx; }