最大战力值(第99道)
题目链接
https://www.marscode.cn/practice/8eeee14o2vr7vn?problem_no=99
题目描述
疫情使得人们线下社交隔离,进而刺激了宅娱乐经济,令手机游戏市场份额再次创新纪录。一款手机游戏一般有很多角色,每个角色都可以设定一个战力值。为了平衡每个角色的能力,提升玩家的游戏体验,游戏策划往往会对角色的战力值通过一些规则进行限制。
在某款手游里共有 `n` 个角色。这些角色从 `0` 到 `n-1` 进行编号排成一列。角色的战力值按照以下的规则进行限定:
1. 第一个角色的初始战力值为 `0`
2. 每个角色的战力值是一个非负的整数
3. 相邻角色的战力值差距不能超过 `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 \leq n \leq 10^6 \\
1 \leq m \leq 10^5
$$
题目思路
这道题有点意思,以游戏角色战力值为背景,加上一些约束条件之后,求游戏角色中的最高战力值。抛开场景的外壳,这无非就是一道求一批前后有关联的数值的问题,对于这种问题,我的解决思路是,从左往右根据关联条件走一遍,再从右往左根据关联条件走一遍,简单来说就是“跑个来回”。
现在,我们来看一看这道题。
第一步,我们先来初始化。要求最大值,首先我们得把值找出来,所以先创建一个数组来存放战力值,数组的值初始化为Integer的最大值。然后根据题目给出的战力限制,将战力值数组对应位置的战力值设置为被限制的最大值,再将第一个角色的战力值设置为0(题目给出的条件)。
第二步,我们根据关联关系,从左到右跑一遍。我们从左往右跑的时候,我们可以以当前索引 i 的视角来设置约束条件,索引 i 角色的战力最大值,要在当前值和比前一个(i - 1)角色大1的值中选择那个最小的值,为什么是最小值呢?因为我们得防止战力值超过最大限制。
设置完当前索引 i 的战力之后,我们还得往后看一眼跑在后面的(i - 1)角色,毕竟我们是要求最大战力值,所以在保证不会越界之后,我们跑后面的角色自然是能高一点就高一点,所以对前一个角色重新进行一个调整,调整为他本身的值和(当前索引角色的最大值-1)这两个值中的最大值。
就这样保证自己不越界,又让跑在自己后面的角色尽量高的情况下,从左到右跑完一轮。
接着我们再从右到左跑一遍。那为什么我们还要从右到左再跑一遍呢?其实是因为我们跑第一遍的时候,对跑在当前索引角色后面的角色进行的调整,可能打破了原有的关联限制条件。所以从右到左再跑一遍,是为了确保那些超过关联限制的条件,重新回到限制的红圈之中。
这回,当前索引仍然是 i 角色,只不过跑在后面的角色变成了(i + 1)了而已。这其实很好理解,从左到右跑,和从右到左跑,两次跑的方向本身就是相反的。
经过了来回跑之后,我们就可以得到了所有角色的战力值数组,接着遍历数组,将最大值取出来即可。
题目答案
public class No99 {
public static int solution(int n, int m, int[][] array) {
// Edit your code here
int[] power = new int[n];
Arrays.fill(power, Integer.MAX_VALUE);
//更新限制条件
for (int i = 0;i < m ;i++){
int index = array[i][0];
int maxPower = array[i][1];
power[index] = Math.min(power[index],maxPower);
}
//初始化第一个角色的战力值
power[0] = 0;
//计算每个角色的最大战力值
for (int i = 1;i < n;i++){
//计算当前角色的最大战力值
power[i] = Math.min(power[i], power[i-1] + 1);
//反向传播限制条件
power[i-1] = Math.max(power[i-1], power[i] - 1);
}
//再次正向传播限制条件
for (int i = n-2;i >= 0 ;i--){
power[i] = Math.min(power[i],power[i+1]+1);
//反向传播限制条件
power[i+1] = Math.max(power[i+1],power[i] -1);
}
//返回最大的战力值
int maxPower = 0;
for (int p : power){
maxPower = Math.max(maxPower,p);
}
System.out.println(maxPower);
return maxPower;
}
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);
}
总结
说实话,这道题一开始对我来说有一定的难度,因为一开始我没看懂题目在说什么,加了一层背景,我就被吓唬住了。很多人可能和我一样,之前刷的题,都很直白的说我就是要求什么,直接在数据结构层面告诉我们需要求啥。
这道题却包装了一层游戏角色的外壳,需要我们剥开外壳,搞清楚在数据结构层面它想求什么,这样思路才会比较清晰,一旦剥开,会突然发现,其实这道题以前就做过类似的,是老朋友了。只是化了点妆,题大十八变罢了。
今天就到这了,买夜宵去喽~拜拜~