Precinct Night Desk
MediumOnline Assessment
Tally an election night from precinct reports that arrive, get corrected and get withdrawn, and decide whether the race can be called.
A county has the candidates in candidates and a set of precincts, each with the number of ballots that were cast there. Precincts phone in figures, one per candidate, as reports [precinct, candidate, votes], processed in the given order:
- A report naming an unknown precinct or candidate is ignored.
votes = -1withdraws the precinct's current figure for that candidate (nothing happens if there is none).- Otherwise
votes >= 0is a new figure that replaces the precinct's earlier figure for that candidate, if any. But a precinct cannot report more votes than ballots: if, with the new figure in place, the precinct's figures would add up to more than itsballots, the report is rejected and the previous figure (if any) stays.
A precinct is reporting only while it holds a figure for every candidate. Only reporting precincts count towards the totals; the figures of a half-reported precinct are held back. The outstanding count is the sum of ballots over precincts that are not reporting. The race is called for the leading candidate when their lead over the runner-up (the difference between the highest and second-highest totals, or the highest total if there is a single candidate) is strictly greater than the outstanding count; otherwise there is no call.
Input: candidates, a list of distinct names; precincts, a list of [name, ballots] with distinct names; reports, the list described above.
Output: a list of strings: "reporting R/P" (R reporting precincts out of P), "outstanding X", then "called NAME" or "no call", then one line "NAME TOTAL" per candidate sorted by total descending, ties by name in ascending alphabetical order. After the report lines are applied there is nothing else to do; the output reflects the final state.
Example 1
- Input:
- [["ash","bo"],[["oak",100],["elm",80]],[["oak","ash",60],["ghost","ash",5],["oak","bo",35],["elm","ash",50]]]
- Output:
- ["reporting 1/2","outstanding 80","no call","ash 60","bo 35"]
- Explanation
- The report for the unknown precinct
ghostis ignored. Oak holds both figures (60 + 35 = 95 ≤ 100), so it is reporting. Elm only has Ash's figure, so it is held back and its 80 ballots are outstanding. Ash leads 60 to 35; a lead of 25 is not greater than 80, so there is no call.
Example 2
- Input:
- [["ash","bo"],[["oak",100],["elm",100]],[["oak","ash",60],["oak","bo",30],["elm","ash",20],["elm","bo",70],["elm","bo",95],["oak","ash",62]]]
- Output:
- ["reporting 2/2","outstanding 0","called bo","bo 100","ash 82"]
- Explanation
- Elm first holds 20 and 70. Bo's 95 would make Elm's figures add up to 115 > 100, so that report is rejected and the 70 stays. Oak's Ash figure is corrected from 60 to 62. Both precincts are reporting, nothing is outstanding, and Bo (100) leads Ash (82) by 18 > 0, so the race is called for Bo.
Example 3
- Input:
- [["cy","ann"],[["north",50],["south",50]],[["north","cy",20],["north","ann",20],["south","cy",30],["south","ann",20],["north","cy",-1]]]
- Output:
- ["reporting 1/2","outstanding 50","no call","cy 30","ann 20"]
- Explanation
- After four reports both precincts are reporting, but then North's Cy figure is withdrawn, so North drops out and takes its votes with it. Outstanding is 50; South alone gives Cy 30 and Ann 20, a lead of 10, which is not greater than 50: no call.
Constraints
- 1 ≤ candidates.length ≤ 6; 1 ≤ precincts.length ≤ 40; 0 ≤ reports.length ≤ 300
- 0 ≤ ballots ≤ 106; -1 ≤ votes ≤ 106
- Names are non-empty strings of lowercase letters and digits