leetcode_rust/problems/p000_0xx/p000_017.rs
1//! # Description
2//!
3//! Given a string containing digits from `2-9` inclusive, return all possible
4//! letter combinations that the number could represent. Return the answer in
5//! any order.
6//!
7//! A mapping of digits to letters (just like on the telephone buttons) is
8//! given below. Note that `1` does not map to any letters.
9//!
10//! 
11//!
12//! Example 1:
13//!
14//! ```plain
15//! Input: digits = "23"
16//! Output: ["ad","ae","af","bd","be","bf","cd","ce","cf"]
17//! ```
18//!
19//! Example 2:
20//!
21//! ```plain
22//! Input: digits = ""
23//! Output: []
24//! ```
25//!
26//! Example 3:
27//!
28//! ```plain
29//! Input: digits = "2"
30//! Output: ["a","b","c"]
31//! ```
32//!
33//! Constraints:
34//!
35//! - `0 $\leqslant$ digits.length $\leqslant$ 4`
36//! - `digits[i]` is a digit in the range `['2', '9']`.
37//!
38//! Sources: <https://leetcode.com/problems/letter-combinations-of-a-phone-number/>
39
40////////////////////////////////////////////////////////////////////////////////
41
42/// Letter Combinations of a Phone Number
43///
44/// # Arguments
45/// * `digits` - input digits
46///
47/// # Examples
48///
49/// ```rust
50/// use leetcode_rust::problems::p000_0xx::p000_017::letter_combinations;
51///
52/// let input = String::from("2");
53/// let output = letter_combinations(input);
54/// assert_eq!(output, vec!["a", "b", "c"]);
55/// ```
56pub fn letter_combinations(digits: String) -> Vec<String> {
57 // letter_combinations_by_match_control_flow(digits)
58 letter_combinations_by_pre_allocation(digits)
59 // letter_combinations_by_pre_allocation_v2(digits)
60}
61
62/// Match structure to get the letters for each digit
63///
64/// # Arguments
65/// - `digits` - input digits
66#[allow(dead_code)]
67fn letter_combinations_by_match_control_flow(digits: String) -> Vec<String> {
68 use std::str;
69 let mut res: Vec<String> = vec![];
70 for digit in digits.as_bytes() {
71 let letters = match *digit {
72 b'2' => "abc",
73 b'3' => "def",
74 b'4' => "ghi",
75 b'5' => "jkl",
76 b'6' => "mno",
77 b'7' => "pqrs",
78 b'8' => "tuv",
79 b'9' => "wxyz",
80 _ => "",
81 }
82 .as_bytes();
83
84 if res.len() > 0 {
85 let mut temp_res = vec![];
86 for partial in res {
87 for letter in letters {
88 let mut new_partial = partial.clone();
89 new_partial.push(*letter as char);
90 temp_res.push(new_partial);
91 }
92 }
93 res = temp_res;
94 } else {
95 res = letters
96 .iter()
97 .map(|l| str::from_utf8(vec![*l].as_slice()).unwrap().to_string())
98 .collect();
99 }
100 }
101
102 res
103}
104
105/// Create a vector of bytes representing each digit in advance. Save memory usage
106/// significantly.
107///
108/// # Arguments
109/// - `digits` - input digits
110#[allow(dead_code)]
111fn letter_combinations_by_pre_allocation(digits: String) -> Vec<String> {
112 use std::str;
113
114 let digits_to_letters: Vec<&[u8]> =
115 vec!["abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"]
116 .iter()
117 .map(|s| s.as_bytes())
118 .collect();
119
120 let mut res: Vec<String> = vec![];
121 for digit in digits.as_bytes() {
122 let letters = digits_to_letters[(*digit - b'2') as usize];
123
124 if res.len() > 0 {
125 let mut temp_res = vec![];
126 for partial in res {
127 for letter in letters {
128 let mut new_partial = partial.clone();
129 new_partial.push(*letter as char);
130 temp_res.push(new_partial);
131 }
132 }
133 res = temp_res;
134 } else {
135 let mut temp: Vec<String> = letters
136 .iter()
137 .map(|l| str::from_utf8(vec![*l].as_slice()).unwrap().to_string())
138 .collect();
139 res.append(&mut temp);
140 }
141 }
142
143 res
144}
145
146/// Create a vector of bytes representing each digit in advance. Save memory
147/// usage significantly. Simplified expression but may cause a little more
148/// memory consumption.
149///
150/// # Arguments
151/// - `digits` - input digits
152#[allow(dead_code)]
153fn letter_combinations_by_pre_allocation_v2(digits: String) -> Vec<String> {
154 use std::str;
155
156 let digits_to_letters: Vec<&[u8]> =
157 vec!["abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"]
158 .iter()
159 .map(|s| s.as_bytes())
160 .collect();
161
162 let mut res: Vec<String> = vec![];
163 for digit in digits.as_bytes() {
164 let letters = digits_to_letters[(*digit - b'2') as usize];
165
166 res = if res.len() == 0 {
167 letters
168 .iter()
169 .map(|l| str::from_utf8(&[*l]).unwrap().to_string())
170 .collect()
171 } else {
172 let mut temp_res = vec![];
173 for partial in res {
174 for letter in letters {
175 temp_res.push(partial.clone() + str::from_utf8(&[*letter]).unwrap());
176 }
177 }
178 temp_res
179 };
180 }
181
182 res
183}
184
185#[cfg(test)]
186mod tests {
187 use super::letter_combinations;
188 #[test]
189 fn test_letter_combinations() {
190 assert_eq!(
191 letter_combinations(String::from("23")),
192 vec!["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
193 );
194 assert_eq!(letter_combinations(String::from("")), Vec::<String>::new());
195 assert_eq!(letter_combinations(String::from("2")), vec!["a", "b", "c"]);
196 }
197}