LC649 Dota2 Senate 🟡
Two parties ban each other round by round — use two queues to track indices and let survivors re-enqueue for the next round.
In the world of Dota2, there are two parties: Radiant and Dire.
The senate consists of senators from both parties. They vote in rounds. In each round, each active senator can exercise one of two rights:
1. **Ban one senator's right** — make another senator lose all rights in this and all future rounds.
2. **Announce victory** — if all remaining active senators belong to the same party.
Given a string `senate` where each character is `'R'` (Radiant) or `'D'` (Dire), predict which party will win. Every senator plays optimally for their own party. Senators act in order from first to last, skipping those who have lost their rights.
- Input:
- senate = "RD"
- Output:
- "Radiant"
- Explanation:
- Explanation:
The first senator comes from Radiant and bans the next senator's right in round 1.
The second senator can't exercise any rights anymore.
In round 2, the first senator announces victory since he is the only one left.
- Input:
- senate = "RDD"
- Output:
- "Dire"
- Explanation:
- Explanation:
The first senator (R) bans the second senator (D) in round 1.
The third senator (D) bans the first senator (R) in round 1.
In round 2, the third senator announces victory since he is the only one left.
- n == senate.length
- 1 <= n <= 10^4
- senate[i] is either 'R' or 'D'.
Full solution · Try yourself firstพับไว้ด้านใน — คลิกเมื่อพร้อมดู
This maps to the Queue pattern: "Process in order — whoever comes first gets to ban first."
1. Mindset Shift
Imagine two separate queues — one for Radiant, one for Dire — each storing the index (seating position) of active senators.
Key insight: the best strategy is always to ban the nearest opponent. In each round, compare the front of both queues. The senator with the smaller index (comes first) bans the other. The survivor re-enqueues with index + n to preserve round order.
Why add n? After round 1, survivors should go behind everyone still in the current round. Adding n ensures correct ordering across rounds.
2. The Logic — 4 Steps
Start two queues and play until one side empties:
- Prepare — iterate senate, push each index into radiant or dire.
- Face off — popleft the front of both queues to get r and d.
- Ban + re-enqueue — if r < d: R bans D, re-enqueue r + n into radiant. Else: D bans R, re-enqueue d + n into dire.
- Game over — when one queue empties, the other party wins.
3. LeetCode-Ready Code
Convert the two-queue rules into code:
from collections import deque
class Solution:
def predictPartyVictory(self, senate: str) -> str:
n = len(senate)
radiant = deque() # store indices of R senators
dire = deque() # store indices of D senators
# Step 1: prepare queues
for i, c in enumerate(senate):
if c == "R":
radiant.append(i)
else:
dire.append(i)
# Steps 2–3: face off until one side empties
while radiant and dire:
r = radiant.popleft()
d = dire.popleft()
# smaller index comes first = gets to ban
if r < d:
radiant.append(r + n) # R survives, re-enqueue for next round
else:
dire.append(d + n) # D survives, re-enqueue for next round
# Step 4: the non-empty queue wins
return "Radiant" if radiant else "Dire"4. Dry Run — senate = "RDD"
n = 3 · Start: senate = R0 D1 D2 · radiant = 0 · dire = 1 → 2
| Turn | Face-off | Who bans | Banned | Survivor re-enqueues | radiant (front…back) | dire (front…back) | Still active |
|---|---|---|---|---|---|---|---|
| 1 | R0 vs D1 | R0 first → bans D1 | D1 | R0 becomes 0+3=3 | 3 | 2 | R0 · D2 |
| 2 | R3 vs D2 | D2 first → bans R3 | R3 | D2 becomes 2+3=5 | [] | 5 | D2 |
| End | radiant empty | — | — | — | [] | 5 | Dire wins |
Left of each queue = front (acts first) · +n = send survivor to the back of the next round so they don't cut ahead of anyone still waiting this round. Answer: "Dire".
5. Edge Cases & Pitfalls
The "forgot +n" mistake — most common error:
- If you re-enqueue r instead of r + n, the survivor gets the same small index.
- They'll jump ahead of senators who haven't played this round yet — wrong order, wrong answer.
Survivors act after everyone in the current round. Adding n keeps them behind all current-round senators while still ordering correctly among themselves.
list.pop(0) is O(n). Always use deque.popleft() for O(1).
6. Time & Space Complexity
- Time O(n) — each senator is banned at most once; each comparison eliminates one person.
- Space O(n) — store every senator's index in the two queues.
When a problem involves "round-based competition with re-entry", use queues to simulate the process. Let survivors re-enqueue with index + n to maintain correct round ordering. Comparing the front of two queues is a common pattern for head-to-head elimination games.