题目描述
Dota2 的世界里有两个阵营:Radiant(天辉)和 Dire(夜魇)
Dota2 参议院由来自两派的参议员组成。现参议院希望对一个 Dota2 游戏里的改变作决定。他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的一项:禁止一名参议员的权利:
参议员可以让另一位参议员在这一轮和随后的几轮中丧失所有的权利。
宣布胜利:
如果参议员发现有权利投票的参议员都是同一个阵营的,他可以宣布胜利并决定在游戏中的有关变化。
给定一个字符串代表每个参议员的阵营。字母 “R” 和 “D” 分别代表了 Radiant(天辉)和 Dire(夜魇)。然后,如果有 n 个参议员,给定字符串的大小将是 n。
以轮为基础的过程从给定顺序的第一个参议员开始到最后一个参议员结束。这一过程将持续到投票结束。所有失去权利的参议员将在过程中被跳过。
假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。输出应该是 Radiant 或 Dire。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/dota2-senate
思路
参议员行使禁止权一定是禁止依序(环状)离自己最近的对方阵营参议员,否则该对方阵营参议员就会先禁止该阵营的参议员
思路一
- 用一个vector记录每轮每个参议员行使权利后,每位参议院的状态(1:仍可行使权利;0:丧失所有权利),初始全部为1
- 把形参参议员字符串看成是环形的,任意一位正在行使权利的参议员从自己开始向后遍历,直到找到和自己不同阵营且仍有权利的参议员为止,行使禁止权(将vector中这位参议员的状态修改为0)
- 若遍历的结果指向该参议员本身,则说明剩余参议员全部为相同阵营的,该参议员行使宣布胜利权,结束循环
注:该实现的时间复杂度较高,可进行如下修改:
思路二
- 不使用vector保存其参议员状态,而是只要某位参议员被使用了禁止权利后,即将其从senate中除去
思路三(参考官方解答)
- 使用两个队列模拟两个阵营的参议员依序行使权利,队列中保存每位参议员行使权利的时间
- 比较两个队列头的时间大小:小的那位参议员行使权利,从队列头pop出来,再加上senate.length(所有参议员人数)后入队准备下一轮行使权利;大的那位参议员被永久pop出自己的队列
- 随后当一个队列为空时,另一个队列的阵营胜利
代码(CPP)
思路一实现
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
string predictPartyVictory(string senate) {
int len = senate.length();
vector<int> active(len, 1);
while (true) {
for (int i = 0; i < len; i++) {
if (active[i] == 0) {
continue;
}
int j = 1;
for (; j <= len; j++) {
int idx = i + j;
if (idx >= len) {
idx -= len;
}
if (active[idx] == 0) {
continue;
}
if (idx == i) {
if (senate[i] == 'D') {
return "Dire";
}
else {
return "Radiant";
}
}
if (active[idx] == 1 && senate[idx] != senate[i]) {
active[idx] = 0;
break;
}
}
}
}
}
};
int main() {
string s = "RDD";
Solution* S = new Solution();
string res = S->predictPartyVictory(s);
}
思路二实现
#include <string>
using namespace std;
class Solution {
public:
string predictPartyVictory(string senate) {
while (true) {
int i = 0;
bool flag = false;
while (i < senate.length()) {
int j = 1;
while (j <= senate.length()) {
int idx = i + j;
if (idx >= senate.length()) {
idx -= senate.length();
flag = true;
}
if (idx == i) {
if (senate[i] == 'D') {
return "Dire";
}
else {
return "Radiant";
}
}
if (senate[idx] != senate[i]) {
senate.erase(idx, 1);
break;
}
j += 1;
}
if (!flag) {
i += 1;
}
}
}
}
};
int main() {
string s = "RDR";
Solution* S = new Solution();
string res = S->predictPartyVictory(s);
}
思路三实现
#include <string>
#include <queue>
using namespace std;
class Solution {
public:
string predictPartyVictory(string senate) {
int len = senate.length();
queue<int> dire;
queue<int> radiant;
for (int i = 0; i < len; i++) {
if (senate[i] == 'D') {
dire.push(i);
}
else {
radiant.push(i);
}
}
while (true)
{
if (dire.empty()) {
return "Radiant";
}
if (radiant.empty()) {
return "Dire";
}
if (dire.front() < radiant.front()) {
dire.push(dire.front() + len);
dire.pop();
radiant.pop();
}
else {
radiant.push(radiant.front() + len);
radiant.pop();
dire.pop();
}
}
}
};
int main() {
string s = "RDR";
Solution* S = new Solution();
string res = S->predictPartyVictory(s);
}