技术求助:选择至多K个字母以构建数组中最多字符串的解法
嘿,我来帮你理清这个问题的解法思路~先再明确下问题:我们有一个字符串数组S,要从字母表里选最多K个不同的字母,用这些字母(可以重复使用)去构建数组里的字符串,目标是能构建出尽可能多的字符串,求这个最大数量。
核心思路拆解
首先要抓住一个关键点:一个字符串能被构建出来的前提是,它包含的所有不同字符,都在我们选的K个字母里。比如"ab"需要选a和b才能构建,只选a的话就不行。
所以我们可以先把每个字符串转换成它的唯一字符集合(比如"aa"的字符集合就是{'a'},"ab"就是{'a','b'}),问题就转化为:选一个大小≤K的字符集合,统计数组中有多少个字符串的字符集合是它的子集,找这个统计数的最大值。
具体解法步骤
1. 预处理字符串
遍历数组S,把每个字符串转换成对应的字符集合(用不可变的frozenset方便后续当字典键),同时统计每个字符集合出现的次数,另外收集所有在S中出现过的字符(没出现过的字母选了也没用,直接忽略)。
2. 枚举候选字符组合
我们需要枚举所有可能的、大小从1到min(K, 出现过的字符总数)的字符组合:
- 比如K=1时,就枚举每个单独的字符;K=2时,枚举所有两个不同字符的组合,以此类推。
- 对每个候选组合,计算它能覆盖的字符串总数:也就是所有字符集合是该候选组合子集的字符串的数量之和。
3. 找出最大值
遍历所有候选组合对应的覆盖数,最大的那个就是我们要的答案。
结合例子验证
拿你给的例子来说:
S = ["a","aa","ab","bb","bc","bd"],K=1
预处理后得到的字符集合及次数:
- {'a'}: 2(对应"a"和"aa")
- {'a','b'}: 1(对应"ab")
- {'b'}:1(对应"bb")
- {'b','c'}:1(对应"bc")
- {'b','d'}:1(对应"bd")
枚举单个字符的组合:
- 选{'a'}:只能覆盖字符集合是{'a'}的字符串,总数2
- 选{'b'}:只能覆盖字符集合是{'b'}的字符串,总数1
- 选{'c'}或{'d'}:没有对应的字符串,总数0
所以最大值是2,和例子结果一致。
代码示例(Python)
from itertools import combinations from collections import defaultdict def max_buildable_strings(S, K): # 预处理:统计每个字符集合的出现次数 count_map = defaultdict(int) existing_chars = set() for s in S: char_set = frozenset(s) count_map[char_set] += 1 existing_chars.update(char_set) existing_chars = list(existing_chars) max_count = 0 max_possible_k = min(K, len(existing_chars)) # 枚举所有可能的选字母数量:1到max_possible_k for k in range(1, max_possible_k + 1): # 生成所有k个字符的组合 for combo in combinations(existing_chars, k): combo_set = set(combo) current_total = 0 # 统计所有是当前组合子集的字符集合的总次数 for s_set in count_map: if s_set.issubset(combo_set): current_total += count_map[s_set] # 更新最大值 if current_total > max_count: max_count = current_total # 特殊情况:如果数组里有空字符串,空集也能覆盖它们,这里可以补充判断 # empty_str_count = S.count("") # max_count = max(max_count, empty_str_count) return max_count # 测试示例 S = ["a","aa","ab","bb","bc","bd"] K = 1 print(max_buildable_strings(S, K)) # 输出:2
优化建议
如果数组里的字符种类很多(比如接近26个),直接枚举组合可能会有点慢,这时候可以用位掩码来优化:把每个字符集合转换成二进制数(比如'a'对应第0位,'b'对应第1位),这样子集判断就变成位运算(sub_mask & combo_mask) == sub_mask,计算速度会快很多。
另外,如果K大于等于S中出现的所有字符的总数,那答案就是整个数组的长度,因为选所有字符就能覆盖所有字符串,可以直接返回,不用枚举。
备注:内容来源于stack exchange,提问作者user23374150

