1796. Second Largest Digit in a String
Problem Description
You are given an alphanumeric string s
that contains lowercase English letters and digits. Your task is to find the second largest numerical digit that appears in the string.
The problem asks you to:
- Scan through the string and identify all digit characters (0-9)
- Find the second largest unique digit among them
- Return this second largest digit as an integer
- If there is no second largest digit (for example, if the string has no digits, only one unique digit, or all digits are the same), return
-1
For example:
- If
s = "abc123"
, the digits are 1, 2, 3. The largest is 3 and the second largest is 2, so return2
- If
s = "abc111"
, there's only one unique digit (1), so return-1
- If
s = "abc"
, there are no digits, so return-1
The solution uses two variables a
and b
to track the largest and second largest digits respectively. As it iterates through the string:
- When a digit larger than the current largest is found, the previous largest becomes the second largest
- When a digit between the second largest and largest is found, it updates the second largest
- This ensures we always maintain the top two unique digit values
Intuition
To find the second largest digit, we need to keep track of the top two distinct digits we've seen so far. Think of it like maintaining a leaderboard with only two positions - first place and second place.
The key insight is that we don't need to collect all digits first and then sort them. Instead, we can maintain just two variables as we scan through the string once. This is similar to finding the maximum element in an array, but extended to track the top two elements.
As we encounter each digit character, there are three possible scenarios:
- The digit is larger than our current largest - in this case, our current largest gets "bumped down" to become the second largest, and this new digit becomes the largest
- The digit is between our second largest and largest - it becomes our new second largest
- The digit is smaller than or equal to our second largest - we ignore it as it doesn't affect our top two
The elegant part of this approach is the update logic: when we find a new maximum with v > a
, we can update both values in one go with a, b = v, a
. This simultaneously promotes the old maximum to second place and installs the new maximum.
We initialize both tracking variables to -1
because this serves as both a sentinel value (indicating "no digit found yet") and conveniently matches our required return value when no second largest exists. This eliminates the need for special case handling at the end.
Solution Approach
We implement a one-pass algorithm that scans through the string once while maintaining two variables to track the largest and second largest digits.
Initialization:
- Set
a = -1
to track the largest digit found - Set
b = -1
to track the second largest digit found - Using
-1
as initial values since it's both our "not found" indicator and the required return value when no second largest exists
Main Loop:
For each character c
in the string s
:
- Check if
c
is a digit usingc.isdigit()
- If it's a digit, convert it to integer
v = int(c)
- Apply the update logic:
- Case 1: If
v > a
(found a new maximum):- Update both values:
a, b = v, a
- This moves the old largest to second place and installs the new largest
- Update both values:
- Case 2: If
b < v < a
(found a value between second and first):- Update only the second largest:
b = v
- This improves our second largest without affecting the first
- Update only the second largest:
- Case 3: If
v <= b
orv == a
:- Do nothing, as this digit doesn't improve our top two
- Case 1: If
Return Result:
After traversing the entire string, return b
which contains:
- The second largest digit if it exists
-1
if no second largest digit was found
The algorithm handles edge cases naturally:
- If the string has no digits, both
a
andb
remain-1
- If only one unique digit exists,
b
remains-1
- Duplicate digits are handled correctly since we use strict inequality checks
Time Complexity: O(n)
where n
is the length of the string - we traverse it once
Space Complexity: O(1)
- we only use two variables regardless of input size
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's trace through the example s = "dfa12321afd"
to see how our algorithm finds the second largest digit.
Initial State:
a = -1
(largest digit)b = -1
(second largest digit)
Step-by-step iteration:
-
c = 'd'
: Not a digit, skip. State:a = -1, b = -1
-
c = 'f'
: Not a digit, skip. State:a = -1, b = -1
-
c = 'a'
: Not a digit, skip. State:a = -1, b = -1
-
c = '1'
: Is a digit!v = 1
- Check:
v > a
? →1 > -1
? Yes! - Update:
a, b = 1, -1
- State:
a = 1, b = -1
- Check:
-
c = '2'
: Is a digit!v = 2
- Check:
v > a
? →2 > 1
? Yes! - Update:
a, b = 2, 1
- State:
a = 2, b = 1
- Check:
-
c = '3'
: Is a digit!v = 3
- Check:
v > a
? →3 > 2
? Yes! - Update:
a, b = 3, 2
- State:
a = 3, b = 2
- Check:
-
c = '2'
: Is a digit!v = 2
- Check:
v > a
? →2 > 3
? No - Check:
b < v < a
? →2 < 2 < 3
? No (v equals b) - No update needed
- State:
a = 3, b = 2
- Check:
-
c = '1'
: Is a digit!v = 1
- Check:
v > a
? →1 > 3
? No - Check:
b < v < a
? →2 < 1 < 3
? No - No update needed
- State:
a = 3, b = 2
- Check:
-
c = 'a'
: Not a digit, skip. State:a = 3, b = 2
-
c = 'f'
: Not a digit, skip. State:a = 3, b = 2
-
c = 'd'
: Not a digit, skip. State:a = 3, b = 2
Final Result: Return b = 2
The algorithm correctly identifies that among the digits {1, 2, 3}, the second largest is 2. Notice how when we encountered the digit '2' again in step 7, we didn't update our variables since it was already tracked as our second largest.
Solution Implementation
1class Solution:
2 def secondHighest(self, s: str) -> int:
3 # Initialize variables to track the highest and second highest digits
4 # Using -1 as sentinel value (no valid digit found)
5 highest = second_highest = -1
6
7 # Iterate through each character in the string
8 for char in s:
9 # Check if the current character is a digit
10 if char.isdigit():
11 # Convert the digit character to integer
12 digit_value = int(char)
13
14 # If current digit is greater than the highest seen so far
15 if digit_value > highest:
16 # Update both: previous highest becomes second highest
17 second_highest = highest
18 highest = digit_value
19 # If current digit is between second highest and highest (exclusive)
20 elif second_highest < digit_value < highest:
21 # Update second highest
22 second_highest = digit_value
23
24 # Return the second highest digit (-1 if not found)
25 return second_highest
26
1class Solution {
2 /**
3 * Finds the second highest digit in a string.
4 *
5 * @param s the input string containing alphanumeric characters
6 * @return the second highest digit, or -1 if it doesn't exist
7 */
8 public int secondHighest(String s) {
9 // Initialize variables to track the highest and second highest digits
10 int highestDigit = -1;
11 int secondHighestDigit = -1;
12
13 // Iterate through each character in the string
14 for (int index = 0; index < s.length(); index++) {
15 char currentChar = s.charAt(index);
16
17 // Check if the current character is a digit
18 if (Character.isDigit(currentChar)) {
19 // Convert character digit to integer value
20 int digitValue = currentChar - '0';
21
22 // Update highest and second highest based on current digit
23 if (digitValue > highestDigit) {
24 // Current digit becomes new highest, previous highest becomes second
25 secondHighestDigit = highestDigit;
26 highestDigit = digitValue;
27 } else if (digitValue > secondHighestDigit && digitValue < highestDigit) {
28 // Current digit is between second highest and highest
29 secondHighestDigit = digitValue;
30 }
31 }
32 }
33
34 // Return the second highest digit (or -1 if not found)
35 return secondHighestDigit;
36 }
37}
38
1class Solution {
2public:
3 int secondHighest(string s) {
4 // Initialize variables to track the highest and second highest digits
5 // -1 indicates no valid digit found yet
6 int highest = -1;
7 int secondHighest = -1;
8
9 // Iterate through each character in the string
10 for (char& ch : s) {
11 // Check if the current character is a digit
12 if (isdigit(ch)) {
13 // Convert character digit to integer value
14 int digitValue = ch - '0';
15
16 // Update highest and second highest values accordingly
17 if (digitValue > highest) {
18 // New highest found, previous highest becomes second highest
19 secondHighest = highest;
20 highest = digitValue;
21 } else if (digitValue > secondHighest && digitValue < highest) {
22 // Found a value between second highest and highest
23 // Update second highest only
24 secondHighest = digitValue;
25 }
26 // Note: If digitValue equals highest or is less than secondHighest,
27 // no update is needed
28 }
29 }
30
31 // Return the second highest digit found, or -1 if it doesn't exist
32 return secondHighest;
33 }
34};
35
1/**
2 * Finds the second highest digit in a string
3 * @param s - Input string containing characters and digits
4 * @returns The second highest digit, or -1 if not found
5 */
6function secondHighest(s: string): number {
7 // Initialize tracking variables for highest and second highest digits
8 let highestDigit: number = -1;
9 let secondHighestDigit: number = -1;
10
11 // Iterate through each character in the string
12 for (const char of s) {
13 // Check if the character is a digit (0-9)
14 if (char >= '0' && char <= '9') {
15 // Convert character to its numeric value
16 const digitValue: number = char.charCodeAt(0) - '0'.charCodeAt(0);
17
18 // Update highest and second highest values accordingly
19 if (digitValue > highestDigit) {
20 // New highest found: shift current highest to second highest
21 secondHighestDigit = highestDigit;
22 highestDigit = digitValue;
23 } else if (digitValue !== highestDigit && digitValue > secondHighestDigit) {
24 // New second highest found (not equal to highest)
25 secondHighestDigit = digitValue;
26 }
27 }
28 }
29
30 return secondHighestDigit;
31}
32
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the string s
. This is because the algorithm iterates through each character in the string exactly once using a single for loop. Each operation inside the loop (checking if a character is a digit, converting to integer, and comparing/updating variables) takes constant time O(1)
.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space regardless of the input size - specifically two integer variables a
and b
to track the highest and second-highest digits, and a temporary variable v
to store the current digit value. The space usage does not grow with the size of the input string.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Not Handling Duplicate Digits Correctly
The Problem: A common mistake is updating the second highest when encountering a digit equal to the current highest. This leads to incorrect results when the largest digit appears multiple times.
Incorrect Implementation:
if digit_value >= highest: # Wrong: using >= instead of > second_highest = highest highest = digit_value
Example Where It Fails:
- Input:
"abc9d9ef2"
- Expected output:
2
(digits are 9, 9, 2) - Incorrect output:
9
(due to setting second_highest = 9 when seeing the second 9)
Correct Solution:
Use strict inequality (>
) to ensure we only update when finding a truly larger value:
if digit_value > highest: # Correct: strict inequality second_highest = highest highest = digit_value
Pitfall 2: Using a Set to Collect All Digits First
The Problem: While using a set seems intuitive for finding unique digits, it requires extra space and two passes through the data.
Inefficient Approach:
digits = set()
for char in s:
if char.isdigit():
digits.add(int(char))
sorted_digits = sorted(digits, reverse=True)
return sorted_digits[1] if len(sorted_digits) >= 2 else -1
Issues:
- Space complexity increases to O(10) for the set
- Time complexity becomes O(n + 10log10) due to sorting
- Less elegant and more code
Better Solution: The two-variable tracking approach maintains O(1) space and O(n) time while being more concise.
Pitfall 3: Forgetting the Boundary Condition for Second Highest Update
The Problem: When updating the second highest, forgetting to check that the new value is also less than the highest can lead to incorrect results.
Incorrect Implementation:
elif digit_value > second_highest: # Wrong: missing upper bound check second_highest = digit_value
Example Where It Fails:
- Input:
"a5b5c5"
- After seeing first 5: highest = 5, second_highest = -1
- After seeing second 5: Without the upper bound check, we might incorrectly set second_highest = 5
- Result: Returns 5 instead of -1
Correct Solution: Always check both bounds:
elif second_highest < digit_value < highest: # Correct: check both bounds second_highest = digit_value
Which algorithm should you use to find a node that is close to the root of the tree?
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!