2284. Sender With Largest Word Count
Problem Description
You are given a chat log containing n
messages. The chat log is represented by two arrays:
messages
: An array wheremessages[i]
contains the text of the i-th messagesenders
: An array wheresenders[i]
contains the name of the person who sent the i-th message
Each message consists of words separated by single spaces, with no extra spaces at the beginning or end. Your task is to find which sender has sent the most total words across all their messages.
Key points to understand:
- A sender can send multiple messages
- The word count for a sender is the total number of words across ALL messages they sent
- To count words in a message, count the number of space-separated tokens (e.g., "hello world" has 2 words)
The goal is to return the name of the sender with the largest total word count. If multiple senders have the same highest word count, return the name that comes last lexicographically (the "largest" name when sorted alphabetically).
Important notes about lexicographical comparison:
- Uppercase letters come before lowercase letters (e.g., 'Z' < 'a')
- Names are case-sensitive (e.g., "Alice" and "alice" are treated as different senders)
For example, if Alice sends "hello world" (2 words) and "good morning everyone" (3 words), her total word count is 5. If Bob sends "hi there how are you" (5 words), and both have the highest count, you would return "Bob" since "Bob" > "Alice" lexicographically.
Intuition
The core challenge is to track the total word count for each sender across potentially multiple messages. Since a sender can appear multiple times in the senders
array with different messages, we need a way to accumulate their total word count.
A hash table (or dictionary) naturally fits this need - we can use the sender's name as the key and maintain a running total of their word count as the value. Each time we encounter a message from a sender, we add the word count of that message to their existing total.
To count words in a message, we observe that words are separated by single spaces. If a message has n
spaces, it contains n + 1
words. For example, "hello world" has 1 space and 2 words. This gives us an efficient way to count words: message.count(" ") + 1
.
Once we've built our word count mapping, we need to find the sender with the maximum word count. We iterate through all sender-count pairs and keep track of the best candidate so far. When comparing candidates, we first check the word count. If two senders have the same count, we choose the one with the lexicographically larger name using string comparison (ans < k
).
The algorithm essentially breaks down into two phases:
- Aggregation phase: Process all messages to build a complete word count for each sender
- Selection phase: Find the sender that satisfies our criteria (max word count, with lexicographic tiebreaker)
This approach is efficient because we only need to process each message once and then make a single pass through the aggregated data to find our answer.
Solution Approach
The solution uses a hash table to track word counts and then finds the sender with the maximum count through enumeration.
Step 1: Initialize the Counter
cnt = Counter()
We use Python's Counter
(a specialized dictionary) to store the word count for each sender. The keys will be sender names, and values will be their total word counts.
Step 2: Build Word Count Mapping
for message, sender in zip(messages, senders):
cnt[sender] += message.count(" ") + 1
We iterate through messages and senders simultaneously using zip()
. For each message:
- Count the number of spaces using
message.count(" ")
- Add 1 to get the total word count (since n spaces means n+1 words)
- Add this count to the sender's running total in the hash table
If a sender appears multiple times, their counts accumulate automatically.
Step 3: Initialize the Answer
ans = senders[0]
We start by assuming the first sender is our answer. This gives us a baseline for comparison.
Step 4: Find the Optimal Sender
for k, v in cnt.items(): if cnt[ans] < v or (cnt[ans] == v and ans < k): ans = k
We enumerate through all sender-count pairs in the hash table. For each sender k
with word count v
:
- Update
ans
tok
if:- The current sender has more words than our current answer (
cnt[ans] < v
), OR - They have the same word count BUT their name is lexicographically larger (
cnt[ans] == v and ans < k
)
- The current sender has more words than our current answer (
The condition ans < k
performs lexicographic comparison where the "smaller" string comes first alphabetically, so we want to update when we find a "larger" name.
Step 5: Return the Result
return ans
After checking all senders, ans
contains the name of the sender with the most words (with lexicographic tiebreaking).
Time Complexity: O(n * m)
where n
is the number of messages and m
is the average message length (for counting spaces)
Space Complexity: O(k)
where k
is the number of unique senders
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Input:
messages = ["Hi there", "Good morning everyone", "Hello", "How are you today"]
senders = ["Alice", "Bob", "Alice", "Bob"]
Step 1: Initialize the Counter
We start with an empty counter: cnt = {}
Step 2: Build Word Count Mapping
Processing each message-sender pair:
-
Message 0: "Hi there" from Alice
- Word count: 1 space + 1 = 2 words
cnt = {"Alice": 2}
-
Message 1: "Good morning everyone" from Bob
- Word count: 2 spaces + 1 = 3 words
cnt = {"Alice": 2, "Bob": 3}
-
Message 2: "Hello" from Alice
- Word count: 0 spaces + 1 = 1 word
- Alice already exists, so we add to her total
cnt = {"Alice": 3, "Bob": 3}
-
Message 3: "How are you today" from Bob
- Word count: 3 spaces + 1 = 4 words
- Bob already exists, so we add to his total
cnt = {"Alice": 3, "Bob": 7}
Step 3: Initialize the Answer
Start with the first sender: ans = "Alice"
Step 4: Find the Optimal Sender
Iterate through the counter:
- Check Alice (3 words): She's already our answer, skip
- Check Bob (7 words):
- Compare:
cnt["Alice"] = 3
<7
? Yes! - Update:
ans = "Bob"
- Compare:
Step 5: Return the Result Return "Bob" as the sender with the most words (7 total words)
Another example with lexicographic tiebreaking:
If we had:
messages = ["One two three", "Four five six"]
senders = ["Charlie", "Alice"]
After processing:
cnt = {"Charlie": 3, "Alice": 3}
When finding the optimal sender:
- Start with
ans = "Charlie"
- Check Alice (3 words):
cnt["Charlie"] = 3
equals3
, and "Charlie" > "Alice" lexicographically - Keep
ans = "Charlie"
(no update needed)
Return "Charlie" because when tied at 3 words each, "Charlie" comes after "Alice" alphabetically.
Solution Implementation
1from typing import List
2from collections import Counter
3
4class Solution:
5 def largestWordCount(self, messages: List[str], senders: List[str]) -> str:
6 # Dictionary to store word count for each sender
7 word_count = Counter()
8
9 # Calculate word count for each sender
10 for message, sender in zip(messages, senders):
11 # Count words by counting spaces and adding 1
12 word_count[sender] += message.count(" ") + 1
13
14 # Initialize result with the first sender
15 result = senders[0]
16
17 # Find sender with maximum word count
18 # If tied, return the lexicographically larger name
19 for sender, count in word_count.items():
20 if word_count[result] < count or (word_count[result] == count and result < sender):
21 result = sender
22
23 return result
24
1class Solution {
2 public String largestWordCount(String[] messages, String[] senders) {
3 // Map to store the total word count for each sender
4 Map<String, Integer> wordCountMap = new HashMap<>(senders.length);
5
6 // Calculate word count for each message and accumulate by sender
7 for (int i = 0; i < messages.length; i++) {
8 // Count words in current message (words = spaces + 1)
9 int wordCount = 1;
10 for (int j = 0; j < messages[i].length(); j++) {
11 if (messages[i].charAt(j) == ' ') {
12 wordCount++;
13 }
14 }
15
16 // Add word count to sender's total using merge method
17 // If sender exists, add to existing count; otherwise, set initial count
18 wordCountMap.merge(senders[i], wordCount, Integer::sum);
19 }
20
21 // Initialize result with the first sender
22 String result = senders[0];
23
24 // Find sender with maximum word count
25 // If tied, choose lexicographically larger name
26 for (Map.Entry<String, Integer> entry : wordCountMap.entrySet()) {
27 String currentSender = entry.getKey();
28 int currentWordCount = entry.getValue();
29
30 // Update result if current sender has more words
31 // OR has same word count but lexicographically larger name
32 if (wordCountMap.get(result) < currentWordCount ||
33 (wordCountMap.get(result) == currentWordCount && result.compareTo(currentSender) < 0)) {
34 result = currentSender;
35 }
36 }
37
38 return result;
39 }
40}
41
1class Solution {
2public:
3 string largestWordCount(vector<string>& messages, vector<string>& senders) {
4 // Map to store word count for each sender
5 unordered_map<string, int> wordCountMap;
6
7 // Calculate word count for each message and accumulate by sender
8 for (int i = 0; i < messages.size(); ++i) {
9 // Count words by counting spaces and adding 1
10 int wordCount = count(messages[i].begin(), messages[i].end(), ' ') + 1;
11 wordCountMap[senders[i]] += wordCount;
12 }
13
14 // Initialize result with the first sender
15 string result = senders[0];
16
17 // Find sender with maximum word count
18 // If tied, choose lexicographically larger name
19 for (auto& [sender, count] : wordCountMap) {
20 if (wordCountMap[result] < count ||
21 (wordCountMap[result] == count && result < sender)) {
22 result = sender;
23 }
24 }
25
26 return result;
27 }
28};
29
1/**
2 * Finds the sender with the largest total word count across all their messages.
3 * If there's a tie, returns the lexicographically larger sender name.
4 *
5 * @param messages - Array of messages where each message contains space-separated words
6 * @param senders - Array of sender names corresponding to each message
7 * @returns The name of the sender with the most total words
8 */
9function largestWordCount(messages: string[], senders: string[]): string {
10 // Map to store the total word count for each sender
11 const wordCountBySender: Record<string, number> = {};
12
13 // Calculate total word count for each sender
14 for (let i = 0; i < messages.length; i++) {
15 // Count words in current message by splitting on spaces
16 const wordCount: number = messages[i].split(' ').length;
17
18 // Add word count to sender's total (initialize to 0 if first occurrence)
19 wordCountBySender[senders[i]] = (wordCountBySender[senders[i]] || 0) + wordCount;
20 }
21
22 // Initialize result with the first sender
23 let result: string = senders[0];
24
25 // Find sender with maximum word count
26 for (const sender in wordCountBySender) {
27 // Update result if current sender has more words,
28 // or same word count but lexicographically larger name
29 if (wordCountBySender[result] < wordCountBySender[sender] ||
30 (wordCountBySender[result] === wordCountBySender[sender] && result < sender)) {
31 result = sender;
32 }
33 }
34
35 return result;
36}
37
Time and Space Complexity
The time complexity is O(n + L)
, where n
is the number of messages and L
is the total length of all messages.
- The
zip(messages, senders)
operation iterates throughn
messages:O(n)
- For each message,
message.count(" ")
scans through the entire message to count spaces, which takes time proportional to the length of that message - The total time for counting spaces across all messages is
O(L)
whereL
is the sum of lengths of all messages - The second loop iterates through the Counter dictionary which has at most
n
entries (one per unique sender):O(n)
- Overall time complexity:
O(n + L)
The space complexity is O(n)
, where n
is the number of messages.
- The
Counter
objectcnt
stores at mostn
key-value pairs (in the worst case, each message has a unique sender) - The variable
ans
stores a single string reference:O(1)
- The space used by the Counter is dominant:
O(n)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Word Counting Logic
Pitfall: Attempting to count words using split()
or other methods instead of counting spaces.
# WRONG - This creates unnecessary overhead
word_count[sender] += len(message.split())
While split()
works correctly, it's less efficient as it creates a list of all words. Counting spaces and adding 1 is more memory-efficient.
2. Misunderstanding Lexicographical Comparison
Pitfall: Incorrectly implementing the tiebreaker logic when multiple senders have the same word count.
# WRONG - Returns lexicographically smaller name if word_count[result] < count or (word_count[result] == count and result > sender): result = sender
The problem asks for the lexicographically larger name when there's a tie. Remember that in Python, "Bob" > "Alice"
evaluates to True
, and we want "Bob" in this case.
3. Not Handling Case Sensitivity
Pitfall: Converting names to lowercase or uppercase for comparison.
# WRONG - Loses case sensitivity word_count[sender.lower()] += message.count(" ") + 1
The problem explicitly states that names are case-sensitive. "Alice" and "alice" should be treated as different senders.
4. Incorrect Initialization of Result
Pitfall: Not initializing the result variable properly or using an empty string.
# WRONG - What if this sender doesn't exist in word_count? result = "" # or result = None
Always initialize with a valid sender name (like senders[0]
) to ensure proper comparison in the loop.
5. Edge Case with Empty Messages
Pitfall: Not considering that a message might be a single word with no spaces.
# This actually works correctly! message.count(" ") + 1 # For "hello", returns 0 + 1 = 1 word
The space-counting approach handles single-word messages correctly, but developers might overthink and add unnecessary edge case handling.
Corrected Solution Approach:
def largestWordCount(self, messages: List[str], senders: List[str]) -> str:
word_count = Counter()
# Build word counts correctly
for message, sender in zip(messages, senders):
word_count[sender] += message.count(" ") + 1
# Find maximum with correct lexicographical tiebreaking
max_sender = None
max_count = 0
for sender, count in word_count.items():
if count > max_count or (count == max_count and (max_sender is None or sender > max_sender)):
max_sender = sender
max_count = count
return max_sender
Which of the following is a min heap?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!