The "Rank Teams by Votes" problem asks you to determine the final ranking of teams based on votes from multiple voters. Each vote is a string where the order of characters represents the voter's ranking of the teams. For instance, in the vote "ABC"
, team 'A' is ranked 1st, 'B' is 2nd, and 'C' is 3rd by that voter.
The rules for ranking are as follows:
votes
(strings). Each string contains all team letters, and all votes are guaranteed to have the same length and contain the same set of teams (no duplicates or missing teams).
The output should be a single string representing the final ranking of teams from highest to lowest.
At first glance, the problem seems to require comparing the frequency of each team's appearances at each rank, position by position. A brute-force approach might involve comparing every team against every other team for each position, but this would be inefficient and difficult to maintain.
Instead, it's helpful to think about the problem as a sorting task, where the "key" for sorting each team is an array of counts: how many times was this team voted 1st, 2nd, 3rd, etc. This leads to a more efficient, structured approach:
Let's break down the solution into clear steps:
This approach leverages hash maps for fast counting and custom sorting for ranking, making it efficient and easy to follow.
Example Input:
votes = ["ABC", "ACB", "ABC", "ACB", "ACB"]
"ACB"
Brute-force Approach:
If you compared every team against every other team for every position, the complexity would be O(n^2 * k), where n is the number of teams and k is the number of positions. This would be inefficient for larger inputs.
Optimized Approach:
The "Rank Teams by Votes" problem is elegantly solved by counting each team's votes per position and sorting with a custom comparator that considers all positions and uses alphabetical order as a tiebreaker. This method is both efficient and easy to reason about, leveraging hash maps for counting and stable sorting for ranking. The clear separation of counting and sorting makes the solution robust and maintainable.
from collections import defaultdict
class Solution:
def rankTeams(self, votes):
if not votes:
return ""
n = len(votes[0])
count = defaultdict(lambda: [0]*n)
for vote in votes:
for i, team in enumerate(vote):
count[team][i] += 1
teams = list(votes[0])
teams.sort(key=lambda team: ([-c for c in count[team]], team))
return ''.join(teams)
#include <vector>
#include <string>
#include <unordered_map>
#include <algorithm>
using namespace std;
class Solution {
public:
string rankTeams(vector<string>& votes) {
if (votes.empty()) return "";
int n = votes[0].size();
unordered_map<char, vector<int>> count;
for (const string& vote : votes) {
for (int i = 0; i < n; ++i) {
count[vote[i]].resize(n, 0);
count[vote[i]][i]++;
}
}
vector<char> teams(votes[0].begin(), votes[0].end());
sort(teams.begin(), teams.end(), [&count, n](char a, char b) {
for (int i = 0; i < n; ++i) {
if (count[a][i] != count[b][i])
return count[a][i] > count[b][i];
}
return a < b;
});
return string(teams.begin(), teams.end());
}
};
import java.util.*;
class Solution {
public String rankTeams(String[] votes) {
if (votes.length == 0) return "";
int n = votes[0].length();
Map<Character, int[]> count = new HashMap<>();
for (String vote : votes) {
for (int i = 0; i < n; ++i) {
char team = vote.charAt(i);
count.putIfAbsent(team, new int[n]);
count.get(team)[i]++;
}
}
List<Character> teams = new ArrayList<>();
for (char c : votes[0].toCharArray()) teams.add(c);
teams.sort((a, b) -> {
for (int i = 0; i < n; ++i) {
if (count.get(a)[i] != count.get(b)[i])
return count.get(b)[i] - count.get(a)[i];
}
return a - b;
});
StringBuilder sb = new StringBuilder();
for (char c : teams) sb.append(c);
return sb.toString();
}
}
/**
* @param {string[]} votes
* @return {string}
*/
var rankTeams = function(votes) {
if (votes.length === 0) return "";
const n = votes[0].length;
const count = {};
for (const vote of votes) {
for (let i = 0; i < n; ++i) {
const team = vote[i];
if (!count[team]) count[team] = Array(n).fill(0);
count[team][i]++;
}
}
const teams = votes[0].split('');
teams.sort((a, b) => {
for (let i = 0; i < n; ++i) {
if (count[a][i] !== count[b][i])
return count[b][i] - count[a][i];
}
return a.localeCompare(b);
});
return teams.join('');
};