题目解析:最佳人选| 豆包MarsCode AI刷题

200 阅读5分钟

题目描述

image.png

解题思路

这道题主要思想是贪心算法,即通过一系列局部最优达到全局最优。在这道题当中,我们局部最优方面选择当前差异值最小的字符串作为最佳匹配。

具体思路:

  1. 定义不相容性格列表nocmp,这里要注意,判断字符串的时候存在先后顺序,例如ADDA是两个不同的性格组合,在定义nocmp时,要注意包括所有情况;
  2. 定义一个子函数cal_dif()来计算target和列表中单个对象的差异值:
    • 遍历两个字符串内相同索引字母,使用字符串拼接判断是否是性格不相容;
    • 若相容,累加计算差异值(两字母ord()差值的绝对值);
    • 若不相容,直接赋值无穷大,后面选择时直接跳过不选择;
  3. 考虑到提供的人选列表会有重复的字符串,对于差异值最小字符串,如果列表中有多个相同元素存在的话,结果返回值肯定也要返回多个对象,因此,在处理人选列表之前,我们需要构造一个字典来记录每个人选对应的字符串出现的次数,处理流程很简单,一个循环直接搞定;
  4. 提取完输入列表的信息后,我们直接调用cal_dif()函数计算每个元素的差异值,也是使用字典用键值对的方式存储,也是一个循环搞定;
  5. 获得差异值的字典后,我们按照值升序排列,方便我们后续寻找最小差异值及其所属成员;
  6. 因为最佳人选不一定只有一个,也可能没有,因此直接用一个列表来保存;
  7. 初始化min_dif为无穷大,遍历差异值字典:
    • 如果值为无穷大,表示性格不合,直接跳过;
    • 如果值小于min_dif,最佳人选列表加入对应的键并更新min_dif(因为我们之前已经升序排列了差异值字典,所以不会出现WA);
    • 由于已经排序,后面的值一定会大于min_dif,所以直接break就行了,也正好提高效率;
  8. 最后处理最佳人选列表,结合最开始处理的字符数返回结果;

完整代码

完整解题代码如下:

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的回复如下:

贪心算法的核心思想

贪心算法的核心思想是:在每一步选择中都采取在当前状态下最优的选择,以期望通过一系列局部最优的选择达到全局最优的解。

在这道题中的体现

  1. 局部最优选择

    • 对于每个备选特种兵的性格密码,计算其与目标性格密码的差异值。
    • 选择差异值最小的字符串作为当前最优解。
  2. 全局最优解

    • 通过遍历所有备选特种兵,找到差异值最小的字符串,从而得到全局最优解。

具体步骤

  1. 初始化

    • 定义不相容性格类型的集合 nocmp
    • 初始化一个变量 min_dif 为无穷大,用于记录最小的差异值。
    • 初始化一个变量 best_choice 为空字符串,用于记录最佳匹配的字符串。
  2. 遍历备选特种兵

    • 对于每个备选特种兵的性格密码,计算其与目标性格密码的差异值。
    • 如果差异值为无穷大(即存在不相容性格类型),则跳过该特种兵。
    • 如果差异值小于当前的最小差异值 min_dif,则更新 min_dif 和 best_choice
  3. 返回结果

    • 如果找到最佳匹配的字符串,则返回该字符串。
    • 如果没有找到匹配的字符串,则返回 "None"。 …………………………

    关键点

  4. 贪心选择

    • 每次选择差异值最小的字符串作为当前最优解。
  5. 差异值计算

    • 使用 cal_dif 函数计算两个字符串之间的差异值。
  6. 不相容性格类型处理

    • 如果存在不相容性格类型,则返回无穷大,跳过该字符串。

总结

在这道题中,贪心算法的体现是通过每次选择当前差异值最小的字符串,从而期望最终得到全局最优解。通过遍历所有备选特种兵,找到差异值最小的字符串,从而得到最佳匹配。

可以看出来,豆包回复还是挺完备的,从思路到要点都总结到了,也结合案例回答了问题。