diff --git a/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/README.md b/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/README.md index 1355c3c47e533..84d14bba28059 100644 --- a/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/README.md +++ b/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/README.md @@ -402,6 +402,176 @@ func minValidStrings(words []string, target string) (ans int) { } ``` +#### TypeScript + +```ts +function minValidStrings(words: string[], target: string): number { + class Hashing { + private p: bigint[]; + private h: bigint[]; + private mod: bigint; + + constructor(word: string, base: bigint, mod: bigint) { + const n = word.length; + this.p = new Array(n + 1).fill(0n); + this.h = new Array(n + 1).fill(0n); + this.mod = mod; + this.p[0] = 1n; + 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(word.charCodeAt(i - 1))) % mod; + } + } + + query(l: number, r: number): bigint { + const res = + (this.h[r] - ((this.h[l - 1] * this.p[r - l + 1]) % this.mod) + this.mod) % + this.mod; + return res; + } + } + + const base = 13331n; + const mod = 998244353n; + const hashing = new Hashing(target, base, mod); + + const m = Math.max(0, ...words.map(w => w.length)); + const s: Set[] = Array.from({ length: m + 1 }, () => new Set()); + + for (const w of words) { + let h = 0n; + for (let j = 0; j < w.length; ++j) { + h = (h * base + BigInt(w.charCodeAt(j))) % mod; + s[j + 1].add(h); + } + } + + const n = target.length; + let ans = 0; + let last = 0; + let mx = 0; + + const f = (i: number): number => { + let l = 0; + let r = Math.min(n - i, m); + while (l < r) { + const mid = (l + r + 1)>> 1; + const sub = hashing.query(i + 1, i + mid); + if (s[mid].has(sub)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; + }; + + for (let i = 0; i < n; ++i) { + const dist = f(i); + mx = Math.max(mx, i + dist); + if (i === last) { + if (i === mx) { + return -1; + } + last = mx; + ans++; + } + } + + return ans; +} +``` + +#### Rust + +```rust +use std::collections::HashSet; +use std::cmp::max; + +struct Hashing { + p: Vec, + h: Vec, + base: i64, + modv: i64, +} + +impl Hashing { + fn new(word: &str, base: i64, modv: i64) -> Self { + let n = word.len(); + let mut p = vec![0; n + 1]; + let mut h = vec![0; n + 1]; + let bytes = word.as_bytes(); + p[0] = 1; + for i in 1..=n { + p[i] = p[i - 1] * base % modv; + h[i] = (h[i - 1] * base + bytes[i - 1] as i64) % modv; + } + Self { p, h, base, modv } + } + + fn query(&self, l: usize, r: usize) -> i64 { + let mut res = self.h[r] - self.h[l - 1] * self.p[r - l + 1] % self.modv; + if res < 0 { + res += self.modv; + } + res % self.modv + } +} + +impl Solution { + pub fn min_valid_strings(words: Vec, target: String) -> i32 { + let base = 13331; + let modv = 998_244_353; + let hashing = Hashing::new(&target, base, modv); + let m = words.iter().map(|w| w.len()).max().unwrap_or(0); + let mut s: Vec> = vec![HashSet::new(); m + 1]; + + for w in &words { + let mut h = 0i64; + for (j, &b) in w.as_bytes().iter().enumerate() { + h = (h * base + b as i64) % modv; + s[j + 1].insert(h); + } + } + + let n = target.len(); + let bytes = target.as_bytes(); + let mut ans = 0; + let mut last = 0; + let mut mx = 0; + + let f = |i: usize, n: usize, m: usize, s: &Vec>, hashing: &Hashing| -> usize { + let mut l = 0; + let mut r = std::cmp::min(n - i, m); + while l < r { + let mid = (l + r + 1)>> 1; + let sub = hashing.query(i + 1, i + mid); + if s[mid].contains(&sub) { + l = mid; + } else { + r = mid - 1; + } + } + l + }; + + for i in 0..n { + let dist = f(i, n, m, &s, &hashing); + mx = max(mx, i + dist); + if i == last { + if i == mx { + return -1; + } + last = mx; + ans += 1; + } + } + + ans + } +} +``` + diff --git a/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/README_EN.md b/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/README_EN.md index d058385e811b1..7f7a8785fddb3 100644 --- a/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/README_EN.md +++ b/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/README_EN.md @@ -400,6 +400,176 @@ func minValidStrings(words []string, target string) (ans int) { } ``` +#### TypeScript + +```ts +function minValidStrings(words: string[], target: string): number { + class Hashing { + private p: bigint[]; + private h: bigint[]; + private mod: bigint; + + constructor(word: string, base: bigint, mod: bigint) { + const n = word.length; + this.p = new Array(n + 1).fill(0n); + this.h = new Array(n + 1).fill(0n); + this.mod = mod; + this.p[0] = 1n; + 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(word.charCodeAt(i - 1))) % mod; + } + } + + query(l: number, r: number): bigint { + const res = + (this.h[r] - ((this.h[l - 1] * this.p[r - l + 1]) % this.mod) + this.mod) % + this.mod; + return res; + } + } + + const base = 13331n; + const mod = 998244353n; + const hashing = new Hashing(target, base, mod); + + const m = Math.max(0, ...words.map(w => w.length)); + const s: Set[] = Array.from({ length: m + 1 }, () => new Set()); + + for (const w of words) { + let h = 0n; + for (let j = 0; j < w.length; ++j) { + h = (h * base + BigInt(w.charCodeAt(j))) % mod; + s[j + 1].add(h); + } + } + + const n = target.length; + let ans = 0; + let last = 0; + let mx = 0; + + const f = (i: number): number => { + let l = 0; + let r = Math.min(n - i, m); + while (l < r) { + const mid = (l + r + 1)>> 1; + const sub = hashing.query(i + 1, i + mid); + if (s[mid].has(sub)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; + }; + + for (let i = 0; i < n; ++i) { + const dist = f(i); + mx = Math.max(mx, i + dist); + if (i === last) { + if (i === mx) { + return -1; + } + last = mx; + ans++; + } + } + + return ans; +} +``` + +#### Rust + +```rust +use std::collections::HashSet; +use std::cmp::max; + +struct Hashing { + p: Vec, + h: Vec, + base: i64, + modv: i64, +} + +impl Hashing { + fn new(word: &str, base: i64, modv: i64) -> Self { + let n = word.len(); + let mut p = vec![0; n + 1]; + let mut h = vec![0; n + 1]; + let bytes = word.as_bytes(); + p[0] = 1; + for i in 1..=n { + p[i] = p[i - 1] * base % modv; + h[i] = (h[i - 1] * base + bytes[i - 1] as i64) % modv; + } + Self { p, h, base, modv } + } + + fn query(&self, l: usize, r: usize) -> i64 { + let mut res = self.h[r] - self.h[l - 1] * self.p[r - l + 1] % self.modv; + if res < 0 { + res += self.modv; + } + res % self.modv + } +} + +impl Solution { + pub fn min_valid_strings(words: Vec, target: String) -> i32 { + let base = 13331; + let modv = 998_244_353; + let hashing = Hashing::new(&target, base, modv); + let m = words.iter().map(|w| w.len()).max().unwrap_or(0); + let mut s: Vec> = vec![HashSet::new(); m + 1]; + + for w in &words { + let mut h = 0i64; + for (j, &b) in w.as_bytes().iter().enumerate() { + h = (h * base + b as i64) % modv; + s[j + 1].insert(h); + } + } + + let n = target.len(); + let bytes = target.as_bytes(); + let mut ans = 0; + let mut last = 0; + let mut mx = 0; + + let f = |i: usize, n: usize, m: usize, s: &Vec>, hashing: &Hashing| -> usize { + let mut l = 0; + let mut r = std::cmp::min(n - i, m); + while l < r { + let mid = (l + r + 1)>> 1; + let sub = hashing.query(i + 1, i + mid); + if s[mid].contains(&sub) { + l = mid; + } else { + r = mid - 1; + } + } + l + }; + + for i in 0..n { + let dist = f(i, n, m, &s, &hashing); + mx = max(mx, i + dist); + if i == last { + if i == mx { + return -1; + } + last = mx; + ans += 1; + } + } + + ans + } +} +``` + diff --git a/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/Solution.rs b/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/Solution.rs new file mode 100644 index 0000000000000..17996b305e6e7 --- /dev/null +++ b/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/Solution.rs @@ -0,0 +1,85 @@ +use std::collections::HashSet; +use std::cmp::max; + +struct Hashing { + p: Vec, + h: Vec, + base: i64, + modv: i64, +} + +impl Hashing { + fn new(word: &str, base: i64, modv: i64) -> Self { + let n = word.len(); + let mut p = vec![0; n + 1]; + let mut h = vec![0; n + 1]; + let bytes = word.as_bytes(); + p[0] = 1; + for i in 1..=n { + p[i] = p[i - 1] * base % modv; + h[i] = (h[i - 1] * base + bytes[i - 1] as i64) % modv; + } + Self { p, h, base, modv } + } + + fn query(&self, l: usize, r: usize) -> i64 { + let mut res = self.h[r] - self.h[l - 1] * self.p[r - l + 1] % self.modv; + if res < 0 { + res += self.modv; + } + res % self.modv + } +} + +impl Solution { + pub fn min_valid_strings(words: Vec, target: String) -> i32 { + let base = 13331; + let modv = 998_244_353; + let hashing = Hashing::new(&target, base, modv); + let m = words.iter().map(|w| w.len()).max().unwrap_or(0); + let mut s: Vec> = vec![HashSet::new(); m + 1]; + + for w in &words { + let mut h = 0i64; + for (j, &b) in w.as_bytes().iter().enumerate() { + h = (h * base + b as i64) % modv; + s[j + 1].insert(h); + } + } + + let n = target.len(); + let bytes = target.as_bytes(); + let mut ans = 0; + let mut last = 0; + let mut mx = 0; + + let f = |i: usize, n: usize, m: usize, s: &Vec>, hashing: &Hashing| -> usize { + let mut l = 0; + let mut r = std::cmp::min(n - i, m); + while l < r { + let mid = (l + r + 1)>> 1; + let sub = hashing.query(i + 1, i + mid); + if s[mid].contains(&sub) { + l = mid; + } else { + r = mid - 1; + } + } + l + }; + + for i in 0..n { + let dist = f(i, n, m, &s, &hashing); + mx = max(mx, i + dist); + if i == last { + if i == mx { + return -1; + } + last = mx; + ans += 1; + } + } + + ans + } +} diff --git a/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/Solution.ts b/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/Solution.ts new file mode 100644 index 0000000000000..0301b7a3840d1 --- /dev/null +++ b/solution/3200-3299/3292.Minimum Number of Valid Strings to Form Target II/Solution.ts @@ -0,0 +1,75 @@ +function minValidStrings(words: string[], target: string): number { + class Hashing { + private p: bigint[]; + private h: bigint[]; + private mod: bigint; + + constructor(word: string, base: bigint, mod: bigint) { + const n = word.length; + this.p = new Array(n + 1).fill(0n); + this.h = new Array(n + 1).fill(0n); + this.mod = mod; + this.p[0] = 1n; + 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(word.charCodeAt(i - 1))) % mod; + } + } + + query(l: number, r: number): bigint { + const res = + (this.h[r] - ((this.h[l - 1] * this.p[r - l + 1]) % this.mod) + this.mod) % + this.mod; + return res; + } + } + + const base = 13331n; + const mod = 998244353n; + const hashing = new Hashing(target, base, mod); + + const m = Math.max(0, ...words.map(w => w.length)); + const s: Set[] = Array.from({ length: m + 1 }, () => new Set()); + + for (const w of words) { + let h = 0n; + for (let j = 0; j < w.length; ++j) { + h = (h * base + BigInt(w.charCodeAt(j))) % mod; + s[j + 1].add(h); + } + } + + const n = target.length; + let ans = 0; + let last = 0; + let mx = 0; + + const f = (i: number): number => { + let l = 0; + let r = Math.min(n - i, m); + while (l < r) { + const mid = (l + r + 1)>> 1; + const sub = hashing.query(i + 1, i + mid); + if (s[mid].has(sub)) { + l = mid; + } else { + r = mid - 1; + } + } + return l; + }; + + for (let i = 0; i < n; ++i) { + const dist = f(i); + mx = Math.max(mx, i + dist); + if (i === last) { + if (i === mx) { + return -1; + } + last = mx; + ans++; + } + } + + return ans; +}

AltStyle によって変換されたページ (->オリジナル) /