2025-05-22:找到初始输入字符串Ⅱ。用go语言,Alice 在键盘上输入一个字符串,但由于输入时可能按键时间过长,导致某
        【摘要】 2025-05-22:找到初始输入字符串Ⅱ。用go语言,Alice 在键盘上输入一个字符串,但由于输入时可能按键时间过长,导致某些字符被重复输入多次。给定一个字符串 word,表示最终显示在屏幕上的内容,同时给定一个正整数 k,表示 Alice 最初打算输入的字符串长度至少为 k。请你计算,满足这种情况的所有可能的原字符串方案数,并将结果对 1000000007 取模后返回。1 <= wor...
    
    
    
    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”]。
- 对于每组,至少保留一个字符,因此每组的选择是保留 1 到 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]转移而来。
 
- 对于每个 
- 由于每组至少选 1 个字符,因此实际的总长度至少是组的数量(即 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)。
Go完整代码如下:
`
package main
import (
	"fmt"
)
func possibleStringCount(word string, k int) int {
	if len(word) < k { // 无法满足要求
		return 0
	}
	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)
}

Rust完整代码如下:
`
fn possible_string_count(word: &str, k: usize) -> i32 {
    let mod_val = 1_000_000_007i64;
    let n = word.len();
    if n < k {
        return 0;
    }
    let bytes = word.as_bytes();
    let mut cnts = vec![];
    let mut ans = 1i64;
    let mut cnt = 0usize;
    let mut kk = k as i32;
    for i in 0..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 as i64) % mod_val;
            }
            kk -= 1;
            cnt = 0;
        }
    }
    if kk <= 0 {
        return (ans % mod_val) as i32;
    }
    let k = kk as usize;
    let mut f = vec![0i64; k];
    f[0] = 1;
    for &c in &cnts {
        // 计算前缀和
        for j in 1..k {
            f[j] = (f[j] + f[j - 1]) % mod_val;
        }
        // 计算子数组和
        for j in (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 as i32
}
fn main() {
    let word = "aabbccdd";
    let k = 7;
    let result = possible_string_count(word, k);
    println!("{}", result);
}

            【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
                cloudbbs@huaweicloud.com
                
            
        
        
        
        
        - 点赞
- 收藏
- 关注作者
 
             
           
评论(0)