leetcode 649.Dota2参议院

leetcode 649.Dota2参议院

题干

Dota2 的世界里有两个阵营:Radiant(天辉)和 Dire(夜魇)
Dota2 参议院由来自两派的参议员组成。现在参议院希望对一个 Dota2 游戏里的改变作出决定。他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的一项:
禁止一名参议员的权利:
参议员可以让另一位参议员在这一轮和随后的几轮中丧失所有的权利。
宣布胜利:
如果参议员发现有权利投票的参议员都是同一个阵营的,他可以宣布胜利并决定在游戏中的有关变化。

给定一个字符串代表每个参议员的阵营。字母 “R” 和 “D” 分别代表了 Radiant(天辉)和 Dire(夜魇)。然后,如果有 n 个参议员,给定字符串的大小将是 n。
以轮为基础的过程从给定顺序的第一个参议员开始到最后一个参议员结束。这一过程将持续到投票结束。所有失去权利的参议员将在过程中被跳过。
假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。输出应该是 Radiant 或 Dire。

示例 1:
输入:“RD”
输出:“Radiant”
解释:第一个参议员来自 Radiant 阵营并且他可以使用第一项权利让第二个参议员失去权力,因此第二个参议员将被跳过因为他没有任何权利。然后在第二轮的时候,第一个参议员可以宣布胜利,因为他是唯一一个有投票权的人

示例 2:
输入:“RDD”
输出:“Dire”
解释:
第一轮中,第一个来自 Radiant 阵营的参议员可以使用第一项权利禁止第二个参议员的权利
第二个来自 Dire 阵营的参议员会被跳过因为他的权利被禁止
第三个来自 Dire 阵营的参议员可以使用他的第一项权利禁止第一个参议员的权利
因此在第二轮只剩下第三个参议员拥有投票的权利,于是他可以宣布胜利

提示:
给定字符串的长度在 [1, 10,000] 之间.

题解

首先想到dp的解法,但是状态位的设置和状态转移方程考虑有点问题,所以第69个样例没过。
还有每次投票后有效人数的问题,我这么写不脑瘫么。

class Solution {
    
    
public:
    string predictPartyVictory(string senate) {
    
    
        int n = senate.length();
        vector<vector<int> > dp(n,vector<int>(2,0));
        dp[n-1][1] = senate[n-1] == 'D' ? 1 : -1;
        dp[n-1][0] = senate[n-1] == 'D' ? 1 : 0;
        for(int i = n - 2 ; i >= 0 ; --i){
    
    
            if(senate[i] == 'R' && dp[i+1][1] > 1){
    
    
                dp[i][0] = 1;
                dp[i][1] = dp[i+1][1] - 1;
            }else if(senate[i] == 'R'){
    
    
                dp[i][0] = 0;
                dp[i][1] = dp[i+1][1] - 1;
            }else if(senate[i] == 'D' && dp[i+1][1] < -1){
    
    
                dp[i][0] = 0;
                dp[i][1] = dp[i+1][1] + 1;
            }else{
    
    
                dp[i][0] = 1;
                dp[i][1] = dp[i+1][1] + 1;
            }
        }
        return dp[0][0] == 1 ? "Dire" : "Radiant";
    }
};
/*
考虑只有一个字符的字符串,显然这个字符是什么,最后获胜的就是哪个阵营
考虑在字符串前面加一个字符串,形成一个两个字符的字符串,显然,加在前面的这个字符串是什么,最后获胜的就是哪个阵营
考虑再在前面加一个字符,这时会有两种不同的情况:如果加在前面的字符与后面字字符串获胜阵营相同,那么获胜阵营不变,若不同呢?
    这时考虑后面字符串的两种情况:假设后面字符串获胜阵营为D,新加字符为R
        后面字符串中D>R+1:
            获胜阵营仍为D
        后面字符串中D<=R+1:
            获胜阵营为R
那么可以考虑使用动态规划,从后向前遍历字符串,dp[i][0]保存从末尾到字符串第i位的获胜情况,dp[i][1]保存从末尾到字符串第i位D与R个数的差值
用1表示Dire,0表示Radiant
        考虑状态转移方程:
            if(senate[i] == 'R' && dp[i+1][1] > 1){
                dp[i][0] = 1;
                dp[i][1] = dp[i+1][1] - 1;
            }else if(senate[i] == 'R'){
                dp[i][0] = 0;
                dp[i][1] = dp[i+1][1] - 1;
            }else if(senate[i] == 'D' && dp[i+1][1] < -1){
                dp[i][0] = 0;
                dp[i][1] = dp[i+1][1] + 1;
            }else{
                dp[i][0] = 1;
                dp[i][1] = dp[i+1][1] + 1;
            }
        考虑初值:
            int n = senate.length();
            dp[n-1][1] = senate[n-1] == 'D' ? 1 : -1;
            dp[n-1][0] = senate[n-1] == 'D' ? 1 : 0;
考虑答案:
    dp[0][0]
    为1即Dire 0即Radiant
    DRDRR
*/

用队列模拟投票
遍历字符串,将议员出现的位置分别存入对应阵营的队列。
比较两个队列的首元素,较小的那个议员会使较大议员失效,因此在后续投票中,较小议员仍然是可用的,因此将较小议员出现的位置+n推入队列,相当于下一轮投票出现的位置
将两个队列首元素抛出。

class Solution {
    
    
public:
    string predictPartyVictory(string senate) {
    
    
        int n = senate.length();
        queue<int> radiant,dire;
        for(int i = 0 ; i < n ; ++i){
    
    
            if(senate[i] == 'R'){
    
    
                radiant.push(i);
            }else{
    
    
                dire.push(i);
            }
        }
        while(!radiant.empty() && !dire.empty() ){
    
    
            if(radiant.front() < dire.front()){
    
    
                radiant.push(radiant.front() + n);
            }else{
    
    
                dire.push(dire.front() + n);
            }
            radiant.pop();
            dire.pop();
        }
        return radiant.empty() ? "Dire" : "Radiant";
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_43662405/article/details/111053247