
本教程详解如何用python准确计算一个字符串的所有**不同排列**在另一字符串中作为子串出现的次数,重点解决因重复字符导致的排列重复计数问题。
在处理字符串排列匹配问题时,一个常见误区是直接使用 itertools.permutations() 生成所有排列后转为列表——这会导致重复字符引发的冗余排列被重复计入。例如,输入 N = "aab" 时,permutations("aab") 实际生成 6 个元组(因为 len("aab")! = 6),但其中仅 {"aab", "aba", "baa"} 是语义上不同的字符串(共 3 个)。原始代码将全部 6 个排列逐一检查,且未去重,导致同一子串(如 "aa" 的某次匹配)被多次误判,最终输出 4 而非预期的 2。
根本原因在于:permutations() 作用于索引而非字符值,因此对 "aab"(字符索引为 a₀, a₁, b₂)会区分 a₀a₁b₂ 和 a₁a₀b₂,尽管拼接结果均为 "aab"。要获得语义唯一的排列集合,必须对拼接后的字符串去重,而非对元组去重(后者无效,因元组本身互异)。
✅ 正确做法是:先用 set() 对所有拼接后的排列字符串去重,再逐个检查是否为 H 的子串。优化后的核心代码如下:
from itertools import permutations
N = input().strip() # 不需 str(input()),input() 默认返回字符串
H = input().strip()
# 生成所有排列 → 拼接为字符串 → 去重 → 转为集合
distinct_perms = set("".join(p) for p in permutations(N))
# 统计在 H 中出现的 distinct 排列数量
count = sum(1 for perm_str in distinct_perms if perm_str in H)
print(count)⚠️ 注意事项:
- 避免变量名覆盖内置类型:原代码中 str = "".join(...) 会覆盖内置 str 类型,可能导致后续 str() 调用失败,应改用 s, perm_str, substring 等清晰变量名;
- 时间复杂度警示:该解法适用于 len(N) ≤ 8 的小规模场景(8! = 40320)。若 N 更长,需改用滑动窗口 + 字符频次统计(如 Counter)的线性算法,避免生成全排列;
- 输入健壮性:建议添加 strip() 清除首尾空白符,防止意外换行符干扰匹配。
综上,关键思维转变是:从“生成所有排列→检查”转向“生成所有不同排列→检查”。利用 set 对字符串结果去重,既简洁又准确,是解决此类含重复字符排列问题的标准实践。










