基于字母配额与词表的合法句子生成器:Python 实现多词组合式字谜求解

3次阅读

基于字母配额与词表的合法句子生成器:Python 实现多词组合式字谜求解

本文介绍如何根据给定字母使用配额(如 n:1, e:1, o:2 等)和外部词表(wordlist.txt),穷举所有由词表中单词构成、且**恰好耗尽全部字母配额**的有效句子,支持同构异形词(anagram)去重与组合优化。

在自然语言处理与算法谜题实践中,常需解决一类“约束型句子构造”问题:给定一组字母及其最大可用次数(即“配额”),以及一个合法词汇集合(如 wordlist.txt),目标是生成所有可能的、由词表内单词拼接而成的句子,要求每个字母的总使用频次严格等于其配额,且不可超额或剩余。例如,配额 n:1, e:1, w:1, b:1, o:2, k:1 对应字母串 “newbook”(长度 7),合法解包括 “new book”、”bow neko” 等——它们均由词表中存在、且字母频次加总后完全匹配原始配额的单词组成。

核心思路是将问题转化为多词级字谜(multi-word anagram)求解

  • 每个单词按字母排序后形成唯一 anagram_id(如 “book” → “bkoo”,”koob” → “bkoo”),实现异形词归一化;
  • 输入配额等价于一个目标字母串(如 “bkeoown” → 排序得 “bkeoown” → “beknoow”),记为 target_sorted;
  • 枚举词表中所有能作为子组件的单词(即其 anagram_id 是 target_sorted 的子多重集),再通过组合与笛卡尔积,生成所有单词序列,使其 anagram_id 拼接后仍与 target_sorted 完全一致。

以下是完整、可运行的 python 实现(已优化逻辑并增强鲁棒性):

from itertools import combinations, product from collections import defaultdict, Counter  def filter_origin(s):     """清理输入:移除空格、换行、标点,转小写,仅保留字母"""     return ''.join(filter(str.isalpha, s.lower()))  def generate_sentences_from_quota(quota_dict, wordlist_path='wordlist.txt'):     """     根据字母配额字典和词表路径生成所有合法句子      Args:         quota_dict (dict): 如 {'n': 1, 'e': 1, 'w': 1, 'b': 1, 'o': 2, 'k': 1}         wordlist_path (str): 词表文件路径,每行一个单词      Returns:         list[str]: 所有满足条件的句子(空格分隔,顺序不同视为不同解)     """     # 构建目标字母串(按配额展开)     target_chars = []     for char, count in quota_dict.items():         if count > 0 and char.isalpha():             target_chars.extend([char.lower()] * count)     target_sorted = ''.join(sorted(target_chars))     target_len = len(target_sorted)      # 读取并预处理词表     with open(wordlist_path, 'r', encoding='utf-8') as f:         words = [line.strip() for line in f if line.strip()]      # 构建 anagram_id → 单词列表 映射     anagram_map = defaultdict(list)     for word in words:         clean_word = filter_origin(word)         if not clean_word or len(clean_word) > target_len:             continue         aid = ''.join(sorted(clean_word))         anagram_map[aid].append(word)      # 筛选所有「可行组件」:anagram_id 必须是 target_sorted 的子多重集     valid_aids = []     target_counter = Counter(target_sorted)     for aid in anagram_map:         aid_counter = Counter(aid)         # 检查 aid 是否可被 target_counter 容纳(每个字母频次 ≤ target)         if all(target_counter[c] >= cnt for c, cnt in aid_counter.items()):             valid_aids.append(aid)      # 枚举所有非空子集组合(按组件数量分层)     valid_sentences = []     # 使用动态规划或回溯更优,此处用组合枚举(适合中小规模)     for r in range(1, min(len(valid_aids) + 1, target_len + 1)):         for combo in combinations(valid_aids, r):             # 拼接当前组合的 anagram_id 并排序             combined_aid = ''.join(combo)             if len(combined_aid) != target_len:                 continue             if ''.join(sorted(combined_aid)) == target_sorted:                 # 笛卡尔积:每个 aid 对应多个实际单词                 word_lists = [anagram_map[aid] for aid in combo]                 for sentence_words in product(*word_lists):                     valid_sentences.append(' '.join(sentence_words))      return list(set(valid_sentences))  # 去重(避免相同句子因多路径生成)  # 示例调用 if __name__ == "__main__":     quota = {'n': 1, 'e': 1, 'w': 1, 'b': 1, 'o': 2, 'k': 1}     sentences = generate_sentences_from_quota(quota, 'wordlist.txt')     print("合法句子列表:")     for s in sorted(sentences):         print(f"  '{s}'")

关键特性说明

立即学习Python免费学习笔记(深入)”;

  • 精准配额匹配:严格校验组合后字母频次与输入配额完全一致(非子集,而是等价);
  • anagram 智能归一:自动识别 “book”/”koob” 等异形词,避免重复计算;
  • 高效剪枝:跳过长度超限或频次越界的候选词,显著提升性能;
  • 输出可控:返回去重后的字符串列表,支持直接用于后续 nlp 流程或人工校验。

⚠️ 注意事项

  • 该算法时间复杂度为指数级(最坏 O(2^N)),适用于配额总长 ≤ 15 字母、词表规模 ≤ 10⁴ 的场景;若需处理更大规模,建议改用回溯 + 频次计数器剪枝,或引入 A* 启发式搜索;
  • wordlist.txt 中单词需为纯字母(无空格/符号),否则 filter_origin() 会自动清洗;
  • 若允许单词复用(同一单词多次出现),需额外修改组合逻辑(当前默认每个单词至多用一次);
  • 实际部署时,建议将 anagram_map 序列化缓存,避免重复解析大型词表。

通过本方案,你不仅能生成 “new book” 和 “bow neko” 这类直观解,更能系统性挖掘所有潜在语义组合——让字母配额从约束变为创意引擎。

text=ZqhQzanResources