题目
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] 之间.
菜鸡题解
【贪心】每读到一个字符就删去离它最近的一个对手,直到其中一个阵营全部删去
string predictPartyVictory(string senate) {
int surviveR = 0, surviveD = 0;
vector<int> person;
for(int i = 0; i != senate.size(); i++){//把senate读入person
if(senate[i] == 'R'){//R则置1,R的个数++
person.push_back(1); surviveR++;
}
else{//D则置0,D的个数++
person.push_back(0); surviveD++;
}
}
for(int i = 0; surviveR && surviveD; ){//直到有一方全部删去
if(person[i] == 1){//当前是R
for(int j = (i+1)%person.size(); j != i; j = (++j)%person.size()){//找到离它最近的一个对手
if(person[j] == 0) {
person.erase(person.begin() + j );//删去
surviveD--;
break;
}
}
}
else{
for(int j = (i+1)%person.size(); j != i; j = (++j)%person.size()){//找到离它最近的一个对手
if(person[j] == 1) {
person.erase(person.begin() + j );//删去
surviveR--;
break;
}
}
}
if(i>=person.size()) i=0;
else i++;
//i =(++i)%person.size()会出现问题
}
if(surviveD == 0) return "Radiant";
else return "Dire";
}
改了有一个小时,主要是在循环的地方难改。一开始在用list和迭代器,但是不大会用,最后还是改成了vector;每次 j 取余的时候注意是对实时的person.size()取余;i 改变的时候不同于 j ,j 每次都是从0重新开始的,可以直接用取余,但是 i 是整体的,i在++的时候伴随着size的变化,所以要用判断
看到下面两个解法的时候,内心:没带脑子写代码真的是不行的,好想法可以转化为时间空间复杂度的缩减
官方题解
class Solution {
public:
string predictPartyVictory(string senate) {
int n = senate.size();
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() ? "Radiant" : "Dire";
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/dota2-senate/solution/dota2-can-yi-yuan-by-leetcode-solution-jb7l/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
第一遍读取senate中的每个元素,分别把该元素的下标放进radiant或dire中;在删去的时候通过queue的先进先出,比较队列头的大小,小的末尾加一个,两个队列队首全部弹出,最后剩余的就是赢家
大佬题解
string predictPartyVictory(string senate) {
// R = true表示本轮循环结束后,字符串里依然有R。D同理
bool R = true, D = true;
// 当flag大于0时,R在D前出现,R可以消灭D。当flag小于0时,D在R前出现,D可以消灭R
int flag = 0;
while (R && D) { // 一旦R或者D为false,就结束循环,说明本轮结束后只剩下R或者D了
R = false;
D = false;
for (int i = 0; i < senate.size(); i++) {
if (senate[i] == 'R') {
if (flag < 0) senate[i] = 0; // 消灭R,R此时为false
else R = true; // 如果没被消灭,本轮循环结束有R
flag++;
}
if (senate[i] == 'D') {
if (flag > 0) senate[i] = 0;
else D = true;
flag--;
}
}
}
// 循环结束之后,R和D只能有一个为true
return R == true ? "Radiant" : "Dire";
}
作者:carlsun-2
链接:https://leetcode-cn.com/problems/dota2-senate/solution/649-dota2-can-yi-yuan-tan-xin-suan-fa-ji-siha/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
真的是太妙了。
这里哟给了一个技巧,在每一轮循环的过程中,去过模拟优先消灭身后的对手,其实是比较麻烦的,所以用一个变量记录当前参议员之前有几个敌对对手了,进而判断自己是否被消灭了。这个变量就是代码中的flag
来自评论的吐槽:
leetcode 用一道算法题告诉我们:打团要抢先手,不然人多也打不过