题目描述
解题思路
这道题主要思想是贪心算法,即通过一系列局部最优达到全局最优。在这道题当中,我们局部最优方面选择当前差异值最小的字符串作为最佳匹配。
具体思路:
- 定义不相容性格列表
nocmp,这里要注意,判断字符串的时候存在先后顺序,例如AD和DA是两个不同的性格组合,在定义nocmp时,要注意包括所有情况; - 定义一个子函数
cal_dif()来计算target和列表中单个对象的差异值:- 遍历两个字符串内相同索引字母,使用字符串拼接判断是否是性格不相容;
- 若相容,累加计算差异值(两字母ord()差值的绝对值);
- 若不相容,直接赋值无穷大,后面选择时直接跳过不选择;
- 考虑到提供的人选列表会有重复的字符串,对于差异值最小字符串,如果列表中有多个相同元素存在的话,结果返回值肯定也要返回多个对象,因此,在处理人选列表之前,我们需要构造一个字典来记录每个人选对应的字符串出现的次数,处理流程很简单,一个循环直接搞定;
- 提取完输入列表的信息后,我们直接调用
cal_dif()函数计算每个元素的差异值,也是使用字典用键值对的方式存储,也是一个循环搞定; - 获得差异值的字典后,我们按照值升序排列,方便我们后续寻找最小差异值及其所属成员;
- 因为最佳人选不一定只有一个,也可能没有,因此直接用一个列表来保存;
- 初始化
min_dif为无穷大,遍历差异值字典:- 如果值为无穷大,表示性格不合,直接跳过;
- 如果值小于
min_dif,最佳人选列表加入对应的键并更新min_dif(因为我们之前已经升序排列了差异值字典,所以不会出现WA); - 由于已经排序,后面的值一定会大于
min_dif,所以直接break就行了,也正好提高效率;
- 最后处理最佳人选列表,结合最开始处理的字符数返回结果;
完整代码
完整解题代码如下:
def solution(m, n, target, array):
nocmp = ['AE', 'BD', 'CE', 'BE', "EA", "DB", "EC", "EB"]
def cal_dif(str1, str2):
difsum = 0
for i in range(m):
if str1[i] + str2[i] not in nocmp:
difsum += abs(ord(str1[i]) - ord(str2[i]))
else:
return float('inf')
return difsum
# 统计每个字符出现的次数
char_count = {}
for char in array:
if char in char_count:
char_count[char] += 1
else:
char_count[char] = 1
choices = {}
for a in array:
res = cal_dif(target, a)
choices[a] = res # 直接使用字符本身作为键
# 按照值升序排列 choices
sorted_choices = sorted(choices.items(), key=lambda item: item[1])
best_choice = []
min_dif = float('inf')
# 遍历排序后的 choices,找到所有最小值的键
for key, value in sorted_choices:
if value == float('inf'):
continue
if value <= min_dif:
best_choice.append(key)
min_dif = value
else:
break # 由于已经排序,后续的值一定大于 min_dif
if best_choice:
# 返回字符乘以返回次数,确保每个字符只出现一次
result = []
for char in best_choice:
result.extend([char] * char_count[char])
return " ".join(result) # 确保字符串之间加空格
return "None"
豆包MarsCode AI对题目进行解释
其实本身对贪心算法理解不是很透彻,于是使用了豆包MarsCode AI对题目及其所用思想进行了解释。我的提问是这样的:这道题怎么体现了贪心算法,豆包MarsCode AI的回复如下:
贪心算法的核心思想
贪心算法的核心思想是:在每一步选择中都采取在当前状态下最优的选择,以期望通过一系列局部最优的选择达到全局最优的解。
在这道题中的体现
局部最优选择:
- 对于每个备选特种兵的性格密码,计算其与目标性格密码的差异值。
- 选择差异值最小的字符串作为当前最优解。
全局最优解:
- 通过遍历所有备选特种兵,找到差异值最小的字符串,从而得到全局最优解。
具体步骤
初始化:
- 定义不相容性格类型的集合
nocmp。- 初始化一个变量
min_dif为无穷大,用于记录最小的差异值。- 初始化一个变量
best_choice为空字符串,用于记录最佳匹配的字符串。遍历备选特种兵:
- 对于每个备选特种兵的性格密码,计算其与目标性格密码的差异值。
- 如果差异值为无穷大(即存在不相容性格类型),则跳过该特种兵。
- 如果差异值小于当前的最小差异值
min_dif,则更新min_dif和best_choice。返回结果:
- 如果找到最佳匹配的字符串,则返回该字符串。
- 如果没有找到匹配的字符串,则返回
"None"。 …………………………关键点
贪心选择:
- 每次选择差异值最小的字符串作为当前最优解。
差异值计算:
- 使用
cal_dif函数计算两个字符串之间的差异值。不相容性格类型处理:
- 如果存在不相容性格类型,则返回无穷大,跳过该字符串。
总结
在这道题中,贪心算法的体现是通过每次选择当前差异值最小的字符串,从而期望最终得到全局最优解。通过遍历所有备选特种兵,找到差异值最小的字符串,从而得到最佳匹配。
可以看出来,豆包回复还是挺完备的,从思路到要点都总结到了,也结合案例回答了问题。