思路:

题目的主要信息:

  • 皮卡丘的生命值是HP,攻击力是ACK;杰尼龟的生命值是HP2,攻击力是ACK2。
  • 杰尼龟在每回合开始前可以吃药满血复活,但吃药后不得在本回合发动攻击。
  • 皮卡丘比杰尼龟先发动攻击。若能成功击败皮卡丘则返回最少回合数,否则返回-1。

方法一:暴力

首先解决一些特殊情况:
a.HP2<ACK,杰尼龟第一局就被皮卡丘打倒,返回-1;
图片说明
b.HP<=ACK2,杰尼龟第一局就把皮卡丘打倒,返回1;
图片说明
其他情况以模拟战斗过程进行分析,若第round局结束后杰尼龟当前的血量低于ACK,表示杰尼龟必须吃药恢复血量,同时本局不能进攻,仍受到皮卡丘的攻击;若杰尼龟当前的血量高于ACK,则这一局可以发起进攻;
模拟对战如下图所示:
图片说明
c.HP2-ACK<ACK,杰尼龟第一局不会被打倒,但一直处于复活的死循环中,返回-1;
图片说明

具体做法:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param HP long长整型 HP
     * @param ACK long长整型 ACK
     * @param HP2 long长整型 HP2
     * @param ACK2 long长整型 ACK2
     * @return long长整型
     */
    long long Pokemonfight(long long HP, long long ACK, long long HP2, long long ACK2) {
        // write code here
        if(ACK>=HP2||((HP2-ACK)<=ACK&&HP>ACK2))//杰尼龟第一回合就被打死或者处于***复活的死循环
        {
            return -1;
        }
        if(HP<=ACK2)//第一局杰尼龟打败了皮卡丘
        {
            return 1;
        }
        int round=0;
        int pikapika=HP2;//pikapika代表杰尼龟当前的剩余血量
        while(HP>0)//皮卡丘还没被打败时,继续战斗
        {
            if(pikapika>ACK)//杰尼龟目前剩余血量还能扛住皮卡丘再一轮进攻时
            {
                pikapika-=ACK;//皮卡丘进攻
                HP-=ACK2;//杰尼龟进攻
            }else{//杰尼龟扛不住进攻了,***
                pikapika=HP2-ACK;//杰尼龟恢复血量至HP2,皮卡丘发动进攻
            }
            round++;
        }
        return round;

    }
};

复杂度分析:

  • 时间复杂度:图片说明 ,最差情况为皮卡丘的血量HP。
  • 空间复杂度:图片说明 ,只用了常数空间。

方法二:数学方法

首先计算如果纯攻击的话,需要多少回合能打败皮卡丘,对HP%ACK2 进行判断,如果HP%ACK2为0,则刚好HP/ACK2回合可以打败皮卡丘;若HP%ACK2不为0,则需要多一回合。
然后计算杰尼龟在多少个回合后需要吃药。对HP2%ACK进行判断,若HP2%ACK为0,则表示HP2/ACK回合后,杰尼龟就死亡了,因此必须在HP2/ACK-1回合时就吃药;若HP2%ACK不为0,表示HP2/ACK后杰尼龟还有剩余血量,可以在HP2/ACK回合后再吃药;
最后计算杰尼龟在和皮卡丘战斗的过程中需要吃几次药。
由于第round回合就把皮卡丘打败了了,杰尼龟不用吃药,所以只要考虑前round-1次的吃药次数。
由于皮卡丘是先手,所以不能等到杰尼龟drug_round后再吃药,所以杰尼龟必须在drug_round-1回合后就吃药。因此(round-1)/(drug_round-1)表示杰尼龟吃药的回合数。对(round-1)%(drug_round-1)进行判断,若为0,我们剔除最后一次回血的情况;若不为0,则返回(round-1)/(drug_round-1)。
具体做法:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param HP long长整型 HP
     * @param ACK long长整型 ACK
     * @param HP2 long长整型 HP2
     * @param ACK2 long长整型 ACK2
     * @return long长整型
     */
    long long Pokemonfight(long long HP, long long ACK, long long HP2, long long ACK2) {
        if(ACK >= HP2 || (ACK2 < HP && ACK*2 >= HP2))
        {
            return -1;
        }
        // 皮卡丘第一局就被打死
        if(HP <= ACK2)
        {
            return 1;
        }
        // round为打败皮卡丘需要的回合数
        long long round;
        if(HP%ACK2 == 0)
        {
            round=HP/ACK2;
        }else{
            round=(HP/ACK2)+1;
        }
        // drug_round为每次满血复活后可以撑多少回合不吃药
        long long drug_round;
        if(HP2%ACK == 0)
        {
            drug_round=(HP2/ACK)-1;
        }else{
            drug_round=(HP2/ACK);
        }
        //count为需要吃药的回合数
        long long count=0;
        if(round < drug_round)//不需要吃药
        {
            return round;
        }else {//计算吃药次数
            if((round-1)%(drug_round-1)==0)
            {
                count=(round-1)/(drug_round-1)-1;
            }else{
                count=(round-1)/(drug_round-1);
            }
        }
        //最后返回吃药回合数+攻击回合数
        return count+round;
    }
};

复杂度分析:

  • 时间复杂度:图片说明 ,没有循环
  • 空间复杂度:图片说明 ,只使用了常数空间