Notes & software courses · Free to learn
Aph's Blog

LC649 Dota2 Senate 🟡

👋 อ่านฟรีทั้งหมดบน Aph's Blog — เนื้อหาภาษาไทย ทำตามทีละหน้าใน sidebar ได้เลย หากมีข้อเสนอแนะหรืออยากให้เพิ่มหัวข้อไหน บอกได้เสมอ

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.

Example 1
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.
Example 2
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.
Constraints (ข้อจำกัด)
  • 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:

  1. Prepare — iterate senate, push each index into radiant or dire.
  2. Face off — popleft the front of both queues to get r and d.
  3. 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.
  4. Game over — when one queue empties, the other party wins.

3. LeetCode-Ready Code

Convert the two-queue rules into code:

Submit this on LeetCodepython
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

TurnFace-offWho bansBannedSurvivor re-enqueuesradiant (front…back)dire (front…back)Still active
1R0 vs D1R0 first → bans D1D1R0 becomes 0+3=332R0 · D2
2R3 vs D2D2 first → bans R3R3D2 becomes 2+3=5[]5D2
Endradiant empty[]5Dire 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.
Why add n?

Survivors act after everyone in the current round. Adding n keeps them behind all current-round senators while still ordering correctly among themselves.

Never use list.pop(0)

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.
💡 Pattern summary

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.