思路:

题目的主要信息:

  • 皮卡丘的生命和攻击力分别为HP与ACK,杰尼龟的生命与攻击力分别为HP2与ACK2,默认攻击一次对方生命值减去攻击力的数值
  • 杰尼龟可以选择恢复全额生命到HP2,但是该轮不能攻击
  • 每个回合皮卡丘优先攻击,如果杰尼龟处于不断复活的循环中则认定不能打败皮卡丘,返回-1

方法一:暴力法(超时)
具体做法:
暴力模拟双方交战的场景,首先排除皮卡丘第一轮优先攻击杀死了杰尼龟,或者第一轮杀不死皮卡丘被皮卡丘第二轮杀死的情况,然后以皮卡丘的作为循环条件,开始模拟战况,模拟的时候我们以贪心的思想,每次杰尼龟到下一次攻击会死的时候再选择回复生命值。
具体如下:
图片说明

class Solution {
public:
    long long Pokemonfight(long long HP, long long ACK, long long HP2, long long ACK2) {
        if(ACK >= HP2 || ACK * 2 >= HP2 && ACK2 < HP) //皮卡丘优先攻击杀死了,或者第一轮杀不死皮卡丘被皮卡丘第二轮杀死
            return -1;
        if(ACK2 >= HP) //不用吃药硬抗一次,第一轮获胜
            return 1;
        long long res = 0;
        long long temp = HP2; //暂存现在血量
        while(HP > 0){
            res++;
            if(temp > ACK){ //不用吃药
                temp -= ACK;
                HP -= ACK2;
            }
            else
                temp = HP2 - ACK;//吃药挨打
        }
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,n为皮卡丘血量HP
  • 空间复杂度:,无额外空间

方法二:数学规律
具体做法:
仔细观察方法一中模拟的最终战况图:
图片说明
我们可以发现除了第一轮其他轮都是循环,我们可以用找到每个循环的回合数,每个回合会因回复少攻击一次,因此每个循环的有效攻击为,利用这两个数据我们就可以知道打败皮卡丘的接近数据,为什么是接近,为开头有第一回合,结尾需要有考虑残局要不要回复以及不满一个循环等问题。

class Solution {
public:
    long long Pokemonfight(long long HP, long long ACK, long long HP2, long long ACK2) {
        if(ACK >= HP2 || ACK * 2 >= HP2 && ACK2 < HP) //皮卡丘优先攻击杀死了,或者第一轮杀不死皮卡丘被皮卡丘第二轮杀死
            return -1;
        if(ACK2 >= HP) //不用吃药硬抗一次,第一轮获胜
            return 1;
        long long res = 1;
        HP -= ACK2; //除去第一轮
        long long countOfCycle = (HP2 - 1) / ACK; //找到循环的回合数
        long long ackOfCycle = (countOfCycle - 1) * ACK2;    // 每个循环可以贡献的攻击力 
        long long basicCount = HP / ackOfCycle;//一共需要几轮
        res += basicCount * countOfCycle; 
        long long restHP = HP % ackOfCycle;//这些攻击之后,HP 还剩下多少
        if (restHP == 0) //最后一次不需要复活,直接拿下
            res--;
        else
            res += restHP / ACK2 + (restHP % ACK2 == 0 ? 0 : 1);// 如果还有血,不需要在进行完整的循环 
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,没有循环,常数时间
  • 空间复杂度:,常数的空间变量