刷题实践 | 豆包MarsCode AI刷题

104 阅读10分钟

从报名青训营到现在,使用豆包MarsCodeAI刷题已经将近一个月了,AI刷题的优势与便利想必大家都多多少少体会到了。这里我以做109题《小M的光明之魂速通挑战》的过程为例,展示我是如何用豆包MarsCode来帮助我刷题的,以及我认为豆包MarsCode的优势。

问题描述

小M最近参加了一个名为《光明之魂》的速通比赛。在比赛中,玩家拥有N把武器以及M个Boss需要击败。规则如下:

  1. 每个Boss有一个唯一的类型编号,用一个正整数表示。
  2. 每把武器能够击败两种类型的Boss,但每把武器只能使用一次。
  3. 玩家必须按照给定的顺序逐个击杀Boss,不能跳过Boss顺序。

小M想知道,在不违反规则的前提下,他最多能够击败多少个Boss。

输入变量说明:

  • n 表示拥有的武器数量。
  • m 表示需要击败的Boss数量。
  • boss 是一个长度为m的列表,表示玩家必须按照顺序击杀的Boss的类型。
  • array 是一个长度为n的二维列表,每个元素为 [x, y],表示对应的武器可以击败类型为 x 和 y 的Boss。

假设我现在刚开始刷题没多久,读题读了几分钟暂时还不知道要从哪里下手,这时我就可以打开侧边栏的AI,点击“需要一点思路提示”

好的,让我们来分析一下这个问题,并提供一些思路提示。

### 问题理解

  **目标**:在不违反规则的前提下,尽可能多地击败Boss。

  **规则**    -   每个Boss有一个唯一的类型编号。
    -   每把武器可以击败两种类型的Boss,但每把武器只能使用一次。
    -   必须按照给定的顺序逐个击杀Boss,不能跳过Boss顺序。

### 数据结构选择

-   **武器数组**`array`,每个元素是一个包含两个整数的列表,表示该武器可以击败的两种类型的Boss。
-   **Boss列表**`boss`,表示需要按照顺序击杀的Boss的类型。
-   **武器使用状态**`used`,一个布尔数组,记录每把武器是否已被使用。

### 算法步骤

  **初始化**    -   创建一个布尔数组 `used`,用于记录每把武器是否已被使用。
    -   初始化一个计数器 `defeated_count`,用于记录击败的Boss数量。

  **遍历Boss列表**    -   对于每个Boss,检查是否有未使用的武器可以击败它。
    -   如果没有武器可以击败当前Boss,则退出循环。

  **选择武器**    -   对于每个能击败当前Boss的武器,检查它是否能击败后续的Boss。
    -   优先选择不能击败后续Boss的武器。
    -   如果所有武器都能击败后续Boss,选择能击败最远后续Boss的武器。

  **更新状态**    -   如果找到了合适的武器,则将其标记为已使用,并增加击败的Boss数量。

### 关键点

-   **武器选择策略**:优先选择不能击败后续Boss的武器,这样可以最大化后续Boss的击败数量。
-   **提前退出**:如果没有武器可以击败当前Boss,则提前退出循环,避免不必要的计算。

通过以上思路,你可以逐步实现代码,确保在不违反规则的前提下,尽可能多地击败Boss。希望这些提示对你有所帮助!

以上是豆包AI给的思路提示,现在我们也大致有解题的思路了:先对武器建立一个used数组,没用过的武器初始化为0,用过的武器设为1,然后对boss列表进行遍历,每次遇到新的boss只在used为0的武器里寻找能击败当前boss的武器,直到没用过的武器都不能击败当前的boss为止。

虽然已经有了思路,但是假设我现在是一个新手,即使有了思路要将思路转化为代码也还是要消耗不少的时间,这时候我们可以在侧边栏的AI点击“给我一些代码提示”,让AI给我们初步实现一些代码

def max_bosses_defeated(n, m, boss, array):
    # 初始化武器匹配字典
    weapon_map = {}
    for i in range(1, n + 1):
        weapon_map[i] = []
    
    # 填充武器匹配字典
    for i in range(n):
        x, y = array[i]
        weapon_map[x].append(i)
        weapon_map[y].append(i)
    
    # 初始化武器使用状态
    used_weapons = [False] * n
    
    # 初始化击杀Boss数量
    defeated_count = 0
    
    # 遍历每个Boss
    for boss_type in boss:
        # 查找是否有未使用的武器可以击败当前Boss
        for weapon_index in weapon_map[boss_type]:
            if not used_weapons[weapon_index]:
                # 使用该武器
                used_weapons[weapon_index] = True
                defeated_count += 1
                break
    
    return defeated_count

# 测试样例
n = 3
m = 5
boss = [1, 2, 3, 4, 5]
array = [[1, 2], [3, 2], [4, 5]]
print(max_bosses_defeated(n, m, boss, array))  # 输出: 2
### 关键步骤解释

1.  **初始化武器匹配字典**    -   创建一个字典`weapon_map`,键为Boss类型,值为可以击败该类型Boss的武器列表。

1.  **填充武器匹配字典**    -   遍历每把武器,将其可以击败的Boss类型添加到对应的列表中。

1.  **初始化武器使用状态**    -   创建一个列表`used_weapons`,记录每把武器是否已经被使用。

1.  **遍历每个Boss**    -   对于每个Boss,检查是否有未使用的武器可以击败它。
    -   如果有,使用该武器并标记为已使用,增加击杀Boss数量。

1.  **返回结果**    -   返回成功击杀的Boss数量。

### 注意

-   代码中使用了`break`语句来确保每把武器只使用一次。
-   你可以根据需要调整代码的细节,例如处理边界情况或优化性能。

希望这些代码提示对你有所帮助!如果你有任何具体的问题或需要进一步的解释,请告诉我。

以上是豆包AI给出的代码和对代码的解释,虽然不是直接解决了所有问题但是也给了我们一个大致的代码框架,接下来我们只要在给出的代码上进行进一步的改进就可以了,这比自己从0开始敲所有代码容易不少。

我们先不检查给出的代码是怎么样的,先在编辑区里运行一下,结果报错了

帮我修复一下 [ERROR] Traceback (most recent call last): File "/cloudide/workspace/daimalianxi/topic/v2/73/python/main.py", line 36, in <module> print(max_bosses_defeated(n, m, boss, array)) # 输出: 2 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/cloudide/workspace/daimalianxi/topic/v2/73/python/main.py", line 10, in max_bosses_defeated weapon_map[x].append(i) ~~~~~~~~~~^^^ KeyError: 4

我们点击AI fix让AI修复报错

好的,错误信息显示在尝试访问`weapon_map[4]`时出现了`KeyError`,这意味着字典`weapon_map`中没有键为`4`的条目。我们需要确保所有可能的Boss类型都在`weapon_map`中初始化。

### 修复步骤

1.  **初始化所有可能的Boss类型**    -   在初始化`weapon_map`时,确保所有可能的Boss类型都被包含在内。
def max_bosses_defeated(n, m, boss, array):
    # 初始化武器匹配字典
    weapon_map = {}
    for i in range(1, n + 1):
        weapon_map[i] = []
    
    # 填充武器匹配字典
    for i in range(n):
        x, y = array[i]
        weapon_map[x].append(i)
        weapon_map[y].append(i)
    
    # 初始化武器使用状态
    used_weapons = [False] * n
    
    # 初始化击杀Boss数量
    defeated_count = 0
    
    # 遍历每个Boss
    for boss_type in boss:
        # 查找是否有未使用的武器可以击败当前Boss
        for weapon_index in weapon_map[boss_type]:
            if not used_weapons[weapon_index]:
                # 使用该武器
                used_weapons[weapon_index] = True
                defeated_count += 1
                break
    
    return defeated_count

# 测试样例
n = 3
m = 5
boss = [1, 2, 3, 4, 5]
array = [[1, 2], [3, 2], [4, 5]]
print(max_bosses_defeated(n, m, boss, array))  # 输出: 2

可以看到报错原因是weapon_map初始化时本来是想建立所有boss对应的武器的字典但不知道为什么range只到n+1,这里修改为把所有boss都包含到字典里了,重新运行。

输出结果为3,但按样例来说应该输出2才对。我们可以让AI模拟运行样例,由AI返回的结果可以看出击败boss1,2以后boss三已经没有武器可以击败了,但却没有结束,而是继续运行下去,用剩下的武器3击败了boss4并计数了,因此我们应该增加一段在没有武器能击败当前boss的时候结束循环的代码。

因为一直贴AI的回复和修改的代码有些耗时间占位置,以下我就不再贴上AI的回复了。

增加了提前结束的代码后三个样例都通过了。这时我们自信满满的提交,然后返回结果是:第24个样例未通过

1.png

让AI分析后知道,这是因为能击败一个boss的武器不止一把,其中有的武器能击败的另一个boss排序更靠后一些,有的武器能击败的另一个boss更靠前一些,这时候就要选择能击败的另一个boss排序靠后的武器,否则就会提前结束,我们让AI增加记录能击败当前boss的武器能击败的另一个boss的顺序,最后选择能击败的另一个boss排序靠后的武器。

最终结果:

def solution(n, m, boss, array):
    # 初始化武器匹配字典
    weapon_map = {}
    for i in range(1, max(boss) + 1):  # 初始化所有可能的Boss类型
        weapon_map[i] = []
    
    # 填充武器匹配字典
    for i in range(n):
        x, y = array[i]
        weapon_map[x].append(i)
        weapon_map[y].append(i)
    
    # 初始化武器使用状态
    used_weapons = [False] * n
    
    # 初始化击杀Boss数量
    defeated_count = 0
    
    # 遍历每个Boss
    for i in range(m):
        boss_type = boss[i]
        # 查找是否有未使用的武器可以击败当前Boss
        possible_weapons = []
        for weapon_index in weapon_map[boss_type]:
            if not used_weapons[weapon_index]:
                possible_weapons.append(weapon_index)
        
        if not possible_weapons:
            break  # 没有武器能击败当前Boss,结束循环
        
        # 选择能击败的另一个Boss排序靠后的武器
        best_weapon = -1
        best_future_boss_idx = -1
        
        for w in possible_weapons:
            future_boss_idx = m  # 初始化为最大值
            for k in range(i + 1, m):
                if boss[k] in array[w]:
                    future_boss_idx = k
                    break
            
            if future_boss_idx > best_future_boss_idx:
                best_weapon = w
                best_future_boss_idx = future_boss_idx
        
        # 使用最佳武器
        if best_weapon != -1:
            used_weapons[best_weapon] = True
            defeated_count += 1
    
    return defeated_count


# 测试案例
n = 22
m = 25
boss = [11,8,7,4,5,17,16,13,2,20,18,6,10,14,12,22,21,19,1,15,3,9,24,23,25]
array = [[6,22],[18,20],[7,5],[12,5],[17,18],[21,17],[8,4],[18,14],[10,22],[18,2],[24,1],[17,23],[14,7],[15,6],[25,15],[12,6],[11,15],[11,22],[12,1],[2,20],[13,15],[23,8]]
print(solution(n, m, boss, array))  # 期望输出:12

image.png

总结: 豆包MarsCode AI刷题降低了我们做题的难度,让我们更容易理解题目,可以帮我们写一部分代码,再根据我们的反馈修改代码,几乎不用自己敲一个代码,实现“自然语言编程”。缺点是豆包AI不能一步到位解决问题,而需要我们指出代码中的不足,并给出修改的建议才能修改,而很难做到自己分析错误并进行合理的修改。由此看出虽然现在AI功能已经挺强大了,但AI也仍然有许多不足,人不会完全被AI替代。