LeetCode 3921 - Score Validator
This problem asks us to simulate a simple scoring system while processing a sequence of event strings from left to right. We are given an array called events, where each element represents one event.
Difficulty: 🟢 Easy
Topics: Array, String, Simulation
Solution
LeetCode 3921 - Score Validator
Problem Understanding
This problem asks us to simulate a simple scoring system while processing a sequence of event strings from left to right.
We are given an array called events, where each element represents one event. Two variables are maintained throughout the simulation:
score, initially0counter, initially0
Each event affects these variables according to predefined rules:
"0","1","2","3","4", and"6"add their numeric value toscore."W"increasescounterby1and does not affectscore."WD"adds1toscore."NB"adds1toscore.
The events must be processed in order. However, processing does not always continue until the end of the array. We stop as soon as one of the following conditions becomes true:
- Every event has been processed.
counterreaches10.
The final answer is an array containing:
[score, counter]
where score is the total accumulated score and counter is the final counter value.
The constraints are very small:
1 <= events.length <= 1000- Every event is guaranteed to be one of the valid strings listed in the statement.
Because there are at most 1000 events, even a straightforward simulation is easily fast enough.
Some important edge cases include situations where the counter reaches 10 before the array ends, arrays consisting entirely of scoring events with no "W" events, and arrays where the first few events immediately push the counter to 10. The problem guarantees that every event string is valid, so we never need to handle unexpected input values.
Approaches
Brute Force Approach
The most direct approach is to simulate the process exactly as described.
We initialize score = 0 and counter = 0, then iterate through the array from left to right. For each event, we apply the corresponding rule:
- Add numeric values for score events.
- Increment the counter for
"W". - Add one point for
"WD"and"NB".
After processing each event, we check whether the counter has reached 10. If it has, we stop immediately and ignore all remaining events.
This approach is correct because it follows the problem statement exactly. Since each event is examined once, it is already efficient enough for the given constraints.
Key Insight
There is no hidden optimization or advanced data structure required. The problem is fundamentally a simulation problem.
The key observation is that each event affects only the current state (score and counter), and the result depends on processing events in order. Therefore, a single linear scan through the array is both natural and optimal.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n) | O(1) | Simulate every event sequentially |
| Optimal | O(n) | O(1) | Same simulation, already optimal |
Algorithm Walkthrough
- Initialize
score = 0andcounter = 0. - Iterate through each event in
eventsfrom left to right. - For the current event:
- If it is
"W", incrementcounterby 1. - If it is
"WD"or"NB", add 1 toscore. - Otherwise, the event is one of the digit strings, so convert it to an integer and add it to
score.
- After processing the event, check whether
counterhas reached 10. - If
counter == 10, stop processing immediately because the problem explicitly states that processing ends when the counter becomes 10. - Continue until either all events have been processed or processing stops early.
- Return
[score, counter].
Why it works
The algorithm maintains the exact state required by the problem definition. After processing each event, score equals the total score contributed by all processed scoring events, and counter equals the number of processed "W" events. Since events are handled in order and processing stops immediately when counter reaches 10, the final state exactly matches the specification. Therefore, the returned result is correct.
Python Solution
class Solution:
def scoreValidator(self, events: list[str]) -> list[int]:
score = 0
counter = 0
for event in events:
if event == "W":
counter += 1
elif event == "WD" or event == "NB":
score += 1
else:
score += int(event)
if counter == 10:
break
return [score, counter]
The implementation directly follows the simulation described in the algorithm.
The variables score and counter store the current state. The loop processes each event one at a time. A series of conditional checks determines which rule applies to the current event. Numeric events are converted using int(event) because the problem guarantees that any remaining valid string in this branch is one of the allowed digit values.
After every event is processed, the code checks whether the counter has reached 10. If so, break immediately terminates the loop, ensuring that all remaining events are ignored exactly as required.
Finally, the method returns the two values in the requested format.
Go Solution
func scoreValidator(events []string) []int {
score := 0
counter := 0
for _, event := range events {
if event == "W" {
counter++
} else if event == "WD" || event == "NB" {
score++
} else {
score += int(event[0] - '0')
}
if counter == 10 {
break
}
}
return []int{score, counter}
}
The Go implementation follows the same logic as the Python version.
One small Go-specific optimization is that numeric events are single-character strings, so instead of using string-to-integer conversion functions, we can obtain the numeric value using:
int(event[0] - '0')
This avoids additional parsing overhead. Integer overflow is not a concern because the maximum possible score is very small relative to Go's integer range. The returned result is represented as a slice containing exactly two integers.
Worked Examples
Example 1
Input:
["1","4","W","6","WD"]
| Event | Score Before | Counter Before | Action | Score After | Counter After |
|---|---|---|---|---|---|
| "1" | 0 | 0 | Add 1 | 1 | 0 |
| "4" | 1 | 0 | Add 4 | 5 | 0 |
| "W" | 5 | 0 | Counter +1 | 5 | 1 |
| "6" | 5 | 1 | Add 6 | 11 | 1 |
| "WD" | 11 | 1 | Add 1 | 12 | 1 |
Final result:
[12, 1]
Example 2
Input:
["WD","NB","0","4","4"]
| Event | Score Before | Counter Before | Action | Score After | Counter After |
|---|---|---|---|---|---|
| "WD" | 0 | 0 | Add 1 | 1 | 0 |
| "NB" | 1 | 0 | Add 1 | 2 | 0 |
| "0" | 2 | 0 | Add 0 | 2 | 0 |
| "4" | 2 | 0 | Add 4 | 6 | 0 |
| "4" | 6 | 0 | Add 4 | 10 | 0 |
Final result:
[10, 0]
Example 3
Input:
["W","W","W","W","W","W","W","W","W","W","W"]
| Step | Event | Score | Counter |
|---|---|---|---|
| 1 | W | 0 | 1 |
| 2 | W | 0 | 2 |
| 3 | W | 0 | 3 |
| 4 | W | 0 | 4 |
| 5 | W | 0 | 5 |
| 6 | W | 0 | 6 |
| 7 | W | 0 | 7 |
| 8 | W | 0 | 8 |
| 9 | W | 0 | 9 |
| 10 | W | 0 | 10 |
At this point the counter reaches 10, so processing stops immediately.
Final result:
[0, 10]
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each event is processed at most once |
| Space | O(1) | Only a few integer variables are stored |
The algorithm performs a single pass through the input array. Every event requires only constant-time work, so the running time is linear in the number of events. The amount of extra memory remains constant regardless of input size because only score and counter are maintained.
Test Cases
sol = Solution()
assert sol.scoreValidator(["1", "4", "W", "6", "WD"]) == [12, 1] # Example 1
assert sol.scoreValidator(["WD", "NB", "0", "4", "4"]) == [10, 0] # Example 2
assert sol.scoreValidator(["W"] * 11) == [0, 10] # Example 3, early stop
assert sol.scoreValidator(["0"]) == [0, 0] # Single zero event
assert sol.scoreValidator(["6"]) == [6, 0] # Single scoring event
assert sol.scoreValidator(["WD"]) == [1, 0] # Single WD event
assert sol.scoreValidator(["NB"]) == [1, 0] # Single NB event
assert sol.scoreValidator(["W"]) == [0, 1] # Single wicket
assert sol.scoreValidator(
["W","W","W","W","W","W","W","W","W","W","6"]
) == [0, 10] # Events after tenth W ignored
assert sol.scoreValidator(
["1","2","3","4","6"]
) == [16, 0] # All numeric scoring events
assert sol.scoreValidator(
["WD","NB","WD","NB"]
) == [4, 0] # Only bonus scoring events
assert sol.scoreValidator(
["6","W","4","WD","NB","2"]
) == [14, 1] # Mixed events
assert sol.scoreValidator(
["W"] * 10
) == [0, 10] # Counter reaches exactly 10 at end
assert sol.scoreValidator(
["W"] * 10 + ["6", "6", "6"]
) == [0, 10] # Remaining events ignored after stop
Test Summary
| Test | Why |
|---|---|
["1","4","W","6","WD"] |
Validates basic mixed processing |
["WD","NB","0","4","4"] |
Validates bonus and numeric scoring |
["W"] * 11 |
Validates early termination |
["0"] |
Smallest scoring value |
["6"] |
Largest scoring value |
["WD"] |
Single bonus event |
["NB"] |
Single bonus event variant |
["W"] |
Single counter increment |
| Ten W events then score events | Ensures ignored suffix after stop |
| All numeric events | Verifies digit handling |
| All bonus events | Verifies repeated score additions |
| Mixed event sequence | General correctness test |
| Exactly ten W events | Boundary condition |
| Ten W events plus extras | Early stop correctness |
Edge Cases
Counter Reaches 10 Before the End of the Array
A common bug is continuing to process events even after the counter reaches 10. For example:
["W","W","W","W","W","W","W","W","W","W","6"]
The final "6" must be ignored. The implementation handles this by checking counter == 10 after every processed event and immediately breaking out of the loop.
Arrays With No "W" Events
An input such as:
["6","4","WD","NB"]
never increases the counter. In this case, every event should be processed and the final counter should remain zero. The algorithm naturally handles this because the stopping condition is never triggered.
The Tenth "W" Is the Final Processed Event
Consider:
["1","W","W","W","W","W","W","W","W","W","W"]
The tenth "W" must still be processed because it is the event that causes the counter to become 10. Only events after that point should be ignored. Since the algorithm updates the counter first and checks the stopping condition afterward, the tenth "W" is counted correctly before processing stops.
Numeric Event "0"
The string "0" is a valid scoring event but contributes zero points. A careless implementation might treat it as a special value or ignore it. Converting it with int(event) in Python or event[0] - '0' in Go correctly adds zero to the score without affecting the result.