https://algo.monster/problems/letter_combinations_of_phone_number
There should be a test case with duplicate numbers, e.g. “565” (try in custom test). I thought solution to Permutations worked here but I was wrong.
Alternative solution for Javascript:
function letterCombinationsOfPhoneNumber(digits) {
let table = {2:‘abc’, 3:‘def’, 4: ‘ghi’, 5:‘jkl’, 6:‘mno’, 7:‘pqrs’, 8:‘tuv’, 9:‘wxyz’}
let path = []
let res = []
let unused = []
function dfs(unused, res, path){
if(path.length === digits.length){
return res.push(path.join(''))
}
for(let letters of unused){
unused = unused.filter(str => str !== letters)
for(let letter of letters){
path.push(letter)
dfs(unused, res, path)
path.pop()
}
}
}
for(let digit of digits){
unused.push(table[digit])
}
dfs(unused, res, path)
return res;
}
It seems we don’t need a “used/unused” map/object/array here in contrast to the permutations problem.
In the permutations problem, we had to go back to the same arr, but our choices kept being reduced.
In this problem, we are able to go through each letter per digit consecutively.
Good job on catching duplicate numbers. You were right that most of the permutations concept can be used to solve this problem with a few changes. The concept of tracking ‘used’ letters here will reduce the number of results, so we will have issues with duplicate numbers.
The solution also doesn’t do that great of a job at explaining that the length of the current path helps establish what digit we are exploring.
At every dfs call, we need to establish what digit in the number we are looking at (i.e. ‘56’ gives us index 0 which is 5, and index 1 which is 6). We want to iterate through all of our letter options for each index. At index 0, we have 5, so we will look at the array [j, k, l]. If our path
list/array/vector already has a letter in it, that means we are now exploring each letter option for number 6 (index 1) - this means we are on our second level in the dfs tree.
C# Solution
private static Dictionary<char, char[]> KEYBOARD = new Dictionary<char, char[]>{
{'2', "abc".ToCharArray()},
{'3', "def".ToCharArray()},
{'4', "ghi".ToCharArray()},
{'5', "jkl".ToCharArray()},
{'6', "mno".ToCharArray()},
{'7', "pqrs".ToCharArray()},
{'8', "tuv".ToCharArray()},
{'9', "wxyz".ToCharArray()}}
;
private static void dfs(StringBuilder path, List<String> res, char[] digits) {
if (path.Length == digits.Length) {
res.Add(path.ToString());
return;
}
char next_digit = digits[path.Length];
foreach (char letter in KEYBOARD[next_digit]) {
path.Append(letter);
dfs(path, res, digits);
path.Remove(path.Length - 1,1);
}
}
public static List<string> LetterCombinationsOfPhoneNumber(string digits)
{
var res = new List<String>();
dfs(new StringBuilder(), res, digits.ToCharArray());
return res;
}
thank you for the explanation that was helpful
Not exactly. Your solution will contain the 4^n combination of n letters. That’s O(n * 4^n) complexity which is the biggest one. That’s the response.
Easier to understand, java
public static List<String> letterCombinationsOfPhoneNumber(String digits) {
// WRITE YOUR BRILLIANT CODE HERE
Map<Character,String> mapping = new HashMap();
mapping.put('0',"");
mapping.put('1',"");
mapping.put('2',"abc");
mapping.put('3',"def");
mapping.put('4',"ghi");
mapping.put('5',"jkl");
mapping.put('6',"mno");
mapping.put('7',"pqrs");
mapping.put('8',"tuv");
mapping.put('9',"wxyz");
List<String> result = new ArrayList();
dfs(new StringBuilder(), 0, mapping , result, digits);
return result;
}
private static void dfs(StringBuilder current, int index, Map<Character,String> mapping,List<String> result,String digits)
{
if(index == digits.length())
{
result.add(current.toString());
return;
}
char number = digits.charAt(index);
for(char c: mapping.get(number).toCharArray()){
current.append(c);
dfs(current,index + 1,mapping,result,digits);
current.deleteCharAt(current.length() - 1);
}
}
Structured Programming JS Solution:
const KEYBOARD = {
'2': ["a", "b", "c"],
'3': ["d", "e", "f"],
'4': ["g", "h", "i"],
'5': ["j", "k", "l"],
'6': ["m", "n", "o"],
'7': ["p", "q", "r", "s"],
'8': ["t", "u", "v"],
'9': ["w", "x", "y", "z"],
};
function letterCombinationsOfPhoneNumber(digits) {
let results = [];
if (digits.length >= 1) {
const char = digits.charAt(0);
const substr = digits.substr(1);
for (const letter of KEYBOARD[char]) {
if (substr.length) {
const combos = letterCombinationsOfPhoneNumber(substr);
combos.forEach((combo) => results.push(`${letter}${combo}`));
} else {
results.push(letter);
}
}
}
return results;
}
Python:
def letter_combinations_of_phone_number(digits: str) → List[str]:
digits_to_letters = ['', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
output = []
def get_edges(index):
return digits_to_letters[int(index)]
n = len(digits)
def dfs(current_idx: int, path: List[str]):
if current_idx >= n:
output.append(''.join(path))
return
for edge in get_edges(digits[current_idx]):
path.append(edge)
dfs(current_idx + 1, path)
path.pop()
dfs(0, [])
return output
I think on the template it should be ‘report(path)’ instead of ‘report(edge)’
you are right, it’ll be updated in the next deploy
Does O(4^n * n) simplify down, or is that the expected time complexity answer in an interview?