649. Dota2 参议院
题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/dota2-senate/
题目
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]
之间.
解题思路
思路:贪心(队列)
先审题,题目给定字符串 senate
中,包含字母 R
和 D
,其中:
R
表示 Dota2 世界阵营中的Radiant
(天辉);D
表示 Dota2 世界阵营中的Dire
(夜魇)。
题中说明,Dota2 世界中的参议院由上面两派组成。现在要以基于轮为过程投票对游戏改变做出决定。其中每个参议员都有以下的权利:
- 禁止一名参议员的权利。这里指的是禁止另外一个阵营的参议员,而被禁止后,后续的票决当中都会失去权利,也即是会被直接跳过;
- 宣布胜利。如果有权利进行票决的成员中仅剩下同一方阵营的参议员,可以直接宣布胜利,决定游戏改变。
题目中假设每一位参议员都足够聪明能够做出最好的策略。在以轮为过程投票中,是以给定字符串的顺序从第一个参议员开始到最后一个参议员结束。假设存在两个阵营的参议员,以第一个参议员为例说明(假设为 R
),因为存在另外一个阵营的参议员,那么此时只能行使**【禁止一名参议员的权利】**。
以下 R 表示天辉,D 表示夜魇。
此时,该参议员(R
)应该选择禁止后续其他阵营前面还是后面的参议员(D
)?
这里应该选择禁止其他阵营前面的参议员(D
),也就是首选当前参议员(R
)后续的第一个其他阵营的议员(D
)。如果选择的是后面的议员(D
),那么其他阵营前面的议员(D
)未被禁止,若行使禁止权利时,接下来的一名己方议员(R
)则会丧失权利,这里并不是好的策略。
那么行使禁止权力时,应该优先选择最早的议员。这里我们可以使用两个队列 radiant
和 dire
分别存储对应阵容的议员的投票顺序。具体的思路如下:
- 若
radiant
和dire
其中一个为空时,那么另外一方可以宣布胜利; - 若均不为空时,那么这里需要比较队列首元素进行判断谁可以先行使权力:
- 如果
radiant
的首元素小于dire
的首元素时,那么R
先行使权力,选择dire
首元素对应的议员。那么这里要将dire
的首元素弹出队列,同时将radiant
的首元素弹出,加上n
之后重新添加到radiant
队列尾部。 - 如果
radiant
的首元素大于dire
的首元素时,那么D
先行使权力,选择radiant
首元素对应的议员。这里一样要将radiant
首元素弹出队列,也将dire
首元素弹出加上n
之后添加到dire
队列尾部。
- 如果
其中上面将对应首元素弹出加上 n
之后添加到对应队列尾部这里,n
表示的是初始字符串 senate
的长度。这里加上 n
是为了保持初始相应投票顺序。
具体的代码实现如下。
class Solution:
def predictPartyVictory(self, senate: str) -> str:
# 声明队列,用以存储对应阵营的投票顺序
radiant = collections.deque()
dire = collections.deque()
n = len(senate)
# 遍历字符串 senate 填充队列
for i, ch in enumerate(senate):
if ch == 'R':
radiant.append(i)
else:
dire.append(i)
# 不为空时,开始比较两个队列首元素确定行使权力
while radiant and dire:
if radiant[0] < dire[0]:
# dire.popleft()
# radiant.append(radiant.popleft() + n)
radiant.append(radiant[0] + n)
else:
# radiant.popleft()
# dire.append(dire.popleft() + n)
dire.append(dire[0] + n)
radiant.popleft()
dire.popleft()
return 'Radiant' if radiant else 'Dire'
欢迎关注
公众号 【书所集录】
如有错误,烦请指出,欢迎指点交流。