题目描述:
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] 之间.
方法1:
主要思路:解题汇总
(1)使用两个队列实现,交替的存储剩余的字符,既在一轮投票中,起始时,一个队列为空,另一个非空,然后开始投票;
(2)使用贪心的思想,当前的字符对应的阵营一定要先投后面距离其最近的对方阵营的议员出局,为了实现该过程,可以保存当前字符,同时使用一个变量保存当前字符对应的阵营议员的投票,若下一个字符和当前字符相同,则增加投票,若是对方阵营的字符,则减小投票;
(3)若投票量为0,则需要重新统计新的字符,并再次统计和投票,直到最终;
class Solution {
public:
//一轮投票过程
void helper(deque<char>& not_empty_dq,deque<char>& empty_dq,int&counts,char& pre){
while(!not_empty_dq.empty()){//直到遍历所有的现存议员对应的字符
if(counts==0){//若没有投票数量了,从新统计当前字符
counts=1;
pre=not_empty_dq.front();
not_empty_dq.pop_front();
empty_dq.push_back(pre);
}
else{
//增加投票数量
if(pre==not_empty_dq.front()){
++counts;
not_empty_dq.pop_front();
empty_dq.push_back(pre);//并保存剩余的议员
}
else{//减小投票数量
--counts;
not_empty_dq.pop_front();
}
}
}
}
string predictPartyVictory(string senate) {
deque<char> dq1(senate.begin(),senate.end());//初始化一个队列
deque<char> dq2;
char pre;//表示当前阵营对应的字符
int counts=0;//统计当前阵营的投票
while(true){
if(dq1.empty()){//找出那个队列是空的
helper(dq2,dq1,counts,pre);//一轮投票
if(counts>=dq1.size()){//说明当前队列中都是同一阵营的议员
break;
}
}
else{
helper(dq1,dq2,counts,pre);
if(counts>=dq2.size()){
break;
}
}
}
if(pre=='R'){//根据剩余的字符,返回对应的阵营
return "Radiant";
}
return "Dire";
}
};
方法2:
主要思路:
(1)同样使用两个队列,投票的思路一致,只不过表示的方式不同;
(2)使用各个字符对应的索引位置进行初始化两个队列,便于保证字符之间的前后关系;
(3)小的索引,说明在前面,具有优先的投票权,可以将另个阵营中的人投出去,注意需要循环补充具有投票全的该阵营的人;
class Solution {
public:
string predictPartyVictory(string senate) {
queue<int> dq_R;//分别表示两个阵营
queue<int> dq_D;
int len=senate.size();
//使用索引进行初始化
for(int i=0;i<len;++i){
if(senate[i]=='R'){
dq_R.push(i);
}
else{
dq_D.push(i);
}
}
//直到某个队列为空,既说明被全部投出去了
while(!dq_R.empty()&&!dq_D.empty()){
if(dq_R.front()<dq_D.front()){//判断具有投票权的阵营
dq_R.push(dq_R.front()+len);//将具有投票权的阵营循环加入要弹出的议员
}
else{
dq_D.push(dq_D.front()+len);
}
//弹出比较过的
dq_R.pop();
dq_D.pop();
}
if(!dq_R.empty()){//不为空的阵营胜利
return "Radiant";
}
return "Dire";
}
};