青训营X豆包MarsCode 技术训练营 刷题 小E的怪物挑战 | 豆包MarsCode AI 刷题

45 阅读3分钟

问题理解

本题的核心在于模拟小E在游戏中击败怪物的过程,并计算她最多能击败多少怪物。每个怪物都有特定的血量和攻击力,小E在击败怪物后会获得该怪物的属性值。为了保持战斗节奏,要求击败的怪物序列中,后一个怪物的血量和攻击力都必须严格大于前一个怪物。

数据结构选择

  1. 动态规划(DP)

    • 使用动态规划来解决最长递增子序列(LIS)问题。
    • dp[i] 表示考虑前 i 个怪物,且需要击败第 i 个怪物,此时的最大击败数量。
  2. 数组

    • 使用两个数组 ha 分别存储怪物的血量和攻击力。
    • 使用一个数组 dp 来存储每个怪物对应的击败数量。

算法步骤

  1. 初始化

    • 初始化一个 dp 数组,长度为 n,初始值为 0
    • 初始化一个变量 ans 用于记录最大击败数量,初始值为 0
  2. 遍历怪物

    • 对于每个怪物 i,检查其血量 h[i] 和攻击力 a[i] 是否小于小E的当前属性 HA
    • 如果小E无法击败当前怪物(即 h[i] >= Ha[i] >= A),则跳过该怪物。
  3. 动态规划更新

    • 如果小E可以击败当前怪物,则将 dp[i] 初始化为 1
    • 对于每个之前的怪物 jj < i),如果 h[i] > h[j]a[i] > a[j],则更新 dp[i]dp[j] + 1 和当前 dp[i] 的最大值。
  4. 更新最大值

    • 每次更新 dp[i] 后,更新 ansdp[i] 和当前 ans 的最大值。
  5. 返回结果

    • 最终返回 ans,即小E最多能击败的怪物数量。

复杂度分析

  • 时间复杂度O(n^2),其中 n 是怪物的数量。因为需要两层循环来更新 dp 数组。
  • 空间复杂度O(n),用于存储 dp 数组。

优化思路

  1. 二分查找优化

    • 可以使用二分查找来优化最长递增子序列的查找过程,将时间复杂度降低到 O(n log n)
    • 维护一个数组 tailstails[i] 表示长度为 i+1 的递增子序列的最后一个元素的最小值。
  2. 状态压缩

    • 如果怪物数量非常大,可以考虑使用状态压缩来减少空间复杂度。
public class Main {
    public static int solution(int n, int H, int A, int[] h, int[] a) {
        // write code here
        // 动态规划,最长递增子序列
        // dp[i] 表示考虑前 i 个怪物,且需要击败第 i 个怪物,此时的最大击败数量
        int ans = 0;
        int[] dp = new int[n];
        for (int i = 0; i < n; i++) {
            // 打不过当前怪物,选择跳过
            if (h[i] >= H || a[i] >= A) {
                continue;
            }
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
                if (h[i] > h[j] && a[i] > a[j]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            ans = Math.max(ans, dp[i]);
        }
        return ans;
    }
    

    public static void main(String[] args) {
        System.out.println(solution(3, 4, 5, new int[]{1, 2, 3}, new int[]{3, 2, 1}) == 1);
        System.out.println(solution(5, 10, 10, new int[]{6, 9, 12, 4, 7}, new int[]{8, 9, 10, 2, 5}) == 2);
        System.out.println(solution(4, 20, 25, new int[]{10, 15, 18, 22}, new int[]{12, 18, 20, 26}) == 3);
    }
}

总结

本题通过动态规划的思想,结合最长递增子序列的特性,有效地解决了小E在游戏中击败怪物的问题。通过合理的初始化和状态转移,可以在 O(n^2) 的时间复杂度内得到结果。如果需要进一步优化,可以考虑使用二分查找来降低时间复杂度。整体思路清晰,逻辑严谨,适合用于理解和练习动态规划的基本思想和应用。