In the world of Dota2, there are two parties: the Radiant and the Dire.
The Dota2 senate consists of senators coming from two parties. Now the Senate wants to decide on a change in the Dota2 game. The voting for this change is a round-based procedure. In each round, each senator can exercise one of the two rights:
Ban one senator's right: A senator can make another senator lose all his rights in this and all the following rounds.
Announce the victory: If this senator found the senators who still have rights to vote are all from the same party, he can announce the victory and decide on the change in the game.
You are given a string senate representing each senator's party belonging. The character 'R' and 'D' represent the Radiant party and the Dire party. Then if there are n senators, the size of the given string will be n.
The round-based procedure starts from the first senator to the last senator in the given order. This procedure will last until the end of voting. All the senators who have lost their rights will be skipped during the procedure.
Suppose every senator is smart enough and will play the best strategy for his own party. Predict which party will finally announce the victory and change the Dota2 game. The output should be "Radiant" or "Dire".
Example 1:
Input: senate = "RRDDD"
Output: "Radiant"Explanation:
Example 2:
Input: senate = "RDD"
Output: "Dire"Constraints:
1 <= senate.length <= 10,000senate[i] is either 'R' or 'D'.Before attempting this problem, you should be comfortable with:
We can simulate the voting process directly. Each senator, when it's their turn, will ban the next opposing senator in the circular order. We keep iterating through the remaining senators until only one party remains. This approach mirrors the problem's rules exactly but requires repeatedly scanning the list to find and remove opponents.
i:i.class Solution:
def predictPartyVictory(self, senate: str) -> str:
s = list(senate)
while True:
i = 0
while i < len(s):
if 'R' not in s:
return "Dire"
if 'D' not in s:
return "Radiant"
if s[i] == 'R':
j = (i + 1) % len(s)
while s[j] == 'R':
j = (j + 1) % len(s)
s.pop(j)
if j < i:
i -= 1
else:
j = (i + 1) % len(s)
while s[j] == 'D':
j = (j + 1) % len(s)
s.pop(j)
if j < i:
i -= 1
i += 1The key insight is that a senator should always ban the nearest opposing senator who would otherwise act before them. We use two queues to track the positions of Radiant and Dire senators. When comparing the front of both queues, the senator with the smaller index acts first and bans the other. The surviving senator then re-enters at the end of the queue with an updated index (adding n to represent the next round).
R and D to store indices of Radiant and Dire senators.+ n.R queue is non-empty, otherwise "Dire".class Solution:
def predictPartyVictory(self, senate: str) -> str:
D, R = deque(), deque()
n = len(senate)
for i, c in enumerate(senate):
if c == 'R':
R.append(i)
else:
D.append(i)
while D and R:
dTurn = D.popleft()
rTurn = R.popleft()
if rTurn < dTurn:
R.append(rTurn + n)
else:
D.append(dTurn + n)
return "Radiant" if R else "Dire"We can track pending bans using a single counter. When we encounter a Radiant senator (R), they either get banned by a waiting Dire (if cnt < 0) or they ban a future Dire senator. Similarly, Dire senators either get banned or ban future Radiant senators. The twist is that when a senator is banned, their surviving opponent is appended to the end to act again in future rounds.
cnt = 0.R:cnt < 0, a Dire senator bans them; append D to the end.cnt (representing a pending Radiant action).D:cnt > 0, a Radiant senator bans them; append R to the end.cnt (representing a pending Dire action).cnt > 0, Radiant wins; otherwise, Dire wins.class Solution:
def predictPartyVictory(self, senate: str) -> str:
senate = list(senate)
cnt = i = 0
while i < len(senate):
c = senate[i]
if c == 'R':
if cnt < 0:
senate.append('D')
cnt += 1
else:
if cnt > 0:
senate.append('R')
cnt -= 1
i += 1
return "Radiant" if cnt > 0 else "Dire"The senate voting is circular, meaning after the last senator votes, it wraps back to the first. A banned senator in round 1 could have banned someone who would act later in the same round or in subsequent rounds.
# Wrong: Only considering senators ahead in the array
j = i + 1
while j < len(s) and s[j] == s[i]:
j += 1
# Correct: Circular wrap-around
j = (i + 1) % len(s)
while s[j] == s[i]:
j = (j + 1) % len(s)Each senator should optimally ban the nearest opposing senator who would otherwise act before them in the next round. Banning a distant opponent wastes the opportunity and may lead to suboptimal outcomes.
# Wrong strategy: Banning any random opponent
# Correct strategy: Ban the next opponent in circular orderIn the queue-based approach, when a senator bans an opponent, the survivor must be re-added to the queue to vote again in future rounds. The index must be incremented by n to maintain proper ordering.
# Wrong: Not re-adding the survivor
if rTurn < dTurn:
pass # R survives but isn't re-added
# Correct: Re-add survivor with updated index
if rTurn < dTurn:
R.append(rTurn + n)