2025-05-22:找到初始输入字符串Ⅱ。用go语言,Alice 在键盘上输入一个字符串,但由于输入时可能按键时间过长,导致某些字符被重复输入多次。
给定一个字符串 word,表示最终显示在屏幕上的内容,同时给定一个正整数 k,表示 Alice 最初打算输入的字符串长度至少为 k。
请你计算,满足这种情况的所有可能的原字符串方案数,并将结果对 1000000007 取模后返回。
1 <= word.length <= 5 * 100000。
word 只包含小写英文字母。
1 <= k <= 2000。
输入:word = "aabbccdd", k = 7。
输出:5。
解释:
可能的字符串包括:"aabbccdd" ,"aabbccd" ,"aabbcdd" ,"aabccdd" 和 "abbccdd" 。
题目来自力扣3333。
word
分成连续的相同字符的组。例如,"aabbccdd" 分为 ["aa", "bb", "cc", "dd"]。count
个字符(count
是该组字符的原始数量)。c
,则可以选择保留 1 到 c
个字符,因此有 c
种选择。c
的乘积。例如,"aa", "bb", "cc", "dd" 的 c
分别为 2, 2, 2, 2,初始方案数为 2 * 2 * 2 * 2 = 16。k
的情况。k
的方案数,然后用初始方案数减去这些不满足条件的方案数。total_length
,则 total_length
是各组保留字符数的和。total_length < k
的方案数。f[j]
表示选择前 i
组时,总长度为 j
的方案数。f[0] = 1
(不选任何字符的方案数为 1,但实际每组至少选 1 个字符,因此需要调整)。c
,可以选择保留 1 到 c
个字符,因此对动态规划的转移是:j
,f[j]
可以从 f[j - 1]
, f[j - 2]
, ..., f[j - c]
转移而来。m
,组数)。m <= total_length < k
的方案数。O(k)
。ans
。sum(f[m..k-1])
。ans - sum(f[m..k-1])
。O(n)
,其中 n
是 word
的长度。O(m)
,其中 m
是组的数量。O(m)
。O(k)
。O(m * k)
。m <= n
且 k <= 2000
,因此动态规划部分的时间复杂度为 O(n * k)
。O(n * k)
。O(m)
,但可以优化为 O(1)
(无需显式存储所有组)。O(k)
。O(k)
。O(n * k)
。O(k)
。`
package main
import (
"fmt"
)
func possibleStringCount(word string, k int)int {
iflen(word) < k { // 无法满足要求
return0
}
const mod = 1_000_000_007
cnts := []int{}
ans := 1
cnt := 0
for i := range word {
cnt++
if i == len(word)-1 || word[i] != word[i+1] {
// 如果 cnt = 1,这组字符串必选,无需参与计算
if cnt > 1 {
if k > 0 { // 保证空间复杂度为 O(k)
cnts = append(cnts, cnt-1)
}
ans = ans * cnt % mod
}
k-- // 注意这里把 k 减小了
cnt = 0
}
}
if k <= 0 {
return ans
}
f := make([]int, k)
f[0] = 1
for _, c := range cnts {
// 原地计算 f 的前缀和
for j := 1; j < k; j++ {
f[j] = (f[j] + f[j-1]) % mod
}
// 计算子数组和
for j := k - 1; j > c; j-- {
f[j] -= f[j-c-1]
}
}
for _, x := range f {
ans -= x
}
return (ans%mod + mod) % mod // 保证结果非负
}
func main() {
word := "aabbccdd"
k := 7
result := possibleStringCount(word, k)
fmt.Println(result)
}
`
fn possible_string_count(word: &str, k: usize) ->i32 {
letmod_val = 1_000_000_007i64;
letn = word.len();
if n < k {
return0;
}
letbytes = word.as_bytes();
letmut cnts = vec![];
letmut ans = 1i64;
letmut cnt = 0usize;
letmut kk = k asi32;
foriin0..n {
cnt += 1;
if i == n - 1 || bytes[i] != bytes[i + 1] {
if cnt > 1 {
if kk > 0 {
cnts.push(cnt - 1);
}
ans = ans * (cnt asi64) % mod_val;
}
kk -= 1;
cnt = 0;
}
}
if kk <= 0 {
return (ans % mod_val) asi32;
}
letk = kk asusize;
letmut f = vec![0i64; k];
f[0] = 1;
for &c in &cnts {
// 计算前缀和
forjin1..k {
f[j] = (f[j] + f[j - 1]) % mod_val;
}
// 计算子数组和
forjin (c + 1..k).rev() {
f[j] = (f[j] - f[j - c - 1] + mod_val) % mod_val;
}
}
for &x in &f {
ans = (ans - x + mod_val) % mod_val;
}
ans asi32
}
fnmain() {
letword = "aabbccdd";
letk = 7;
letresult = possible_string_count(word, k);
println!("{}", result);
}