Evaluate word-guess feedback with repeats
Company: Patreon
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates string manipulation, multiset/frequency tracking, and stateful validation across rounds, with particular emphasis on handling repeated letters and multiplicity constraints in feedback generation.
Part 1: Produce feedback for one guess
Constraints
- 1 <= len(guess) == len(target) <= 100000
- Both strings contain only lowercase English letters.
Examples
Input: ('cable', 'maple')
Expected Output: 'WGWGG'
Explanation: `a`, `l`, and `e` are exact matches. The remaining target letters are `m` and `p`, so `c` and `b` are both `W`.
Input: ('apple', 'maple')
Expected Output: 'YWGGG'
Explanation: After reserving the green `p`, `l`, and `e`, only one `a` remains available for yellow. The first `a` is `Y`, but the extra `p` becomes `W`.
Input: ('aaaa', 'abca')
Expected Output: 'GWWG'
Explanation: The `a` at positions 0 and 3 are green. The two middle `a` characters cannot be yellow because all `a` occurrences in target are already used.
Input: ('bca', 'cab')
Expected Output: 'YYY'
Explanation: No letters are in the correct position, but each guessed letter appears elsewhere in the target.
Input: ('a', 'b')
Expected Output: 'W'
Explanation: Single-character edge case: the letter does not appear in the target.
Solution
def solution(guess, target):
n = len(guess)
counts = [0] * 26
result = ['W'] * n
for i in range(n):
if guess[i] == target[i]:
result[i] = 'G'
else:
counts[ord(target[i]) - 97] += 1
for i in range(n):
if result[i] == 'G':
continue
idx = ord(guess[i]) - 97
if counts[idx] > 0:
result[i] = 'Y'
counts[idx] -= 1
return ''.join(result)
Time complexity: O(n). Space complexity: O(1) auxiliary space (excluding the output string).
Hints
- First mark every exact match as `G`. Those target positions cannot be reused for `Y`.
- Count only the letters from target that were not matched as `G`, then scan the remaining guess positions and assign `Y` while decrementing counts.
Part 2: Validate future guesses using past information
Constraints
- 1 <= len(target) <= 100000
- 0 <= len(guesses)
- Each guess contains only lowercase English letters and has length equal to len(target).
- The sum of lengths of all guesses is at most 200000.
Examples
Input: ('maple', ['cable', 'cazle', 'zzzzz'])
Expected Output: ['WGWGG', 'invalid_input', 'WWWWW']
Explanation: After `cable`, letters `c` and `b` are confirmed absent. `cazle` is invalid because it contains `c`. Invalid guesses do not teach anything, so `zzzzz` is still evaluated normally.
Input: ('abca', ['aaaa', 'dada'])
Expected Output: ['GWWG', 'WYWG']
Explanation: In round 1, letter `a` is not confirmed absent because it has green positions. Therefore round 2 is valid even though it contains `a`.
Input: ('maple', ['zzzzz', 'fuzzy'])
Expected Output: ['WWWWW', 'invalid_input']
Explanation: All `z` characters are white in round 1, so `z` is confirmed absent. The next guess is invalid because it contains `z`.
Input: ('a', ['b', 'a', 'b'])
Expected Output: ['W', 'G', 'invalid_input']
Explanation: Single-character edge case: after the first round, `b` is known to be absent, so the third guess is invalid.
Input: ('abc', [])
Expected Output: []
Explanation: No guesses means no rounds to evaluate.
Solution
def solution(target, guesses):
n = len(target)
def feedback(guess):
counts = [0] * 26
result = ['W'] * n
for i in range(n):
if guess[i] == target[i]:
result[i] = 'G'
else:
counts[ord(target[i]) - 97] += 1
for i in range(n):
if result[i] == 'G':
continue
idx = ord(guess[i]) - 97
if counts[idx] > 0:
result[i] = 'Y'
counts[idx] -= 1
return ''.join(result)
absent = [False] * 26
answers = []
for guess in guesses:
invalid = False
for ch in guess:
if absent[ord(ch) - 97]:
invalid = True
break
if invalid:
answers.append('invalid_input')
continue
status = feedback(guess)
answers.append(status)
seen = [False] * 26
has_non_white = [False] * 26
for ch, mark in zip(guess, status):
idx = ord(ch) - 97
seen[idx] = True
if mark != 'W':
has_non_white[idx] = True
for idx in range(26):
if seen[idx] and not has_non_white[idx]:
absent[idx] = True
return answers
Time complexity: O(total_characters_in_all_guesses). Space complexity: O(1) auxiliary space (excluding the returned list and feedback strings).
Hints
- Keep a set or 26-length boolean array for letters already proven absent. Check that before evaluating each new guess.
- To decide which letters become absent after a valid round, look at each distinct letter in that guess: if none of its positions were marked `G` or `Y`, then that letter is confirmed absent.