LeetCode 3798 - Largest Even Number
We are given a string s that contains only the characters '1' and '2'. We are allowed to delete any number of characters while preserving the relative order of the remaining characters. In other words, we may choose any subsequence of the original string.
Difficulty: 🟢 Easy
Topics: String
Solution
LeetCode 3798 - Largest Even Number
Problem Understanding
We are given a string s that contains only the characters '1' and '2'. We are allowed to delete any number of characters while preserving the relative order of the remaining characters. In other words, we may choose any subsequence of the original string.
The goal is to produce the largest possible string that represents an even integer. Since the resulting string must be a subsequence, we cannot rearrange characters. We may only keep or remove characters.
An integer is even if its last digit is even. Since the string contains only '1' and '2', the resulting number is even if and only if its last character is '2'.
The key challenge is determining which characters to keep so that the resulting subsequence is numerically as large as possible while still ending with '2'.
The constraints are very small, 1 <= s.length <= 100, but even with small constraints we should still look for the simplest and most efficient solution.
Some important edge cases are:
- A string containing only
'1'characters, in which case no even number can be formed. - A string consisting entirely of
'2'characters, where the entire string should be returned. - A string where the only
'2'appears very early, forcing us to discard everything after it. - A string that already ends with
'2', where keeping all characters may be optimal. - A single-character string such as
"1"or"2".
Approaches
Brute Force
A brute-force solution would generate every possible subsequence of the string.
For each subsequence, we would check whether:
- It is non-empty.
- It ends with
'2'. - It represents a larger number than the best answer found so far.
Since a string of length n has 2^n subsequences, this approach becomes exponential. Even though n <= 100, generating all subsequences is completely infeasible.
The brute-force approach is correct because it explicitly examines every valid subsequence and selects the largest even one, but its running time is far too large.
Key Insight
Since the digits are only '1' and '2', the digit '2' is larger than '1'.
To maximize the resulting number, we want the longest possible sequence, and among sequences of equal length, we want larger digits to appear as early as possible.
The result must end with a '2'. Suppose we choose some occurrence of '2' as the final digit.
Any character before that chosen '2' can only help us:
- Adding more digits before the last digit increases the length.
- Keeping a digit never makes the number smaller when compared to deleting it, because longer positive integer strings are always numerically larger than their prefixes.
Therefore, once we decide which '2' will be the last digit, the optimal subsequence is simply the entire prefix ending at that '2'.
To maximize the result, we should choose the rightmost '2' in the string. This allows us to keep the largest possible prefix.
Thus the answer is simply the substring from the beginning of the string through the last occurrence of '2'.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(2^n · n) | O(2^n · n) | Enumerates all subsequences |
| Optimal | O(n) | O(1) | Find the last '2' and return the prefix |
Algorithm Walkthrough
- Scan the string from right to left and find the last occurrence of the character
'2'. - If no
'2'exists, return the empty string. Any subsequence would consist entirely of'1'characters, which always form odd numbers. - Let the position of the rightmost
'2'belast_two_index. - Return the substring
s[:last_two_index + 1]. - This substring contains every character up to and including the last
'2', producing the longest possible valid even number.
Why it works
Any valid answer must end at some occurrence of '2'. If that occurrence is not the rightmost '2', then there are additional characters between it and the rightmost '2'. Keeping those characters and extending the subsequence to end at the rightmost '2' creates a longer number, which is always numerically larger. Therefore, the optimal answer must end at the rightmost '2', and keeping all preceding characters maximizes the result.
Python Solution
class Solution:
def largestEven(self, s: str) -> str:
last_two_index = s.rfind('2')
if last_two_index == -1:
return ""
return s[:last_two_index + 1]
The implementation directly follows the algorithm.
The call to rfind('2') locates the rightmost occurrence of '2'. If no such character exists, rfind returns -1, indicating that no even number can be formed.
Otherwise, we return the prefix ending at that position. Because every character before the chosen ending digit can only increase the resulting number, this prefix is guaranteed to be optimal.
Go Solution
func largestEven(s string) string {
lastTwoIndex := -1
for i := len(s) - 1; i >= 0; i-- {
if s[i] == '2' {
lastTwoIndex = i
break
}
}
if lastTwoIndex == -1 {
return ""
}
return s[:lastTwoIndex+1]
}
The Go implementation performs the same logic manually. It scans from right to left until it finds the first '2', which is the rightmost occurrence in the string.
If no '2' is found, an empty string is returned. Otherwise, Go's string slicing operation returns the prefix ending at that index.
There are no concerns about integer overflow because we only manipulate indices. Returning "" is the standard way to represent an empty string in Go.
Worked Examples
Example 1
Input:
s = "1112"
Finding the rightmost '2':
| Index | Character |
|---|---|
| 3 | 2 |
last_two_index = 3
Returned substring:
s[:4] = "1112"
Output:
"1112"
Example 2
Input:
s = "221"
Scanning from the end:
| Index | Character |
|---|---|
| 2 | 1 |
| 1 | 2 |
last_two_index = 1
Returned substring:
s[:2] = "22"
Output:
"22"
Example 3
Input:
s = "1"
Scanning from the end:
| Index | Character |
|---|---|
| 0 | 1 |
No '2' is found.
last_two_index = -1
Output:
""
Additional Example
Input:
s = "2121121"
Scanning from the end:
| Index | Character |
|---|---|
| 6 | 1 |
| 5 | 2 |
last_two_index = 5
Returned substring:
s[:6] = "212112"
Output:
"212112"
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | One scan to locate the last '2' |
| Space | O(1) | Only a few variables are used |
The algorithm performs a single traversal of the string. No auxiliary data structures are required, so the extra space usage remains constant.
Test Cases
sol = Solution()
assert sol.largestEven("1112") == "1112" # provided example, already optimal
assert sol.largestEven("221") == "22" # provided example
assert sol.largestEven("1") == "" # provided example, no even number
assert sol.largestEven("2") == "2" # single even digit
assert sol.largestEven("11") == "" # all odd digits
assert sol.largestEven("22") == "22" # all even digits
assert sol.largestEven("121") == "12" # rightmost 2 in middle
assert sol.largestEven("2111") == "2" # only 2 at beginning
assert sol.largestEven("112111") == "112" # suffix after last 2 removed
assert sol.largestEven("2121121") == "212112" # mixed digits
assert sol.largestEven("222222") == "222222" # many 2s
assert sol.largestEven("1111112") == "1111112" # last character is 2
# maximum-style length stress case
assert sol.largestEven("1" * 99 + "2") == "1" * 99 + "2"
Test Summary
| Test | Why |
|---|---|
"1112" |
Already optimal answer |
"221" |
Requires deleting a trailing 1 |
"1" |
No valid even number exists |
"2" |
Smallest valid even number |
"11" |
All digits are odd |
"22" |
All digits are even |
"121" |
Last 2 appears in the middle |
"2111" |
Only even digit at the start |
"112111" |
Must remove a long suffix |
"2121121" |
General mixed case |
"222222" |
Multiple possible ending positions |
"1111112" |
Rightmost character already even |
"1"*99 + "2" |
Near maximum input size |
Edge Cases
No '2' Exists
A string such as "111111" contains only odd digits. Since an even number must end with an even digit, no valid subsequence exists. The implementation detects this because rfind('2') returns -1, and it immediately returns the empty string.
The Only '2' Is at the Beginning
Consider "21111". A common mistake would be to try preserving later digits because they increase length. However, any valid even number must still end with '2'. Since there is no later '2', the best answer is simply "2". Returning the prefix ending at the rightmost '2' handles this correctly.
The String Already Ends with '2'
For an input such as "121212", the rightmost '2' is already the last character. The algorithm returns the entire string unchanged. This is correct because deleting any character would either shorten the number or remove its even ending, producing a smaller result.
Multiple Occurrences of '2'
For a string like "21212", several positions could serve as the final digit. Choosing any earlier '2' would force us to discard characters that could otherwise be kept. By always selecting the rightmost '2', the algorithm guarantees the longest and therefore largest possible valid number.