Problem#
You are given a string formed by concatenating several words corresponding to the integers zero through nine and then anagramming.
For example, the input could be ’niesevehrtfeev’, which is an anagram of ’threefiveseven’. Note that there can be multiple instances of each integer.
Given this string, return the original integers in sorted order. In the example above, this would be 357
.
Examples#
Example 1#
1
2
3
Input: "niesevehrtfeev"
Output: "357"
Explanation: The string is an anagram of "threefiveseven" , which contains digits 3 , 5 , and 7 in sorted order.
Example 2#
1
2
3
Input: "owtztnfur"
Output: "024"
Explanation: The string is an anagram of "zerotwofouru" , which contains digits 0 , 2 , and 4 in sorted order.
Example 3#
1
2
3
Input: "fviefuro"
Output: "45"
Explanation: The string is an anagram of "fourfive" , which contains digits 4 and 5 in sorted order.
Example 4#
1
2
3
Input: "nneonoene"
Output: "1199"
Explanation: The string is an anagram of "onenineonine" , which contains digits 1 , 9 , 1 , 9 in sorted order.
Solution#
Method 1 - Character Frequency Analysis#
Intuition#
The key insight is that some digits have unique characters that only appear in their word representation. For example, ‘z’ only appears in “zero”, ‘w’ only in “two”, ‘u’ only in “four”, etc. We can use these unique characters to identify how many times each digit appears, then work our way through the remaining digits.
Approach#
Count character frequencies in the input string
Identify digits with unique characters first:
‘z’ → zero (0)
‘w’ → two (2)
‘u’ → four (4)
‘x’ → six (6)
‘g’ → eight (8)
Remove counted characters from frequency map
Identify remaining digits with semi-unique characters:
‘f’ → five (5) (after removing four)
’s’ → seven (7) (after removing six)
‘h’ → three (3) (after removing eight)
Handle remaining digits :
‘i’ → nine (9) (after removing five, six, eight)
‘o’ → one (1) (after removing zero, two, four)
Build result string by repeating each digit according to its count
Code#
Cpp
Go
Java
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public :
string originalDigits(string s) {
vector< int > count(26 , 0 );
for (char c : s) {
count[c - 'a' ]++ ;
}
vector< int > nums(10 , 0 );
// Digits with unique characters
nums[0 ] = count['z' - 'a' ];
nums[2 ] = count['w' - 'a' ];
nums[4 ] = count['u' - 'a' ];
nums[6 ] = count['x' - 'a' ];
nums[8 ] = count['g' - 'a' ];
// Semi-unique after removing above
nums[5 ] = count['f' - 'a' ] - nums[4 ];
nums[7 ] = count['s' - 'a' ] - nums[6 ];
nums[3 ] = count['h' - 'a' ] - nums[8 ];
// Remaining digits
nums[9 ] = count['i' - 'a' ] - nums[5 ] - nums[6 ] - nums[8 ];
nums[1 ] = count['o' - 'a' ] - nums[0 ] - nums[2 ] - nums[4 ];
string ans = "" ;
for (int i = 0 ; i < 10 ; i++ ) {
ans += string(nums[i], '0' + i);
}
return ans;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
func originalDigits (s string ) string {
count := make([]int , 26 )
for _ , c := range s {
count [c - 'a' ]++
}
nums := make([]int , 10 )
// Digits with unique characters
nums [0 ] = count ['z' - 'a' ]
nums [2 ] = count ['w' - 'a' ]
nums [4 ] = count ['u' - 'a' ]
nums [6 ] = count ['x' - 'a' ]
nums [8 ] = count ['g' - 'a' ]
// Semi-unique after removing above
nums [5 ] = count ['f' - 'a' ] - nums [4 ]
nums [7 ] = count ['s' - 'a' ] - nums [6 ]
nums [3 ] = count ['h' - 'a' ] - nums [8 ]
// Remaining digits
nums [9 ] = count ['i' - 'a' ] - nums [5 ] - nums [6 ] - nums [8 ]
nums [1 ] = count ['o' - 'a' ] - nums [0 ] - nums [2 ] - nums [4 ]
var ans strings .Builder
for i := 0 ; i < 10 ; i ++ {
for j := 0 ; j < nums [i ]; j ++ {
ans .WriteByte (byte('0' + i ))
}
}
return ans .String ()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
public String originalDigits (String s) {
int [] count = new int [ 26] ;
for (char c : s.toCharArray ()) {
count[ c - 'a' ]++ ;
}
int [] nums = new int [ 10] ;
// Digits with unique characters
nums[ 0] = count[ 'z' - 'a' ] ;
nums[ 2] = count[ 'w' - 'a' ] ;
nums[ 4] = count[ 'u' - 'a' ] ;
nums[ 6] = count[ 'x' - 'a' ] ;
nums[ 8] = count[ 'g' - 'a' ] ;
// Semi-unique after removing above
nums[ 5] = count[ 'f' - 'a' ] - nums[ 4] ;
nums[ 7] = count[ 's' - 'a' ] - nums[ 6] ;
nums[ 3] = count[ 'h' - 'a' ] - nums[ 8] ;
// Remaining digits
nums[ 9] = count[ 'i' - 'a' ] - nums[ 5] - nums[ 6] - nums[ 8] ;
nums[ 1] = count[ 'o' - 'a' ] - nums[ 0] - nums[ 2] - nums[ 4] ;
StringBuilder ans = new StringBuilder();
for (int i = 0; i < 10; i++ ) {
for (int j = 0; j < nums[ i] ; j++ ) {
ans.append ((char )('0' + i));
}
}
return ans.toString ();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution :
def originalDigits (self, s: str) -> str:
count = [0 ] * 26
for c in s:
count[ord(c) - ord('a' )] += 1
nums = [0 ] * 10
# Digits with unique characters
nums[0 ] = count[ord('z' ) - ord('a' )]
nums[2 ] = count[ord('w' ) - ord('a' )]
nums[4 ] = count[ord('u' ) - ord('a' )]
nums[6 ] = count[ord('x' ) - ord('a' )]
nums[8 ] = count[ord('g' ) - ord('a' )]
# Semi-unique after removing above
nums[5 ] = count[ord('f' ) - ord('a' )] - nums[4 ]
nums[7 ] = count[ord('s' ) - ord('a' )] - nums[6 ]
nums[3 ] = count[ord('h' ) - ord('a' )] - nums[8 ]
# Remaining digits
nums[9 ] = count[ord('i' ) - ord('a' )] - nums[5 ] - nums[6 ] - nums[8 ]
nums[1 ] = count[ord('o' ) - ord('a' )] - nums[0 ] - nums[2 ] - nums[4 ]
ans = ""
for i in range(10 ):
ans += str(i) * nums[i]
return ans
Complexity#
⏰ Time complexity: O(n)
, where n is the length of the input string. We iterate through the string once to count characters, then perform constant time operations to determine digit counts.
🧺 Space complexity: O(1)
, as we use fixed-size arrays for character counting and digit counting (size 26 and 10 respectively).
Method 2 - Direct Pattern Matching#
Intuition#
Another approach is to systematically subtract the character patterns of each digit word from our character count. We start with digits that have the most unique characteristics and work our way to the more ambiguous ones.
Approach#
Count all character frequencies in the input string
Define digit patterns as character frequency maps for each digit word
Process digits in strategic order to avoid conflicts:
First: digits with completely unique characters (0, 2, 4, 6, 8)
Second: digits with semi-unique characters (3, 5, 7)
Last: remaining digits (1, 9)
For each digit , determine how many times it appears and subtract its pattern
Build result by concatenating digits in sorted order
Code#
Cpp
Go
Java
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public :
string originalDigits(string s) {
vector< int > count(26 , 0 );
for (char c : s) {
count[c - 'a' ]++ ;
}
vector< string> words = {"zero" , "one" , "two" , "three" , "four" ,
"five" , "six" , "seven" , "eight" , "nine" };
vector< int > nums(10 , 0 );
vector< int > order = {0 , 2 , 4 , 6 , 8 , 3 , 5 , 7 , 1 , 9 };
for (int digit : order) {
int cnt = INT_MAX;
for (char c : words[digit]) {
cnt = min(cnt, count[c - 'a' ]);
}
nums[digit] = cnt;
// Subtract this digit's characters
for (char c : words[digit]) {
count[c - 'a' ] -= cnt;
}
}
string ans = "" ;
for (int i = 0 ; i < 10 ; i++ ) {
ans += string(nums[i], '0' + i);
}
return ans;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
func originalDigits (s string ) string {
count := make([]int , 26 )
for _ , c := range s {
count [c - 'a' ]++
}
words := []string {"zero" , "one" , "two" , "three" , "four" ,
"five" , "six" , "seven" , "eight" , "nine" }
nums := make([]int , 10 )
order := []int {0 , 2 , 4 , 6 , 8 , 3 , 5 , 7 , 1 , 9 }
for _ , digit := range order {
cnt := 1000000
for _ , c := range words [digit ] {
if count [c - 'a' ] < cnt {
cnt = count [c - 'a' ]
}
}
nums [digit ] = cnt
// Subtract this digit's characters
for _ , c := range words [digit ] {
count [c - 'a' ] -= cnt
}
}
var ans strings .Builder
for i := 0 ; i < 10 ; i ++ {
for j := 0 ; j < nums [i ]; j ++ {
ans .WriteByte (byte('0' + i ))
}
}
return ans .String ()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
public String originalDigits (String s) {
int [] count = new int [ 26] ;
for (char c : s.toCharArray ()) {
count[ c - 'a' ]++ ;
}
String[] words = {"zero" , "one" , "two" , "three" , "four" ,
"five" , "six" , "seven" , "eight" , "nine" };
int [] nums = new int [ 10] ;
int [] order = {0, 2, 4, 6, 8, 3, 5, 7, 1, 9};
for (int digit : order) {
int cnt = Integer.MAX_VALUE ;
for (char c : words[ digit] .toCharArray ()) {
cnt = Math.min (cnt, count[ c - 'a' ] );
}
nums[ digit] = cnt;
// Subtract this digit's characters
for (char c : words[ digit] .toCharArray ()) {
count[ c - 'a' ] -= cnt;
}
}
StringBuilder ans = new StringBuilder();
for (int i = 0; i < 10; i++ ) {
for (int j = 0; j < nums[ i] ; j++ ) {
ans.append ((char )('0' + i));
}
}
return ans.toString ();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution :
def originalDigits (self, s: str) -> str:
count = [0 ] * 26
for c in s:
count[ord(c) - ord('a' )] += 1
words = ["zero" , "one" , "two" , "three" , "four" ,
"five" , "six" , "seven" , "eight" , "nine" ]
nums = [0 ] * 10
order = [0 , 2 , 4 , 6 , 8 , 3 , 5 , 7 , 1 , 9 ]
for digit in order:
cnt = float('inf' )
for c in words[digit]:
cnt = min(cnt, count[ord(c) - ord('a' )])
nums[digit] = cnt
# Subtract this digit's characters
for c in words[digit]:
count[ord(c) - ord('a' )] -= cnt
ans = ""
for i in range(10 ):
ans += str(i) * nums[i]
return ans
Complexity#
⏰ Time complexity: O(n)
, where n is the length of the input string. We count characters once and then process each digit pattern in constant time.
🧺 Space complexity: O(1)
, as we use constant space for character counting and digit word storage.