以下是题目描述
问题描述
疫情使得人们线下社交隔离,进而刺激了宅娱乐经济,令手机游戏市场份额再次创新纪录。一款手机游戏一般有很多角色,每个角色都可以设定一个战力值。为了平衡每个角色的能力,提升玩家的游戏体验,游戏策划往往会对角色的战力值通过一些规则进行限制。
在某款手游里共有 n 个角色。这些角色从 0 到 n-1 进行编号排成一列。角色的战力值按照以下的规则进行限定:
- 第一个角色的初始战力值为
0 - 每个角色的战力值是一个非负的整数
- 相邻角色的战力值差距不能超过
1(之间的差值可能是0,+1,-1)
在上边规则的基础上会再额外对其中的一些角色增加一些限制,设定最大战力值。这些限制会以若干数对的形式给出,每一个数对定义如下,limit[i] = [index, maxPower](index != 0 且 i < n - 1)表示编号为 index 的角色的最大战力值不能超过 maxPower(maxPower 为一个非负整数)。由于第一个角色有了初始的战力值,所以不会再对编号为 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);
}
}
代码解释
- 初始化最小和最大战力值数组:
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
- 应用限制条件到 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,因此第 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; // 无法满足条件
}
}
- 反向遍历,再次应用相邻差值限制:
• 最小战力值更新:
第 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 数组