豆包MarsCode算法题之最大战力值

最大战力值(第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);
    }

        总结

        说实话,这道题一开始对我来说有一定的难度,因为一开始我没看懂题目在说什么,加了一层背景,我就被吓唬住了。很多人可能和我一样,之前刷的题,都很直白的说我就是要求什么,直接在数据结构层面告诉我们需要求啥。

        这道题却包装了一层游戏角色的外壳,需要我们剥开外壳,搞清楚在数据结构层面它想求什么,这样思路才会比较清晰,一旦剥开,会突然发现,其实这道题以前就做过类似的,是老朋友了。只是化了点妆,题大十八变罢了。

        今天就到这了,买夜宵去喽~拜拜~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值