刷题练习——129. 最大战力值

70 阅读6分钟

以下是题目描述

问题描述

疫情使得人们线下社交隔离,进而刺激了宅娱乐经济,令手机游戏市场份额再次创新纪录。一款手机游戏一般有很多角色,每个角色都可以设定一个战力值。为了平衡每个角色的能力,提升玩家的游戏体验,游戏策划往往会对角色的战力值通过一些规则进行限制。

在某款手游里共有 n 个角色。这些角色从 0 到 n-1 进行编号排成一列。角色的战力值按照以下的规则进行限定:

  1. 第一个角色的初始战力值为 0
  2. 每个角色的战力值是一个非负的整数
  3. 相邻角色的战力值差距不能超过 1(之间的差值可能是 0+1-1

在上边规则的基础上会再额外对其中的一些角色增加一些限制,设定最大战力值。这些限制会以若干数对的形式给出,每一个数对定义如下,limit[i] = [index, maxPower]index != 0 且 i < n - 1)表示编号为 index 的角色的最大战力值不能超过 maxPowermaxPower 为一个非负整数)。由于第一个角色有了初始的战力值,所以不会再对编号为 0 的角色进行战力值限定。

请根据以上规则,计算出单个角色能达到的最大战力值。

输入格式

第一行为两个整数 n,m (2<=n<=10^6, 1<=m<=10^5),其中 n 为游戏中角色的总个数,m 为限制了最大战力值的角色数。
后边的 m 行,每一行都有两个整数 index, maxPower (index != 0 且 index < n - 1),index 是角色编号,index != 0 即不会对编号为 0 的角色进行战力值的限定,maxPower 是该角色被限定的最大战力值。

输出格式

输出1个整数,表示单个角色能达到的最大战力值。

输入样例1

3 2
1 3
2 2

说明:
第1行表示游戏中有3个角色,对其中2个角色限制了最大战力值。
接下来的2行是具体的限制,对编号为1的角色限制了最大战力值为3,对编号为2的角色限制了最大战力值为2。

输出样例1

2

说明:
[0,1,2] 是满足规则约束的一个战力值设定方案,相邻角色的战力值之差不超过 1,最大战力值是最后一个角色,最大战力值为 2

输入样例2

5 3
1 1
2 3
4 3

说明:
第1行表示游戏中有5个角色,对其中3个角色限制了最大战力值。
接下来的2行是具体的限制,对编号为1的角色限制了最大战力值为1,对编号为2的角色限制了最大战力值为3,对编号为4的角色限制了最大战力值为3。

输出样例2

3

说明:
[0,1,2,3,3] 是满足规则约束的一个战力值设定方案,相邻角色的战力值之差不超过 1,最大战力值是最后两个角色,最大战力值为 3

数据范围

2≤n≤10^6
1≤m≤10^5

首先先给出我的解答

解决方案


public class Main {

    public static int solution(int n, int m, int[][] limit) {
        // 初始化最小战力值数组和最大战力值数组
        int[] minPower = new int[n];
        int[] maxPower = new int[n];
        // 初始化maxPower数组为一个较大的值
        int INF = Integer.MAX_VALUE / 2; // 防止溢出
        for (int i = 0; i < n; i++) {
            maxPower[i] = INF;
        }

        // 第一个角色的战力值固定为0
        minPower[0] = 0;
        maxPower[0] = 0;

        // 将限制条件应用到maxPower数组
        for (int i = 0; i < m; i++) {
            int index = limit[i][0];
            int maxP = limit[i][1];
            maxPower[index] = Math.min(maxPower[index], maxP);
        }

        // 正向遍历,应用相邻差值不超过1的限制
        for (int i = 1; i < n; i++) {
            // 相邻角色的最小战力值不能小于前一个角色的战力值减1,且不能小于0
            minPower[i] = Math.max(0, minPower[i - 1] - 1);
            // 相邻角色的最大战力值不能超过前一个角色的战力值加1
            maxPower[i] = Math.min(maxPower[i], maxPower[i - 1] + 1);
            // 检查是否有解
            if (minPower[i] > maxPower[i]) {
                return -1; // 无法满足条件
            }
        }

        // 反向遍历,再次应用相邻差值不超过1的限制
        for (int i = n - 2; i >= 0; i--) {
            minPower[i] = Math.max(minPower[i], minPower[i + 1] - 1);
            maxPower[i] = Math.min(maxPower[i], maxPower[i + 1] + 1);
            if (minPower[i] > maxPower[i]) {
                return -1; // 无法满足条件
            }
        }

        // 找到所有角色中的最大战力值
        int maxBattlePower = 0;
        for (int i = 0; i < n; i++) {
            // 由于我们想要最大的战力值,取可能的最大值
            int power = maxPower[i];
            // 更新最大战力值
            if (power > maxBattlePower) {
                maxBattlePower = power;
            }
        }

        return maxBattlePower;
    }

    public static void main(String[] args) {
        // Add your test cases here
        
        System.out.println(solution(3, 2, new int[][]{{1, 3}, {2, 2}}) == 2);
        System.out.println(solution(5, 3, new int[][]{{1, 1}, {2, 3}, {4, 3}}) == 3);
    }
}

代码解释

  1. 初始化最小和最大战力值数组:
int[] minPower = new int[n];
int[] maxPower = new int[n];
int INF = Integer.MAX_VALUE / 2; // 使用较大的值,防止加法时溢出
for (int i = 0; i < n; i++) {
    maxPower[i] = INF;
}

其中,minPower[i]:第 i 个角色的最小可能战力值,初始为 0;maxPower[i]:第 i 个角色的最大可能战力值,初始为一个很大的值 INF。 之后,第一个角色的战力值固定为 0,因此最小值和最大值都为 0

  1. 应用限制条件到 maxPower 数组: 即对于有战力值限制的角色,将其最大战力值更新为限制值与当前值的较小者
for (int i = 0; i < m; i++) {
    int index = limit[i][0];
    int maxP = limit[i][1];
    maxPower[index] = Math.min(maxPower[index], maxP);
}
  1. 正向遍历,应用相邻差值限制:

最小战力值更新:

由于相邻角色的战力值差不能超过 1,因此第 i 个角色的最小战力值不能小于前一个角色的最小战力值减 1,且不能小于 0

最大战力值更新:

同理,第 i 个角色的最大战力值不能超过前一个角色的最大战力值加 1

可行性检查:

如果 minPower[i] > maxPower[i],则说明无解,返回 -1
for (int i = 1; i < n; i++) {
    minPower[i] = Math.max(0, minPower[i - 1] - 1);
    maxPower[i] = Math.min(maxPower[i], maxPower[i - 1] + 1);
    if (minPower[i] > maxPower[i]) {
        return -1; // 无法满足条件
    }
}
  1. 反向遍历,再次应用相邻差值限制:

最小战力值更新:

i 个角色的最小战力值不能小于后一个角色的最小战力值减 1

最大战力值更新:

i 个角色的最大战力值不能超过后一个角色的最大战力值加 1

可行性检查:

同样,如果 minPower[i] > maxPower[i],则无解
for (int i = n - 2; i >= 0; i--) {
    minPower[i] = Math.max(minPower[i], minPower[i + 1] - 1);
    maxPower[i] = Math.min(maxPower[i], maxPower[i + 1] + 1);
    if (minPower[i] > maxPower[i]) {
        return -1; // 无法满足条件
    }
}

最后的算法复杂度如下

算法复杂度:

时间复杂度: O(n),因为正向和反向各遍历一次数组。

空间复杂度: O(n),需要存储 minPower 和 maxPower 数组