You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:高效生成20个letter pair组成10个4-letter word的合法组合

问题描述

给定一个包含20个字母对的数组:

['BA', 'BO', 'CO', 'CR', 'DA','FA', 'FE', 'FI', 'GL', 'LL','MA', 'NE', 'OW', 'OW', 'RE','RK', 'RN', 'SK', 'ST', 'TS']

数组中的字母对可重复出现。

同时给定一个4字母单词数组:

['BALL','BANE','BARE','BARK','BARN','BASK','BAST','BATS','BOLL','BONE','BORE','BORK','BORN','BOSK','BOTS','CODA','COMA','CONE','CORE','CORK','CORN','COST','COTS','CROW','DARE','DARK','DARN','FALL','FANE','FARE','FAST','FATS','FELL','FERE','FERN','FEST','FETS','FICO','FIFE','FILL','FINE','FIRE','FIRN','FIST','FITS','GLOW','MALL','MANE','MARE','MARK','MASK','MAST','MATS','NEMA','NEST','NETS','REST','RETS','STOW']

所有单词均来自词典,且每个单词可拆分为两个合法字母对。

需要生成所有合法组合:

  • 每个组合包含10个唯一的4字母单词(均来自上述数组)
  • 每个单词由两个字母对拼接而成(如CO+RK→CORK,BA+TS→BATS)
  • 组合需将20个字母对恰好使用一次,且字母对使用次数不超过其在原数组中的出现次数

当前暴力枚举方案耗时过长(80-100小时)或内存占用过高,需要高效的实现方法。


高效实现方案

1. 预构建字母对映射表

先把所有4字母单词拆解为字母对组合,构建字典快速查询:

  • 键:单个字母对
  • 值:所有以该字母对作为前半部分的单词,以及对应的后半字母对
    示例结构:
pair_map = {
    'BA': [('BALL', 'LL'), ('BANE', 'NE'), ('BARE', 'RE'), ...],
    'CO': [('CODA', 'DA'), ('COMA', 'MA'), ('CONE', 'NE'), ...],
    # 覆盖所有字母对的映射
}

同时用计数器(如collections.Counter)统计原字母对数组的使用次数,方便后续快速判断剩余可用次数。

2. 回溯剪枝算法

采用深度优先搜索(DFS)+剪枝的方式遍历可能的组合,核心逻辑:

  • 每次选择未使用过的单词,检查其两个字母对是否还有剩余可用次数
  • 选择后,扣除对应字母对的使用次数,将单词加入当前组合
  • 当组合包含10个单词时,记录为合法组合
  • 回溯时,恢复字母对的使用次数,移除当前单词

关键剪枝策略:

  • 优先用稀有字母对:先处理原数组中出现次数少的字母对(比如GL仅出现1次),快速排除无效路径,减少分支数
  • 跳过重复单词:用集合记录已选单词,避免重复选择
  • 提前终止无效路径:若剩余字母对数量为奇数,或剩余字母对无法配对成单词,直接终止该分支

3. 内存与性能优化

  • 用迭代式DFS代替递归,避免栈溢出,更易控制内存
  • 用位标记或哈希集合快速判断单词是否已使用
  • 预筛选单词:提前排除包含原数组中没有的字母对的单词(题目已保证单词合法,此步骤可省略)

示例代码框架(Python)

from collections import Counter

# 输入数据
letter_pairs = ['BA', 'BO', 'CO', 'CR', 'DA','FA', 'FE', 'FI', 'GL', 'LL','MA', 'NE', 'OW', 'OW', 'RE','RK', 'RN', 'SK', 'ST', 'TS']
word_list = ['BALL','BANE','BARE','BARK','BARN','BASK','BAST','BATS','BOLL','BONE','BORE','BORK','BORN','BOSK','BOTS','CODA','COMA','CONE','CORE','CORK','CORN','COST','COTS','CROW','DARE','DARK','DARN','FALL','FANE','FARE','FAST','FATS','FELL','FERE','FERN','FEST','FETS','FICO','FIFE','FILL','FINE','FIRE','FIRN','FIST','FITS','GLOW','MALL','MANE','MARE','MARK','MASK','MAST','MATS','NEMA','NEST','NETS','REST','RETS','STOW']

# 构建字母对到单词+后半对的映射
pair_map = {}
for word in word_list:
    first_pair = word[:2]
    second_pair = word[2:]
    if first_pair not in pair_map:
        pair_map[first_pair] = []
    pair_map[first_pair].append( (word, second_pair) )

# 统计字母对初始计数
pair_counter = Counter(letter_pairs)
total_words_needed = 10
valid_combinations = []

def dfs(current_combination, current_counter):
    if len(current_combination) == total_words_needed:
        valid_combinations.append(current_combination.copy())
        return
    
    # 剪枝:剩余字母对数量必须是偶数,否则无法组成完整单词
    remaining_pairs = sum(current_counter.values())
    if remaining_pairs % 2 != 0:
        return
    
    # 优先遍历稀有字母对对应的单词,减少分支
    available_pairs = [p for p in current_counter if current_counter[p] > 0]
    available_pairs.sort(key=lambda x: current_counter[x])
    
    used_words = set(current_combination)
    for pair in available_pairs:
        if pair not in pair_map:
            continue  # 没有以该字母对开头的单词,跳过
        for word, second_pair in pair_map[pair]:
            if word in used_words:
                continue
            # 检查第二个字母对是否可用
            if current_counter.get(second_pair, 0) == 0:
                continue
            
            # 选择该单词,更新计数
            current_counter[pair] -= 1
            if current_counter[pair] == 0:
                del current_counter[pair]
            current_counter[second_pair] -= 1
            if current_counter[second_pair] == 0:
                del current_counter[second_pair]
            current_combination.append(word)
            
            # 递归搜索
            dfs(current_combination, current_counter)
            
            # 回溯,恢复计数
            current_combination.pop()
            current_counter[pair] = current_counter.get(pair, 0) + 1
            current_counter[second_pair] = current_counter.get(second_pair, 0) + 1

# 启动DFS
dfs([], pair_counter.copy())

# 输出结果
print(f"找到{len(valid_combinations)}个合法组合")
for combo in valid_combinations:
    print(combo)

额外优化建议

  • 预计算单词的字母对使用情况,避免每次拆解单词
  • 对单词按前/后字母对分组,减少遍历次数
  • 使用多线程/多进程并行搜索不同初始分支(注意线程安全,每个线程使用独立的计数器和组合)

内容的提问来源于stack exchange,提问作者thefuzzy0ne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:37:14