diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/README.md b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/README.md index c2b1874c84663..f46042b1a0c62 100644 --- a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/README.md +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/README.md @@ -111,7 +111,7 @@ class Solution { ss.add(t.charAt(j)); } if (ss.size() <= maxLetters) { - cnt.put(t, cnt.getOrDefault(t, 0) + 1); + cnt.merge(t, 1, Integer::sum); ans = Math.max(ans, cnt.get(t)); } } @@ -180,6 +180,415 @@ function maxFreq(s: string, maxLetters: number, minSize: number, maxSize: number } ``` +#### Rust + +```rust +use std::collections::{HashMap, HashSet}; + +impl Solution { + pub fn max_freq(s: String, max_letters: i32, min_size: i32, _max_size: i32) -> i32 { + let n = s.len(); + let m = min_size as usize; + let max_letters = max_letters as usize; + let bytes = s.as_bytes(); + let mut cnt: HashMap<&[u8], i32> = HashMap::new(); + let mut ans = 0; + + for i in 0..=n - m { + let t = &bytes[i..i + m]; + + let mut set = HashSet::new(); + for &c in t { + set.insert(c); + if set.len() > max_letters { + break; + } + } + if set.len() <= max_letters { + let v = cnt.entry(t).or_insert(0); + *v += 1; + ans = ans.max(*v); + } + } + + ans + } +} +``` + + + + + + + +### 方法二:滑动窗口 + 字符串哈希 + +我们可以使用滑动窗口来维护当前子串中不同字母的数目,同时使用字符串哈希来高效地计算子串的哈希值,从而避免使用字符串作为哈希表的键,提升性能。 + +具体地,我们定义一个 $\textit{Hashing}$ 类来预处理字符串 $s$ 的前缀哈希值和幂次值,从而可以在 $O(1)$ 的时间内计算任意子串的哈希值。 + +然后,我们使用滑动窗口遍历字符串 $s$,维护当前窗口中不同字母的数目,并在窗口大小达到 $\textit{minSize}$ 时,计算当前子串的哈希值并更新出现次数。然后,将窗口向右滑动一个位置,更新字母频率和不同字母数目。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为字符串 $s$ 的长度。 + + + +#### Python3 + +```python +class Hashing: + __slots__ = ["mod", "h", "p"] + + def __init__( + self, s: Union[str, List[str]], base: int = 13331, mod: int = 998244353 + ): + self.mod = mod + self.h = [0] * (len(s) + 1) + self.p = [1] * (len(s) + 1) + for i in range(1, len(s) + 1): + self.h[i] = (self.h[i - 1] * base + ord(s[i - 1])) % mod + self.p[i] = (self.p[i - 1] * base) % mod + + def query(self, l: int, r: int) -> int: + return (self.h[r] - self.h[l - 1] * self.p[r - l + 1]) % self.mod + + +class Solution: + def maxFreq(self, s: str, maxLetters: int, minSize: int, maxSize: int) -> int: + freq = Counter() + hashing = Hashing(s) + cnt = Counter() + ans = k = 0 + for i, c in enumerate(s, 1): + freq[c] += 1 + if freq[c] == 1: + k += 1 + if i >= minSize: + if k <= maxLetters: + x = hashing.query(i - minSize + 1, i) + cnt[x] += 1 + ans = max(ans, cnt[x]) + j = i - minSize + freq[s[j]] -= 1 + if freq[s[j]] == 0: + k -= 1 + return ans +``` + +#### Java + +```java +class Hashing { + private final long[] p; + private final long[] h; + private final long mod; + + public Hashing(String word) { + this(word, 13331, 998244353); + } + + public Hashing(String word, long base, int mod) { + int n = word.length(); + p = new long[n + 1]; + h = new long[n + 1]; + p[0] = 1; + this.mod = mod; + for (int i = 1; i <= n; i++) { + p[i] = p[i - 1] * base % mod; + h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod; + } + } + + public long query(int l, int r) { + return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod; + } +} + +class Solution { + public int maxFreq(String s, int maxLetters, int minSize, int maxSize) { + int n = s.length(); + Hashing hashing = new Hashing(s); + int[] freq = new int[256]; + int k = 0; + int ans = 0; + Map cnt = new HashMap<>(); + + for (int i = 1; i <= n; i++) { + if (++freq[s.charAt(i - 1)] == 1) { + k++; + } + + if (i >= minSize) { + if (k <= maxLetters) { + long x = hashing.query(i - minSize + 1, i); + ans = Math.max(ans, cnt.merge(x, 1, Integer::sum)); + } + int j = i - minSize; + if (--freq[s.charAt(j)] == 0) { + k--; + } + } + } + + return ans; + } +} +``` + +#### C++ + +```cpp +class Hashing { +public: + vector p, h; + long long mod; + + Hashing(const string& word) + : Hashing(word, 13331, 998244353) {} + + Hashing(const string& word, long long base, long long mod) + : mod(mod) { + int n = word.size(); + p.assign(n + 1, 1); + h.assign(n + 1, 0); + for (int i = 1; i <= n; i++) { + p[i] = p[i - 1] * base % mod; + h[i] = (h[i - 1] * base + word[i - 1]) % mod; + } + } + + long long query(int l, int r) { + return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod; + } +}; + +class Solution { +public: + int maxFreq(string s, int maxLetters, int minSize, int maxSize) { + int n = s.size(); + Hashing hashing(s); + vector freq(256, 0); + int k = 0; + int ans = 0; + unordered_map cnt; + + for (int i = 1; i <= n; i++) { + if (++freq[s[i - 1]] == 1) { + k++; + } + + if (i >= minSize) { + if (k <= maxLetters) { + long long x = hashing.query(i - minSize + 1, i); + ans = max(ans, ++cnt[x]); + } + int j = i - minSize; + if (--freq[s[j]] == 0) { + k--; + } + } + } + + return ans; + } +}; +``` + +#### Go + +```go +func maxFreq(s string, maxLetters int, minSize int, maxSize int) int { + n := len(s) + hashing := NewHashing(s) + freq := make([]int, 256) + k := 0 + ans := 0 + cnt := make(map[uint64]int) + + for i := 1; i <= n; i++ { + c := s[i-1] + freq[c]++ + if freq[c] == 1 { + k++ + } + + if i >= minSize { + if k <= maxLetters { + x := hashing.Query(i-minSize+1, i) + cnt[x]++ + if cnt[x] > ans { + ans = cnt[x] + } + } + j := i - minSize + c2 := s[j] + freq[c2]-- + if freq[c2] == 0 { + k-- + } + } + } + + return ans +} + +type Hashing struct { + p, h []uint64 + mod uint64 + base uint64 +} + +func NewHashing(word string) *Hashing { + return NewHashingWithBase(word, 13331, 998244353) +} + +func NewHashingWithBase(word string, base uint64, mod uint64) *Hashing { + n := len(word) + p := make([]uint64, n+1) + h := make([]uint64, n+1) + p[0] = 1 + for i := 1; i <= n; i++ { + p[i] = p[i-1] * base % mod + h[i] = (h[i-1]*base + uint64(word[i-1])) % mod + } + return &Hashing{p, h, mod, base} +} + +func (hs *Hashing) Query(l, r int) uint64 { + return (hs.h[r] + hs.mod - hs.h[l-1]*hs.p[r-l+1]%hs.mod) % hs.mod +} +``` + +#### TypeScript + +```ts +class Hashing { + private p: bigint[]; + private h: bigint[]; + private mod: bigint; + + constructor(s: string, base: bigint = 13331n, mod: bigint = 998244353n) { + const n = s.length; + this.mod = mod; + this.p = new Array(n + 1).fill(1n); + this.h = new Array(n + 1).fill(0n); + for (let i = 1; i <= n; i++) { + this.p[i] = (this.p[i - 1] * base) % mod; + this.h[i] = (this.h[i - 1] * base + BigInt(s.charCodeAt(i - 1))) % mod; + } + } + + query(l: number, r: number): bigint { + return (this.h[r] - ((this.h[l - 1] * this.p[r - l + 1]) % this.mod) + this.mod) % this.mod; + } +} + +function maxFreq(s: string, maxLetters: number, minSize: number, maxSize: number): number { + const n = s.length; + const hashing = new Hashing(s); + const freq = new Array(256).fill(0); + let k = 0; + let ans = 0; + const cnt = new Map(); + + for (let i = 1; i <= n; i++) { + const c = s.charCodeAt(i - 1); + if (++freq[c] === 1) { + k++; + } + + if (i >= minSize) { + if (k <= maxLetters) { + const x = hashing.query(i - minSize + 1, i); + const v = (cnt.get(x) || 0) + 1; + cnt.set(x, v); + ans = Math.max(ans, v); + } + const j = i - minSize; + const c2 = s.charCodeAt(j); + if (--freq[c2] === 0) { + k--; + } + } + } + + return ans; +} +``` + +#### Rust + +```rust +impl Solution { + pub fn max_freq(s: String, max_letters: i32, min_size: i32, _max_size: i32) -> i32 { + let n = s.len(); + let bytes = s.as_bytes(); + let hashing = Hashing::new(bytes.to_vec()); + let mut freq = [0i32; 256]; + let mut k = 0; + let mut ans = 0; + let mut cnt: std::collections::HashMap = std::collections::HashMap::new(); + + for i in 1..=n { + let c = bytes[i - 1] as usize; + freq[c] += 1; + if freq[c] == 1 { + k += 1; + } + + if i as i32 >= min_size { + if k <= max_letters { + let x = hashing.query(i - min_size as usize, i - 1); + let v = cnt.entry(x).and_modify(|v| *v += 1).or_insert(1); + ans = ans.max(*v); + } + let j = i - min_size as usize; + let c2 = bytes[j] as usize; + freq[c2] -= 1; + if freq[c2] == 0 { + k -= 1; + } + } + } + + ans + } +} + +struct Hashing { + p: Vec, + h: Vec, + base: u64, + modv: u64, +} + +impl Hashing { + fn new(s: Vec) -> Self { + Self::with_params(s, 13331, 998244353) + } + + fn with_params(s: Vec, base: u64, modv: u64) -> Self { + let n = s.len(); + let mut p = vec![0u64; n + 1]; + let mut h = vec![0u64; n + 1]; + p[0] = 1; + for i in 1..=n { + p[i] = p[i - 1].wrapping_mul(base) % modv; + h[i] = (h[i - 1].wrapping_mul(base) + s[i - 1] as u64) % modv; + } + Self { p, h, base, modv } + } + + fn query(&self, l: usize, r: usize) -> u64 { + let mut res = + self.h[r + 1] + self.modv - (self.h[l] * self.p[r - l + 1] % self.modv); + res %= self.modv; + res + } +} +``` + diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/README_EN.md b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/README_EN.md index 2aa30af79cc2e..2a94cc74c2d54 100644 --- a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/README_EN.md +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/README_EN.md @@ -99,7 +99,7 @@ class Solution { ss.add(t.charAt(j)); } if (ss.size() <= maxLetters) { - cnt.put(t, cnt.getOrDefault(t, 0) + 1); + cnt.merge(t, 1, Integer::sum); ans = Math.max(ans, cnt.get(t)); } } @@ -168,6 +168,415 @@ function maxFreq(s: string, maxLetters: number, minSize: number, maxSize: number } ``` +#### Rust + +```rust +use std::collections::{HashMap, HashSet}; + +impl Solution { + pub fn max_freq(s: String, max_letters: i32, min_size: i32, _max_size: i32) -> i32 { + let n = s.len(); + let m = min_size as usize; + let max_letters = max_letters as usize; + let bytes = s.as_bytes(); + let mut cnt: HashMap<&[u8], i32> = HashMap::new(); + let mut ans = 0; + + for i in 0..=n - m { + let t = &bytes[i..i + m]; + + let mut set = HashSet::new(); + for &c in t { + set.insert(c); + if set.len() > max_letters { + break; + } + } + if set.len() <= max_letters { + let v = cnt.entry(t).or_insert(0); + *v += 1; + ans = ans.max(*v); + } + } + + ans + } +} +``` + + + + + + + +### Solution 2: Sliding Window + String Hashing + +We can use a sliding window to maintain the number of distinct letters in the current substring, while using string hashing to efficiently calculate the hash value of substrings, thereby avoiding using strings as hash table keys and improving performance. + +Specifically, we define a $\textit{Hashing}$ class to preprocess the prefix hash values and power values of the string $s$, so that we can calculate the hash value of any substring in $O(1)$ time. + +Then, we use a sliding window to traverse the string $s$, maintaining the number of distinct letters in the current window. When the window size reaches $\textit{minSize}$, we calculate the hash value of the current substring and update its occurrence count. Next, we slide the window one position to the right and update the letter frequencies and the count of distinct letters. + +The time complexity is $O(n)$ and the space complexity is $O(n)$, where $n$ is the length of the string $s$. + + + +#### Python3 + +```python +class Hashing: + __slots__ = ["mod", "h", "p"] + + def __init__( + self, s: Union[str, List[str]], base: int = 13331, mod: int = 998244353 + ): + self.mod = mod + self.h = [0] * (len(s) + 1) + self.p = [1] * (len(s) + 1) + for i in range(1, len(s) + 1): + self.h[i] = (self.h[i - 1] * base + ord(s[i - 1])) % mod + self.p[i] = (self.p[i - 1] * base) % mod + + def query(self, l: int, r: int) -> int: + return (self.h[r] - self.h[l - 1] * self.p[r - l + 1]) % self.mod + + +class Solution: + def maxFreq(self, s: str, maxLetters: int, minSize: int, maxSize: int) -> int: + freq = Counter() + hashing = Hashing(s) + cnt = Counter() + ans = k = 0 + for i, c in enumerate(s, 1): + freq[c] += 1 + if freq[c] == 1: + k += 1 + if i >= minSize: + if k <= maxLetters: + x = hashing.query(i - minSize + 1, i) + cnt[x] += 1 + ans = max(ans, cnt[x]) + j = i - minSize + freq[s[j]] -= 1 + if freq[s[j]] == 0: + k -= 1 + return ans +``` + +#### Java + +```java +class Hashing { + private final long[] p; + private final long[] h; + private final long mod; + + public Hashing(String word) { + this(word, 13331, 998244353); + } + + public Hashing(String word, long base, int mod) { + int n = word.length(); + p = new long[n + 1]; + h = new long[n + 1]; + p[0] = 1; + this.mod = mod; + for (int i = 1; i <= n; i++) { + p[i] = p[i - 1] * base % mod; + h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod; + } + } + + public long query(int l, int r) { + return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod; + } +} + +class Solution { + public int maxFreq(String s, int maxLetters, int minSize, int maxSize) { + int n = s.length(); + Hashing hashing = new Hashing(s); + int[] freq = new int[256]; + int k = 0; + int ans = 0; + Map cnt = new HashMap<>(); + + for (int i = 1; i <= n; i++) { + if (++freq[s.charAt(i - 1)] == 1) { + k++; + } + + if (i >= minSize) { + if (k <= maxLetters) { + long x = hashing.query(i - minSize + 1, i); + ans = Math.max(ans, cnt.merge(x, 1, Integer::sum)); + } + int j = i - minSize; + if (--freq[s.charAt(j)] == 0) { + k--; + } + } + } + + return ans; + } +} +``` + +#### C++ + +```cpp +class Hashing { +public: + vector p, h; + long long mod; + + Hashing(const string& word) + : Hashing(word, 13331, 998244353) {} + + Hashing(const string& word, long long base, long long mod) + : mod(mod) { + int n = word.size(); + p.assign(n + 1, 1); + h.assign(n + 1, 0); + for (int i = 1; i <= n; i++) { + p[i] = p[i - 1] * base % mod; + h[i] = (h[i - 1] * base + word[i - 1]) % mod; + } + } + + long long query(int l, int r) { + return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod; + } +}; + +class Solution { +public: + int maxFreq(string s, int maxLetters, int minSize, int maxSize) { + int n = s.size(); + Hashing hashing(s); + vector freq(256, 0); + int k = 0; + int ans = 0; + unordered_map cnt; + + for (int i = 1; i <= n; i++) { + if (++freq[s[i - 1]] == 1) { + k++; + } + + if (i >= minSize) { + if (k <= maxLetters) { + long long x = hashing.query(i - minSize + 1, i); + ans = max(ans, ++cnt[x]); + } + int j = i - minSize; + if (--freq[s[j]] == 0) { + k--; + } + } + } + + return ans; + } +}; +``` + +#### Go + +```go +func maxFreq(s string, maxLetters int, minSize int, maxSize int) int { + n := len(s) + hashing := NewHashing(s) + freq := make([]int, 256) + k := 0 + ans := 0 + cnt := make(map[uint64]int) + + for i := 1; i <= n; i++ { + c := s[i-1] + freq[c]++ + if freq[c] == 1 { + k++ + } + + if i >= minSize { + if k <= maxLetters { + x := hashing.Query(i-minSize+1, i) + cnt[x]++ + if cnt[x] > ans { + ans = cnt[x] + } + } + j := i - minSize + c2 := s[j] + freq[c2]-- + if freq[c2] == 0 { + k-- + } + } + } + + return ans +} + +type Hashing struct { + p, h []uint64 + mod uint64 + base uint64 +} + +func NewHashing(word string) *Hashing { + return NewHashingWithBase(word, 13331, 998244353) +} + +func NewHashingWithBase(word string, base uint64, mod uint64) *Hashing { + n := len(word) + p := make([]uint64, n+1) + h := make([]uint64, n+1) + p[0] = 1 + for i := 1; i <= n; i++ { + p[i] = p[i-1] * base % mod + h[i] = (h[i-1]*base + uint64(word[i-1])) % mod + } + return &Hashing{p, h, mod, base} +} + +func (hs *Hashing) Query(l, r int) uint64 { + return (hs.h[r] + hs.mod - hs.h[l-1]*hs.p[r-l+1]%hs.mod) % hs.mod +} +``` + +#### TypeScript + +```ts +class Hashing { + private p: bigint[]; + private h: bigint[]; + private mod: bigint; + + constructor(s: string, base: bigint = 13331n, mod: bigint = 998244353n) { + const n = s.length; + this.mod = mod; + this.p = new Array(n + 1).fill(1n); + this.h = new Array(n + 1).fill(0n); + for (let i = 1; i <= n; i++) { + this.p[i] = (this.p[i - 1] * base) % mod; + this.h[i] = (this.h[i - 1] * base + BigInt(s.charCodeAt(i - 1))) % mod; + } + } + + query(l: number, r: number): bigint { + return (this.h[r] - ((this.h[l - 1] * this.p[r - l + 1]) % this.mod) + this.mod) % this.mod; + } +} + +function maxFreq(s: string, maxLetters: number, minSize: number, maxSize: number): number { + const n = s.length; + const hashing = new Hashing(s); + const freq = new Array(256).fill(0); + let k = 0; + let ans = 0; + const cnt = new Map(); + + for (let i = 1; i <= n; i++) { + const c = s.charCodeAt(i - 1); + if (++freq[c] === 1) { + k++; + } + + if (i >= minSize) { + if (k <= maxLetters) { + const x = hashing.query(i - minSize + 1, i); + const v = (cnt.get(x) || 0) + 1; + cnt.set(x, v); + ans = Math.max(ans, v); + } + const j = i - minSize; + const c2 = s.charCodeAt(j); + if (--freq[c2] === 0) { + k--; + } + } + } + + return ans; +} +``` + +#### Rust + +```rust +impl Solution { + pub fn max_freq(s: String, max_letters: i32, min_size: i32, _max_size: i32) -> i32 { + let n = s.len(); + let bytes = s.as_bytes(); + let hashing = Hashing::new(bytes.to_vec()); + let mut freq = [0i32; 256]; + let mut k = 0; + let mut ans = 0; + let mut cnt: std::collections::HashMap = std::collections::HashMap::new(); + + for i in 1..=n { + let c = bytes[i - 1] as usize; + freq[c] += 1; + if freq[c] == 1 { + k += 1; + } + + if i as i32 >= min_size { + if k <= max_letters { + let x = hashing.query(i - min_size as usize, i - 1); + let v = cnt.entry(x).and_modify(|v| *v += 1).or_insert(1); + ans = ans.max(*v); + } + let j = i - min_size as usize; + let c2 = bytes[j] as usize; + freq[c2] -= 1; + if freq[c2] == 0 { + k -= 1; + } + } + } + + ans + } +} + +struct Hashing { + p: Vec, + h: Vec, + base: u64, + modv: u64, +} + +impl Hashing { + fn new(s: Vec) -> Self { + Self::with_params(s, 13331, 998244353) + } + + fn with_params(s: Vec, base: u64, modv: u64) -> Self { + let n = s.len(); + let mut p = vec![0u64; n + 1]; + let mut h = vec![0u64; n + 1]; + p[0] = 1; + for i in 1..=n { + p[i] = p[i - 1].wrapping_mul(base) % modv; + h[i] = (h[i - 1].wrapping_mul(base) + s[i - 1] as u64) % modv; + } + Self { p, h, base, modv } + } + + fn query(&self, l: usize, r: usize) -> u64 { + let mut res = + self.h[r + 1] + self.modv - (self.h[l] * self.p[r - l + 1] % self.modv); + res %= self.modv; + res + } +} +``` + diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution.java b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution.java index 917769b3d334c..6b4570c6c6691 100644 --- a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution.java +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution.java @@ -9,10 +9,10 @@ public int maxFreq(String s, int maxLetters, int minSize, int maxSize) { ss.add(t.charAt(j)); } if (ss.size() <= maxLetters) { - cnt.put(t, cnt.getOrDefault(t, 0) + 1); + cnt.merge(t, 1, Integer::sum); ans = Math.max(ans, cnt.get(t)); } } return ans; } -} \ No newline at end of file +} diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution.rs b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution.rs new file mode 100644 index 0000000000000..4013894a0b6e0 --- /dev/null +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution.rs @@ -0,0 +1,31 @@ +use std::collections::{HashMap, HashSet}; + +impl Solution { + pub fn max_freq(s: String, max_letters: i32, min_size: i32, _max_size: i32) -> i32 { + let n = s.len(); + let m = min_size as usize; + let max_letters = max_letters as usize; + let bytes = s.as_bytes(); + let mut cnt: HashMap<&[u8], i32> = HashMap::new(); + let mut ans = 0; + + for i in 0..=n - m { + let t = &bytes[i..i + m]; + + let mut set = HashSet::new(); + for &c in t { + set.insert(c); + if set.len() > max_letters { + break; + } + } + if set.len() <= max_letters { + let v = cnt.entry(t).or_insert(0); + *v += 1; + ans = ans.max(*v); + } + } + + ans + } +} diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.cpp b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.cpp new file mode 100644 index 0000000000000..9ab02bc8c73fa --- /dev/null +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.cpp @@ -0,0 +1,54 @@ +class Hashing { +public: + vector p, h; + long long mod; + + Hashing(const string& word) + : Hashing(word, 13331, 998244353) {} + + Hashing(const string& word, long long base, long long mod) + : mod(mod) { + int n = word.size(); + p.assign(n + 1, 1); + h.assign(n + 1, 0); + for (int i = 1; i <= n; i++) { + p[i] = p[i - 1] * base % mod; + h[i] = (h[i - 1] * base + word[i - 1]) % mod; + } + } + + long long query(int l, int r) { + return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod; + } +}; + +class Solution { +public: + int maxFreq(string s, int maxLetters, int minSize, int maxSize) { + int n = s.size(); + Hashing hashing(s); + vector freq(256, 0); + int k = 0; + int ans = 0; + unordered_map cnt; + + for (int i = 1; i <= n; i++) { + if (++freq[s[i - 1]] == 1) { + k++; + } + + if (i >= minSize) { + if (k <= maxLetters) { + long long x = hashing.query(i - minSize + 1, i); + ans = max(ans, ++cnt[x]); + } + int j = i - minSize; + if (--freq[s[j]] == 0) { + k--; + } + } + } + + return ans; + } +}; diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.go b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.go new file mode 100644 index 0000000000000..070471ba4b307 --- /dev/null +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.go @@ -0,0 +1,60 @@ +func maxFreq(s string, maxLetters int, minSize int, maxSize int) int { + n := len(s) + hashing := NewHashing(s) + freq := make([]int, 256) + k := 0 + ans := 0 + cnt := make(map[uint64]int) + + for i := 1; i <= n; i++ { + c := s[i-1] + freq[c]++ + if freq[c] == 1 { + k++ + } + + if i >= minSize { + if k <= maxLetters { + x := hashing.Query(i-minSize+1, i) + cnt[x]++ + if cnt[x] > ans { + ans = cnt[x] + } + } + j := i - minSize + c2 := s[j] + freq[c2]-- + if freq[c2] == 0 { + k-- + } + } + } + + return ans +} + +type Hashing struct { + p, h []uint64 + mod uint64 + base uint64 +} + +func NewHashing(word string) *Hashing { + return NewHashingWithBase(word, 13331, 998244353) +} + +func NewHashingWithBase(word string, base uint64, mod uint64) *Hashing { + n := len(word) + p := make([]uint64, n+1) + h := make([]uint64, n+1) + p[0] = 1 + for i := 1; i <= n; i++ { + p[i] = p[i-1] * base % mod + h[i] = (h[i-1]*base + uint64(word[i-1])) % mod + } + return &Hashing{p, h, mod, base} +} + +func (hs *Hashing) Query(l, r int) uint64 { + return (hs.h[r] + hs.mod - hs.h[l-1]*hs.p[r-l+1]%hs.mod) % hs.mod +} diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.java b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.java new file mode 100644 index 0000000000000..4192347a8e7c4 --- /dev/null +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.java @@ -0,0 +1,55 @@ +class Hashing { + private final long[] p; + private final long[] h; + private final long mod; + + public Hashing(String word) { + this(word, 13331, 998244353); + } + + public Hashing(String word, long base, int mod) { + int n = word.length(); + p = new long[n + 1]; + h = new long[n + 1]; + p[0] = 1; + this.mod = mod; + for (int i = 1; i <= n; i++) { + p[i] = p[i - 1] * base % mod; + h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod; + } + } + + public long query(int l, int r) { + return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod; + } +} + +class Solution { + public int maxFreq(String s, int maxLetters, int minSize, int maxSize) { + int n = s.length(); + Hashing hashing = new Hashing(s); + int[] freq = new int[256]; + int k = 0; + int ans = 0; + Map cnt = new HashMap<>(); + + for (int i = 1; i <= n; i++) { + if (++freq[s.charAt(i - 1)] == 1) { + k++; + } + + if (i >= minSize) { + if (k <= maxLetters) { + long x = hashing.query(i - minSize + 1, i); + ans = Math.max(ans, cnt.merge(x, 1, Integer::sum)); + } + int j = i - minSize; + if (--freq[s.charAt(j)] == 0) { + k--; + } + } + } + + return ans; + } +} diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.py b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.py new file mode 100644 index 0000000000000..0ae29a3a43744 --- /dev/null +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.py @@ -0,0 +1,37 @@ +class Hashing: + __slots__ = ["mod", "h", "p"] + + def __init__( + self, s: Union[str, List[str]], base: int = 13331, mod: int = 998244353 + ): + self.mod = mod + self.h = [0] * (len(s) + 1) + self.p = [1] * (len(s) + 1) + for i in range(1, len(s) + 1): + self.h[i] = (self.h[i - 1] * base + ord(s[i - 1])) % mod + self.p[i] = (self.p[i - 1] * base) % mod + + def query(self, l: int, r: int) -> int: + return (self.h[r] - self.h[l - 1] * self.p[r - l + 1]) % self.mod + + +class Solution: + def maxFreq(self, s: str, maxLetters: int, minSize: int, maxSize: int) -> int: + freq = Counter() + hashing = Hashing(s) + cnt = Counter() + ans = k = 0 + for i, c in enumerate(s, 1): + freq[c] += 1 + if freq[c] == 1: + k += 1 + if i >= minSize: + if k <= maxLetters: + x = hashing.query(i - minSize + 1, i) + cnt[x] += 1 + ans = max(ans, cnt[x]) + j = i - minSize + freq[s[j]] -= 1 + if freq[s[j]] == 0: + k -= 1 + return ans diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.rs b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.rs new file mode 100644 index 0000000000000..4fb81c5e65fe5 --- /dev/null +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.rs @@ -0,0 +1,67 @@ +impl Solution { + pub fn max_freq(s: String, max_letters: i32, min_size: i32, _max_size: i32) -> i32 { + let n = s.len(); + let bytes = s.as_bytes(); + let hashing = Hashing::new(bytes.to_vec()); + let mut freq = [0i32; 256]; + let mut k = 0; + let mut ans = 0; + let mut cnt: std::collections::HashMap = std::collections::HashMap::new(); + + for i in 1..=n { + let c = bytes[i - 1] as usize; + freq[c] += 1; + if freq[c] == 1 { + k += 1; + } + + if i as i32 >= min_size { + if k <= max_letters { + let x = hashing.query(i - min_size as usize, i - 1); + let v = cnt.entry(x).and_modify(|v| *v += 1).or_insert(1); + ans = ans.max(*v); + } + let j = i - min_size as usize; + let c2 = bytes[j] as usize; + freq[c2] -= 1; + if freq[c2] == 0 { + k -= 1; + } + } + } + + ans + } +} + +struct Hashing { + p: Vec, + h: Vec, + base: u64, + modv: u64, +} + +impl Hashing { + fn new(s: Vec) -> Self { + Self::with_params(s, 13331, 998244353) + } + + fn with_params(s: Vec, base: u64, modv: u64) -> Self { + let n = s.len(); + let mut p = vec![0u64; n + 1]; + let mut h = vec![0u64; n + 1]; + p[0] = 1; + for i in 1..=n { + p[i] = p[i - 1].wrapping_mul(base) % modv; + h[i] = (h[i - 1].wrapping_mul(base) + s[i - 1] as u64) % modv; + } + Self { p, h, base, modv } + } + + fn query(&self, l: usize, r: usize) -> u64 { + let mut res = + self.h[r + 1] + self.modv - (self.h[l] * self.p[r - l + 1] % self.modv); + res %= self.modv; + res + } +} diff --git a/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.ts b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.ts new file mode 100644 index 0000000000000..8a4299b2f90a1 --- /dev/null +++ b/solution/1200-1299/1297.Maximum Number of Occurrences of a Substring/Solution2.ts @@ -0,0 +1,52 @@ +class Hashing { + private p: bigint[]; + private h: bigint[]; + private mod: bigint; + + constructor(s: string, base: bigint = 13331n, mod: bigint = 998244353n) { + const n = s.length; + this.mod = mod; + this.p = new Array(n + 1).fill(1n); + this.h = new Array(n + 1).fill(0n); + for (let i = 1; i <= n; i++) { + this.p[i] = (this.p[i - 1] * base) % mod; + this.h[i] = (this.h[i - 1] * base + BigInt(s.charCodeAt(i - 1))) % mod; + } + } + + query(l: number, r: number): bigint { + return (this.h[r] - ((this.h[l - 1] * this.p[r - l + 1]) % this.mod) + this.mod) % this.mod; + } +} + +function maxFreq(s: string, maxLetters: number, minSize: number, maxSize: number): number { + const n = s.length; + const hashing = new Hashing(s); + const freq = new Array(256).fill(0); + let k = 0; + let ans = 0; + const cnt = new Map(); + + for (let i = 1; i <= n; i++) { + const c = s.charCodeAt(i - 1); + if (++freq[c] === 1) { + k++; + } + + if (i >= minSize) { + if (k <= maxLetters) { + const x = hashing.query(i - minSize + 1, i); + const v = (cnt.get(x) || 0) + 1; + cnt.set(x, v); + ans = Math.max(ans, v); + } + const j = i - minSize; + const c2 = s.charCodeAt(j); + if (--freq[c2] === 0) { + k--; + } + } + } + + return ans; +}