问题描述
某特种部队采用了一套性格密码机制来筛选执行特定任务的最佳士兵,该机制规则如下:
- 每个人的性格可以从 M 个维度来描述,每个维度分为 ABCDE 5 种类型;
- 同一维度内字母距离越近,表示该维度性格类型差异越小,也就越匹配,比如:A和B的差异为1,A和D的差异为3,所以A和B的性格类型越匹配;
- 其中 AE、BD、CE、BE 为不相容性格类型,可以认为他们的性格差异为正无穷大;
- 如果两士兵性格密码在 M 个维度下性格类型差异值总和越小,就代表这两人性格越匹配,但是如果某一维度包含不相容性格类型,则表示两人性格密码完全不匹配。
假如你是该特种部队的技术负责人,现在有一项重要的机密任务,需要在 N 个特种兵中,找到最匹配该任务的性格密码的人选,请你写一套算法帮助他们找到执行该任务的最佳人选。
问题分析
本题的核心在于计算士兵性格密码与目标任务性格密码的匹配度。每个士兵有 MM 个维度的性格描述,而性格匹配由以下两种情况决定:
- 完全不匹配的情况:
若某一维度中出现了 不相容性格类型(AE、BD、CE、BE),两人直接判定为完全不匹配。 - 差异值计算:
如果每个维度都没有出现不相容性格类型,则计算字母之间的距离差异,差异越小越匹配。
最终,我们需要从 NN 个士兵中找到与任务性格密码最匹配的士兵。
解题思路
-
定义差异值计算方法:
- 若两个字母在同一维度中为不相容类型,则返回无穷大。
- 否则返回两字母的 ASCII 差值的绝对值(表示差异程度)。
-
匹配度计算:
- 遍历每个维度,检查是否存在不相容性格类型。
- 若某一维度完全不匹配,则跳过该士兵。
- 若每个维度均匹配,累加每个维度的差异值。
-
从所有士兵中找到最优匹配:
- 记录当前最小匹配值,并跟踪对应的士兵索引。
-
返回结果:
- 输出最匹配的士兵的索引及其匹配值。
实现代码
from math import inf
# 检查是否为不相容类型
def is_incompatible(a: str, b: str) -> bool:
incompatible_pairs = {"AE", "BD", "CE", "BE"}
return f"{a}{b}" in incompatible_pairs or f"{b}{a}" in incompatible_pairs
# 计算两个字母的匹配差异值
def char_difference(a: str, b: str) -> int:
if is_incompatible(a, b):
return inf
return abs(ord(a) - ord(b))
# 找到最匹配士兵
def find_best_match(task_password: str, soldiers_passwords: list[str]) -> tuple[int, int]:
min_diff = inf
best_match_index = -1
for i, soldier_password in enumerate(soldiers_passwords):
total_diff = 0
compatible = True
for a, b in zip(task_password, soldier_password):
diff = char_difference(a, b)
if diff == inf:
compatible = False
break
total_diff += diff
if compatible and total_diff < min_diff:
min_diff = total_diff
best_match_index = i
return best_match_index, min_diff
# 示例
task = "ABCDE"
soldiers = ["BACED", "ABBAE", "EDCBA", "ABCDE"]
best_index, min_diff = find_best_match(task, soldiers)
print(f"最佳匹配士兵索引: {best_index}, 差异值: {min_diff}")
核心步骤讲解
1. 不相容性格类型检查
通过定义一个不相容类型集合 {AE, BD, CE, BE},可以在 O(1)O(1) 时间内判断两个字母是否为不相容类型。例如:
is_incompatible("A", "E") # 返回 True
is_incompatible("A", "C") # 返回 False
2. 逐字符差异值计算
如果两个字符不相容,差异值直接为正无穷;否则计算 ASCII 差值的绝对值,例如:
char_difference("A", "B") # 返回 1
char_difference("A", "E") # 返回 inf
3. 逐士兵匹配
逐一检查每个士兵与任务密码的匹配度,累加每个维度的差异值。如果某一维度不匹配,直接跳过该士兵。
4. 找到最优匹配
记录当前最小差异值及对应的士兵索引,最终返回结果。
示例和边界测试
示例 1
输入:
任务性格密码:"ABCDE"
士兵性格密码列表:["BACED", "ABBAE", "EDCBA", "ABCDE"]
输出:
最佳匹配士兵索引:3,差异值:0
解释:
第 3 个士兵与任务性格密码完全一致,差异值为 0,最佳匹配。
边界测试
- 全不相容
输入:"ABCDE",士兵:["AEAAA", "BDCCC"]
输出:-1,匹配失败。
解释:所有士兵都包含不相容类型。 - 空列表
输入:"ABCDE",士兵:[]
输出:-1,匹配失败。
解释:无士兵。 - 单维度不相容
输入:"ABCDE",士兵:["ABCBD", "EDCBA"]
输出:1,差异值:6
解释:第 0 个士兵因 BD 不相容而跳过。
复杂度分析
-
时间复杂度:
- 检查每个士兵与任务密码的匹配度:O(M)O(M),其中 MM 是维度数。
- 对 NN 个士兵进行检查:O(N×M)O(N \times M)。
-
空间复杂度:
- 常量级存储,例如不相容集合:O(1)O(1)。
总结
本题考查了字符处理和逻辑判断的能力,通过合理的函数分解,清晰地实现了性格密码匹配的算法。代码效率高,结构清晰,能够处理各种输入情况,是一个实践基础算法和边界条件处理的优秀案例。