题目的主要信息:

  • Alice的牌里有p1张石头牌,q1张剪刀牌,m1张布牌,Bob的牌里有p2张石头牌,q2张剪刀牌,m2张布牌,每人都是n张
  • 赢一局得1分,输一局扣1分,平局不得分,问Alice在每次知道Bob出什么牌的情况,怎么出牌最终得分最高

方法一:暴力模拟

具体做法:
我们利用贪心的思想,Alice知道Bob每次出什么牌,如果她手里有可以赢的牌就出可以赢的牌去得分,如果没有再看有没有相同的牌争取平局不扣分,最后实在不行再出要输的牌扣分,这样得分才能最高。
因为三种牌是相互克制的,出牌顺序并不影响得分,因此我们可以按照Bob先出石头再出剪刀最后出布的顺序来模拟。
图片说明

class Solution {
public:

    int Highestscore(int n, int p1, int q1, int m1, int p2, int q2, int m2) {
        int res = 0;
        //Alice赢的局
        while(p2 > 0){
            if(m1 > 0){ //Bob出石头,Alice有布出布,否则Bob的石头留到后面
                m1--;
                p2--;
                res++; //得分
            }
            else
                break;
        }
        while(q2 > 0){
            if(p1 > 0){ //Bob出剪刀,Alice有石头出石头,否则Bob的剪刀留到后面
                p1--;
                res++; //得分
                q2--;
            }
            else
                break;
        }
        while(m2 > 0){
            if(q1 > 0){ //Bob出布,Alice有剪刀出剪刀,否则Bob的布留到后面
                q1--;
                res++; //得分
                m2--;
            }
            else
                break;
        }
        //打平的局
        while(p2 > 0){
            if(p1 > 0){ //Bob出石头,Alice没有布了,有石头出石头,打平
                p1--;
                p2--;
            }
            else
                break;
        }
        while(q2 > 0){
            if(q1 > 0){ //Bob出剪刀,Alice没有石头了,有剪刀出剪刀,打平
                q1--;
                q2--;
            }
            else
                break;
        }
        while(m2 > 0){
            if(m1 > 0){ //Bob出布,Alice没有剪刀了,有布出布,打平
                m1--;
                m2--;
            }
            else
                break;
        }
        //Alice输的局:最后Bob还剩下的牌Alice都输
        while(p2 > 0){ 
            p2--;
            res--;
        }
        while(q2 > 0){
            q2--;
            res--;
        }
        while(m2 > 0){
            m2--;
            res--;
        }
        return res;
    }
};

复杂度分析:

  • 时间复杂度:,最坏情况遍历所有的牌,一共
  • 空间复杂度:,常数级空间

方法二:直接计算

具体做法:
上面的循环可以用min函数直接计算,比如Bob出石头Alice能赢的局就是双方的,同理其他的可以类似计算,这就是Alice能赢的局,得分加上局数就行了。后面他们手中各种牌要减去相应的局数(被消耗掉了),得到的牌用相同的手法处理平局的情况,最后Bob手中剩余的牌Alice都赢不了,得分减去这些牌数。

class Solution {
public:

    int Highestscore(int n, int p1, int q1, int m1, int p2, int q2, int m2) {
        int res = 0;
        int temp1 = min(p2, m1); //Bob出石头,Alice出布能赢的局
        int temp2 = min(q2, p1); //Bob出剪刀,Alice出石头能赢的局
        int temp3 = min(m2, q1); //Bob出布,Alice出剪刀能赢的局
        res = temp1 + temp2 + temp3; //上三种情况得分
        //减掉上面用掉的牌
        p2 -= temp1; 
        m1 -= temp1;
        q2 -= temp2;
        p1 -= temp2;
        m2 -= temp3;
        q1 -= temp3;
        temp1 = min(p1, p2); //Bob出石头,Alice出石头,打平的局
        temp2 = min(q1, q2); //Bob出剪刀,Alice出剪刀,打平的局
        temp3 = min(m1, m2); //Bob出布,Alice出布,打平的局
        //减掉上面用掉的牌
        p2 -= temp1;
        q2 -= temp2;
        m2 -= temp3;
        return res - p2 - q2 - m2; //最后剩余的Bob手中的牌都是Alice不能赢的
    }
};

复杂度分析:

  • 时间复杂度:,直接计算,不含循环
  • 空间复杂度:,常数级空间