Skip to content

refactor: redesign LetterCombinationsOfPhoneNumber #5221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
61e2a98
Refactor
Jun 12, 2024
93252bf
fix clang
Jun 12, 2024
96bdb98
fix clang
Jun 12, 2024
8fe553a
Merge branch 'cleanup_LetterCombinationsOfPhoneNumber' of https://git…
Jun 12, 2024
bfb4d32
fix clang tests
Jun 12, 2024
b228744
fix pattern
Jun 12, 2024
b1a6124
add test case null
Jun 12, 2024
667403b
Update src/main/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 12, 2024
48f23e2
Update src/main/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 12, 2024
e1a428c
Update src/main/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 12, 2024
cc069a8
Update src/main/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 12, 2024
fda621b
Update src/main/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 12, 2024
d8ace83
Update src/main/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 12, 2024
b257d14
Update src/test/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 12, 2024
575b5e1
rename MAP_OF_CHARS to KEYPAD
Jun 12, 2024
909acdb
fix clang
Jun 12, 2024
1c100ef
remove main
Jun 12, 2024
97e26d3
add tests
Jun 12, 2024
910c814
feat: throw for wrong inputs
vil02 Jun 12, 2024
06d49ce
change keypad to list
Jun 13, 2024
349dedc
Merge branch 'master' into cleanup_LetterCombinationsOfPhoneNumber
Jun 13, 2024
41c7007
Update src/main/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 13, 2024
3ef428b
Update src/main/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 13, 2024
d3f8c03
Update src/main/java/com/thealgorithms/strings/LetterCombinationsOfPh…
samuelfac Jun 13, 2024
24697f9
fix with number 1 (empty value), and add tests
Jun 13, 2024
5b39d4b
style: avoid concatenation while populating `KEYPAD`
vil02 Jun 13, 2024
f83e55c
Merge branch 'master' into cleanup_LetterCombinationsOfPhoneNumber
samuelfac Jun 13, 2024
aeb56a9
Merge branch 'master' into cleanup_LetterCombinationsOfPhoneNumber
samuelfac Jun 13, 2024
87aff59
change to assertEquals
Jun 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,61 @@
import java.util.List;

public final class LetterCombinationsOfPhoneNumber {

private static final char EMPTY = '\0';

// Mapping of numbers to corresponding letters on a phone keypad
private static final String[] KEYPAD = new String[] {" ", String.valueOf(EMPTY), "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};

private LetterCombinationsOfPhoneNumber() {
}

static Character[][] numberToCharMap;

protected static List<String> printWords(int[] numbers, int len, int numIndex, String s) {
if (len == numIndex) {
return new ArrayList<>(Collections.singleton(s));
/**
* Generates a list of all possible letter combinations that the provided
* array of numbers could represent on a phone keypad.
*
* @param numbers an array of integers representing the phone numbers
* @return a list of possible letter combinations
*/
public static List<String> getCombinations(int[] numbers) {
if (numbers == null) {
return List.of("");
}
return generateCombinations(numbers, 0, new StringBuilder());
}

List<String> stringList = new ArrayList<>();
/**
* Recursive method to generate combinations of letters from the phone keypad.
*
* @param numbers the input array of phone numbers
* @param index the current index in the numbers array being processed
* @param current a StringBuilder holding the current combination of letters
* @return a list of letter combinations formed from the given numbers
*/
private static List<String> generateCombinations(int[] numbers, int index, StringBuilder current) {
// Base case: if we've processed all numbers, return the current combination
if (index == numbers.length) {
return new ArrayList<>(Collections.singletonList(current.toString()));
}

for (int i = 0; i < numberToCharMap[numbers[numIndex]].length; i++) {
String sCopy = String.copyValueOf(s.toCharArray());
sCopy = sCopy.concat(numberToCharMap[numbers[numIndex]][i].toString());
stringList.addAll(printWords(numbers, len, numIndex + 1, sCopy));
final var number = numbers[index];
if (number < 0 || number > 9) {
throw new IllegalArgumentException("Input numbers must in the range [0, 9]");
}
return stringList;
}

private static void printWords(int[] numbers) {
generateNumberToCharMap();
List<String> stringList = printWords(numbers, numbers.length, 0, "");
stringList.stream().forEach(System.out::println);
}
List<String> combinations = new ArrayList<>();

protected static void generateNumberToCharMap() {
numberToCharMap = new Character[10][5];
numberToCharMap[0] = new Character[] {'\0'};
numberToCharMap[1] = new Character[] {'\0'};
numberToCharMap[2] = new Character[] {'a', 'b', 'c'};
numberToCharMap[3] = new Character[] {'d', 'e', 'f'};
numberToCharMap[4] = new Character[] {'g', 'h', 'i'};
numberToCharMap[5] = new Character[] {'j', 'k', 'l'};
numberToCharMap[6] = new Character[] {'m', 'n', 'o'};
numberToCharMap[7] = new Character[] {'p', 'q', 'r', 's'};
numberToCharMap[8] = new Character[] {'t', 'u', 'v'};
numberToCharMap[9] = new Character[] {'w', 'x', 'y', 'z'};
}
// Iterate over each letter and recurse to generate further combinations
for (char letter : KEYPAD[number].toCharArray()) {
if (letter != EMPTY) {
current.append(letter);
}
combinations.addAll(generateCombinations(numbers, index + 1, current));
if (letter != EMPTY) {
current.deleteCharAt(current.length() - 1); // Backtrack by removing the last appended letter
}
}

// Driver code
public static void main(String[] args) {
int[] number = {2, 3, 4};
printWords(number);
return combinations;
}
}
Original file line number Diff line number Diff line change
@@ -1,45 +1,37 @@
package com.thealgorithms.strings;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

public class LetterCombinationsOfPhoneNumberTest {

@Test
public void letterCombinationsOfPhoneNumber() {
LetterCombinationsOfPhoneNumber.generateNumberToCharMap();

// ** Test 1 **
// Input: digits = ""
// Output: []
int[] numbers1 = {};
List<String> output1 = Arrays.asList("");
assertTrue(LetterCombinationsOfPhoneNumber.printWords(numbers1, numbers1.length, 0, "").equals(output1));
@ParameterizedTest
@MethodSource("provideTestCases")
public void testLetterCombinationsOfPhoneNumber(int[] numbers, List<String> expectedOutput) {
assertEquals(expectedOutput, LetterCombinationsOfPhoneNumber.getCombinations(numbers));
}

// ** Test 2 **
// Input: digits = "2"
// Output: ["a","b","c"]
int[] numbers2 = {2};
List<String> output2 = Arrays.asList("a", "b", "c");
assertTrue(LetterCombinationsOfPhoneNumber.printWords(numbers2, numbers2.length, 0, "").equals(output2));
@ParameterizedTest
@MethodSource("wrongInputs")
void throwsForWrongInput(int[] numbers) {
assertThrows(IllegalArgumentException.class, () -> LetterCombinationsOfPhoneNumber.getCombinations(numbers));
}

// ** Test 3 **
// Input: digits = "23"
// Output: ["ad","ae","af","bd","be","bf","cd","ce","cf"]
int[] numbers3 = {2, 3};
List<String> output3 = Arrays.asList("ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf");
assertTrue(LetterCombinationsOfPhoneNumber.printWords(numbers3, numbers3.length, 0, "").equals(output3));
private static Stream<Arguments> provideTestCases() {
return Stream.of(Arguments.of(null, List.of("")), Arguments.of(new int[] {}, List.of("")), Arguments.of(new int[] {2}, List.of("a", "b", "c")), Arguments.of(new int[] {2, 3}, List.of("ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf")),
Arguments.of(new int[] {2, 3, 4}, List.of("adg", "adh", "adi", "aeg", "aeh", "aei", "afg", "afh", "afi", "bdg", "bdh", "bdi", "beg", "beh", "bei", "bfg", "bfh", "bfi", "cdg", "cdh", "cdi", "ceg", "ceh", "cei", "cfg", "cfh", "cfi")),
Arguments.of(new int[] {3, 3}, List.of("dd", "de", "df", "ed", "ee", "ef", "fd", "fe", "ff")), Arguments.of(new int[] {8, 4}, List.of("tg", "th", "ti", "ug", "uh", "ui", "vg", "vh", "vi")), Arguments.of(new int[] {2, 0}, List.of("a ", "b ", "c ")),
Arguments.of(new int[] {9, 2}, List.of("wa", "wb", "wc", "xa", "xb", "xc", "ya", "yb", "yc", "za", "zb", "zc")), Arguments.of(new int[] {0}, List.of(" ")), Arguments.of(new int[] {1}, List.of("")), Arguments.of(new int[] {2}, List.of("a", "b", "c")),
Arguments.of(new int[] {1, 2, 0, 4}, List.of("a g", "a h", "a i", "b g", "b h", "b i", "c g", "c h", "c i")));
}

// ** Test 4 **
// Input: digits = "234"
// Output: ["adg", "adh", "adi", "aeg", "aeh", "aei", "afg", "afh", "afi",
// "bdg", "bdh", "bdi", "beg", "beh", "bei", "bfg", "bfh", "bfi", "cdg", "cdh",
// "cdi", "ceg", "ceh", "cei", "cfg", "cfh", "cfi"]
int[] numbers4 = {2, 3, 4};
List<String> output4 = Arrays.asList("adg", "adh", "adi", "aeg", "aeh", "aei", "afg", "afh", "afi", "bdg", "bdh", "bdi", "beg", "beh", "bei", "bfg", "bfh", "bfi", "cdg", "cdh", "cdi", "ceg", "ceh", "cei", "cfg", "cfh", "cfi");
assertTrue(LetterCombinationsOfPhoneNumber.printWords(numbers4, numbers4.length, 0, "").equals(output4));
private static Stream<Arguments> wrongInputs() {
return Stream.of(Arguments.of(new int[] {-1}), Arguments.of(new int[] {10}), Arguments.of(new int[] {2, 2, -1, 0}), Arguments.of(new int[] {0, 0, 0, 10}));
}
}