The Winning Candidate problem describes an election scenario where you are given a list of votes, and each vote is represented by a string indicating the candidate's name. The task is to determine which candidate received the most votes. If there is a tie (two or more candidates have the highest number of votes), the winner is the candidate whose name comes last in lexicographical (dictionary) order.
votes
, where each string is a candidate's name.The core of this problem is to count how many votes each candidate received, then select the candidate(s) with the most votes. If there is a tie, we need a way to break it—specifically, by picking the candidate whose name is lexicographically last.
The naive (brute-force) approach would be to count the votes for each candidate by iterating over the list for each unique candidate, but this is inefficient. Instead, we can use a hash map (dictionary) to tally votes efficiently in a single pass.
Once we've counted the votes, we need to identify the winner. If several candidates have the same count, we compare their names to find the lexicographically last one.
Let's break down the steps for solving this problem efficiently:
votes
list. This allows us to tally votes in O(n) time, where n is the number of votes.
We use a hash map for counting because it provides O(1) insertion and lookup, making the solution efficient. For the tie-breaker, comparing strings is straightforward and built-in for all major languages.
Let's consider the following example:
votes = ["Alice", "Bob", "Alice", "David", "Bob", "Bob", "Alice"]
This step-by-step process ensures we correctly identify the winner, even in the case of a tie.
Brute-force approach: For each unique candidate, count their votes by iterating over the entire list. If there are k unique candidates and n votes, this is O(k * n) time and O(k) space.
Optimized approach:
To solve the Winning Candidate problem, we efficiently count votes using a hash map, then select the candidate(s) with the highest count, breaking ties using lexicographical order. This approach is both fast and memory-efficient, and leverages built-in data structures for clarity and simplicity. The solution is elegant because it combines counting and tie-breaking in a single, clear process.
def winningCandidate(votes):
from collections import Counter
counts = Counter(votes)
max_votes = max(counts.values())
winners = [name for name, cnt in counts.items() if cnt == max_votes]
return max(winners)
#include <string>
#include <vector>
#include <unordered_map>
#include <algorithm>
std::string winningCandidate(const std::vector<std::string>& votes) {
std::unordered_map<std::string, int> counts;
for (const auto& name : votes) {
counts[name]++;
}
int max_votes = 0;
for (const auto& entry : counts) {
if (entry.second > max_votes) {
max_votes = entry.second;
}
}
std::string winner = "";
for (const auto& entry : counts) {
if (entry.second == max_votes) {
if (winner == "" || entry.first > winner) {
winner = entry.first;
}
}
}
return winner;
}
import java.util.*;
public class Solution {
public String winningCandidate(String[] votes) {
HashMap<String, Integer> counts = new HashMap<>();
for (String name : votes) {
counts.put(name, counts.getOrDefault(name, 0) + 1);
}
int maxVotes = 0;
for (int cnt : counts.values()) {
if (cnt > maxVotes) {
maxVotes = cnt;
}
}
String winner = "";
for (String name : counts.keySet()) {
if (counts.get(name) == maxVotes) {
if (winner.equals("") || name.compareTo(winner) > 0) {
winner = name;
}
}
}
return winner;
}
}
function winningCandidate(votes) {
const counts = {};
for (const name of votes) {
counts[name] = (counts[name] || 0) + 1;
}
let maxVotes = 0;
for (const cnt of Object.values(counts)) {
if (cnt > maxVotes) maxVotes = cnt;
}
let winner = "";
for (const name in counts) {
if (counts[name] === maxVotes) {
if (winner === "" || name > winner) {
winner = name;
}
}
}
return winner;
}