求助:实现Shortest Superstring对应的最少数组元素拼接计数
给最短超串算法新增「最小拼接元素数量」功能的实现方案
嘿,这个需求很清晰!咱们可以在现有的最短超串计算逻辑上,通过追踪状态对应的元素使用数量,轻松实现这个新增功能。我假设你当前用的是**动态规划(DP)**的经典解法(这是最短超串问题的最优解思路),下面一步步给你拆解实现步骤:
核心思路
最短超串的DP解法通常会用dp[mask][i]记录「使用mask标记的字符串集合,且最后一个拼接的是第i个字符串」时的最短超串长度。我们只需要新增一个对应的count[mask][i]数组,用来记录该状态下使用的最小元素数量,然后在状态转移时同步更新这个值即可。
具体实现步骤
1. 预计算字符串重叠矩阵
首先还是先算出任意两个字符串strs[i]和strs[j]之间的最大重叠长度(即strs[i]的后缀和strs[j]的前缀的最长匹配长度),这个是原算法就需要的:
def get_overlap(a, b): max_len = min(len(a), len(b)) for l in range(max_len, 0, -1): if a.endswith(b[:l]): return l return 0 strs = ["abc", "bcd", "cde"] n = len(strs) overlap_mat = [[0]*n for _ in range(n)] for i in range(n): for j in range(n): if i != j: overlap_mat[i][j] = get_overlap(strs[i], strs[j])
2. 初始化DP和计数数组
dp[mask][i]:初始时,每个单独的字符串对应mask只有第i位为1,长度就是字符串本身的长度count[mask][i]:初始时,每个单独的字符串只使用了1个元素
full_mask = (1 << n) - 1 INF = float('inf') # 初始化DP数组 dp = [[INF]*n for _ in range(1 << n)] # 初始化计数数组 count = [[INF]*n for _ in range(1 << n)] for i in range(n): mask = 1 << i dp[mask][i] = len(strs[i]) count[mask][i] = 1
3. 状态转移时同步更新计数
遍历所有可能的mask和每个可能的结尾字符串i,尝试拼接新的字符串j,同步更新最短长度和对应的最小元素数量:
for mask in range(1 << n): for i in range(n): if not (mask & (1 << i)): continue # 当前状态是mask,结尾是i,尝试拼接j for j in range(n): if mask & (1 << j): continue new_mask = mask | (1 << j) new_len = dp[mask][i] + len(strs[j]) - overlap_mat[i][j] # 如果新长度更短,直接更新长度和计数 if new_len < dp[new_mask][j]: dp[new_mask][j] = new_len count[new_mask][j] = count[mask][i] + 1 # 如果长度相同,选择元素数量更少的情况 elif new_len == dp[new_mask][j]: if count[mask][i] + 1 < count[new_mask][j]: count[new_mask][j] = count[mask][i] + 1
4. 获取最终结果
遍历所有全mask状态下的结尾字符串,找到最短超串对应的最小元素数量:
min_super_len = INF min_element_count = INF for i in range(n): if dp[full_mask][i] < min_super_len: min_super_len = dp[full_mask][i] min_element_count = count[full_mask][i] elif dp[full_mask][i] == min_super_len: if count[full_mask][i] < min_element_count: min_element_count = count[full_mask][i] print(f"最短超串长度: {min_super_len}") print(f"所需最小拼接元素数量: {min_element_count}")
示例验证
比如用数组["abc", "bcd", "cde"]测试:
- 最短超串是
"abcde"(长度5) - 可以通过
"abc"+"cde"(重叠1个字符)实现,仅用2个元素;而如果用三个元素拼接,长度虽相同但元素数量更多。所以最终输出的最小元素数量是2,符合预期。
非DP解法的适配(比如贪心)
如果你当前用的是贪心算法(每次选重叠最大的两个字符串合并),那你只需要在每次合并时记录合并的次数:初始元素数量是n,每合并一次数量减1,直到无法再合并出更短的串为止。不过要注意,贪心算法不一定能得到全局最优的最短超串,所以对应的最小元素数量也可能不是全局最优的。
内容的提问来源于stack exchange,提问作者Ross Headington
相关产品推荐
相关产品推荐

