Je viens d’essayer pour ma première entrevue de programmation et l’une des questions était d’écrire un programme qui donnerait un numéro de téléphone à 7 chiffres et pourrait imprimer toutes les combinaisons possibles de lettres que chaque nombre pourrait représenter.
Une deuxième partie de la question était la suivante: que se passerait-il s’il s’agissait d’un numéro international à 12 chiffres? Comment cela affecterait-il votre conception?.
Je n'ai pas le code que j'ai écrit dans l'interview, mais j'ai eu l'impression qu'il n'était pas content.
Quelle est la meilleure façon de procéder?
En Python, itératif:
digit_map = {
'2': 'abc',
'3': 'def',
'4': 'ghi',
'5': 'jkl',
'6': 'mno',
'7': 'pqrs',
'8': 'tuv',
'9': 'wxyz',
}
def Word_numbers(input):
input = str(input)
ret = ['']
for char in input:
letters = digit_map.get(char, '')
ret = [prefix+letter for prefix in ret for letter in letters]
return ret
ret
est une liste des résultats obtenus jusqu'à présent; Au début, il contient un élément, la chaîne vide. Ensuite, pour chaque caractère de la chaîne d'entrée, il recherche la liste de lettres qui lui correspond dans le dict défini en haut. Il remplace ensuite la liste ret
par toutes les combinaisons de préfixes existants et de lettres possibles.
Cela ressemble à une question appelée combinaison de lettres d'un numéro de téléphone , Voici ma solution.
Cela fonctionne pour un nombre arbitraire de chiffres, tant que le résultat ne dépasse pas la limite de mémoire.
import Java.util.HashMap;
public class Solution {
public ArrayList<String> letterCombinations(String digits) {
ArrayList<String> res = new ArrayList<String>();
ArrayList<String> preres = new ArrayList<String>();
res.add("");
for(int i = 0; i < digits.length(); i++) {
String letters = map.get(digits.charAt(i));
if (letters.length() == 0)
continue;
for(String str : res) {
for(int j = 0; j < letters.length(); j++)
preres.add(str + letters.charAt(j));
}
res = preres;
preres = new ArrayList<String>();
}
return res;
}
static final HashMap<Character,String> map = new HashMap<Character,String>(){{
put('1', "");
put('2',"abc");
put('3',"def");
put('4',"ghi");
put('5',"jkl");
put('6',"mno");
put('7',"pqrs");
put('8',"tuv");
put('9',"wxyz");
put('0', "");
}} ;
}
Je ne sais pas comment les numéros internationaux à 12 chiffres affectent la conception.
Edit: les numéros internationaux seront également traités
En Java utilisant la récursivité:
import Java.util.LinkedList;
import Java.util.List;
public class Main {
// Number-to-letter mappings in order from zero to nine
public static String mappings[][] = {
{"0"}, {"1"}, {"A", "B", "C"}, {"D", "E", "F"}, {"G", "H", "I"},
{"J", "K", "L"}, {"M", "N", "O"}, {"P", "Q", "R", "S"},
{"T", "U", "V"}, {"W", "X", "Y", "Z"}
};
public static void generateCombosHelper(List<String> combos,
String prefix, String remaining) {
// The current digit we are working with
int digit = Integer.parseInt(remaining.substring(0, 1));
if (remaining.length() == 1) {
// We have reached the last digit in the phone number, so add
// all possible prefix-digit combinations to the list
for (int i = 0; i < mappings[digit].length; i++) {
combos.add(prefix + mappings[digit][i]);
}
} else {
// Recursively call this method with each possible new
// prefix and the remaining part of the phone number.
for (int i = 0; i < mappings[digit].length; i++) {
generateCombosHelper(combos, prefix + mappings[digit][i],
remaining.substring(1));
}
}
}
public static List<String> generateCombos(String phoneNumber) {
// This will hold the final list of combinations
List<String> combos = new LinkedList<String>();
// Call the helper method with an empty prefix and the entire
// phone number as the remaining part.
generateCombosHelper(combos, "", phoneNumber);
return combos;
}
public static void main(String[] args) {
String phone = "3456789";
List<String> combos = generateCombos(phone);
for (String s : combos) {
System.out.println(s);
}
}
}
La solution évidente est une fonction permettant de mapper un chiffre sur une liste de touches, puis une fonction qui générerait les combinaisons possibles:
La première est évidente, la seconde est plus problématique car vous avez environ 3 ^ nombre de combinaisons de chiffres, ce qui peut être un très grand nombre.
Une façon de procéder consiste à examiner chaque possibilité de correspondance de chiffres sous forme de chiffre dans un nombre (base 4) et à mettre en œuvre quelque chose de proche du compteur (sautant par-dessus certaines occurrences, car il y a généralement moins de 4 lettres pouvant être mappées sur un chiffre ).
Les solutions les plus évidentes seraient les boucles imbriquées ou la récursivité, qui sont moins élégantes mais qui, à mon avis, sont valables.
Il faut également éviter les problèmes d’évolutivité (par exemple, conserver les possibilités en mémoire, etc.), car nous parlons de nombreuses combinaisons.
P.S. Une autre extension intéressante de la question serait la localisation.
En C++ (récursif):
string pattern[] = {"0",".,!","ABC","DEF","GHI","JKL","MNO","PQRS","TUV","WXYZ"};
ofstream keyout("keypad.txt");
void print_keypad(char* str, int k, vector<char> patt, int i){
if(str[k] != '\0')
{
int x = str[k] - '0';
for(int l = 0; l < pattern[x].length(); l++)
{
patt[i] = pattern[x][l];
print_keypad(str, k+1, patt, i+1);
}
keyout << endl;
}
else if(i == k)
{
string st(patt.data());
keyout << st << endl;
return;
}
}
Cette fonction peut être appelée avec 'k' et 'i' égaux à zéro.
Toute personne qui a besoin de plus d’illustrations pour comprendre la logique peut combiner la technique de récursion avec les résultats suivants:
ADG
ADH
ADI
AEG
AEH
AEI
AFG
AFH
AFI
BDG
BDH
BDI
BEG
BEH
BEI
BFG
BFH
...
Sur les claviers numériques, les textes et les chiffres sont placés sur la même touche. Par exemple, 2 a “ABC” si nous voulons écrire quelque chose commençant par “A”, nous devons taper la clé 2 une fois. Si nous voulions taper «B», appuyez deux fois deux fois sur la touche 2 pour taper «C». ci-dessous est une image de ce clavier.
clavier http://d2o58evtke57tz.cloudfront.net/wp-content/uploads/phoneKeyboard.png
Avec un clavier comme indiqué sur le schéma et un numéro à n chiffres, listez tous les mots possibles en appuyant sur ces chiffres.
Par exemple, si le nombre saisi est 234, les mots pouvant être formés sont les suivants (ordre alphabétique): Adg adh. cfg cfh cfi
Faisons quelques calculs en premier. Combien de mots sont possibles avec sept chiffres, chaque chiffre représentant n lettres? Pour le premier chiffre, nous avons au maximum quatre choix, et pour chaque choix pour la première lettre, nous avons au maximum quatre choix pour le deuxième chiffre, etc. C’est donc un calcul simple, ce sera O (4 ^ n). Comme les touches 0 et 1 n’ont pas d’alphabet correspondant et que de nombreux caractères ont 3 caractères, 4 ^ n serait la limite supérieure du nombre de mots et non le minimum de mots.
Faisons maintenant quelques exemples.
Pour un nombre supérieur à 234. Voyez-vous une tendance? Oui, nous remarquons que le dernier caractère est toujours soit G, H ou I et que, chaque fois qu’il réinitialise sa valeur de I à G, le chiffre situé à sa gauche est modifié . De même, chaque fois que l’avant-dernier alphabet réinitialise sa valeur, troisième dernier alphabet obtient des modifications et ainsi de suite. Le premier caractère ne se réinitialise qu'une fois lorsque nous avons généré tous les mots. Cela peut être regardé de l'autre côté aussi. C’est-à-dire que chaque fois que le caractère à la position i change, le caractère à la position i + 1 passe en revue tous les caractères possibles et crée un effet d’ondulation jusqu’à ce que nous atteignions la fin . nous devrions rompre car il n'y aura pas d'itération pour ces chiffres.
Prenons la deuxième approche car il sera facile de la mettre en œuvre en utilisant la récursivité. Nous allons jusqu'au bout et revenons un à un. Parfait état pour la récursion. recherchons le cas de base . Lorsque nous arrivons au dernier caractère, nous imprimons le mot avec tous les caractères possibles pour le dernier chiffre et le retour. Cas de base simple. Lorsque nous arrivons au dernier caractère, nous imprimons le mot avec tous les caractères possibles pour le dernier chiffre et le retour. Cas de base simple.
Voici la mise en œuvre de l'approche récursive en C pour imprimer tous les mots possibles correspondant à un nombre à n chiffres. Notez que le numéro d'entrée est représenté sous la forme d'un tableau afin de simplifier le code.
#include <stdio.h>
#include <string.h>
// hashTable[i] stores all characters that correspond to digit i in phone
const char hashTable[10][5] = {"", "", "abc", "def", "ghi", "jkl",
"mno", "pqrs", "tuv", "wxyz"};
// A recursive function to print all possible words that can be obtained
// by input number[] of size n. The output words are one by one stored
// in output[]
void printWordsUtil(int number[], int curr_digit, char output[], int n)
{
// Base case, if current output Word is prepared
int i;
if (curr_digit == n)
{
printf("%s ", output);
return ;
}
// Try all 3 possible characters for current digir in number[]
// and recur for remaining digits
for (i=0; i<strlen(hashTable[number[curr_digit]]); i++)
{
output[curr_digit] = hashTable[number[curr_digit]][i];
printWordsUtil(number, curr_digit+1, output, n);
if (number[curr_digit] == 0 || number[curr_digit] == 1)
return;
}
}
// A wrapper over printWordsUtil(). It creates an output array and
// calls printWordsUtil()
void printWords(int number[], int n)
{
char result[n+1];
result[n] ='\0';
printWordsUtil(number, 0, result, n);
}
//Driver program
int main(void)
{
int number[] = {2, 3, 4};
int n = sizeof(number)/sizeof(number[0]);
printWords(number, n);
return 0;
}
Sortie:
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
La complexité du temps:
La complexité temporelle du code ci-dessus est O (4 ^ n), où n est le nombre de chiffres du nombre saisi.
Références:
En JavaScript. Une classe CustomCounter prend en charge l’incrémentation des index. Ensuite, indiquez simplement les différentes combinaisons possibles.
var CustomCounter = function(min, max) {
this.min = min.slice(0)
this.max = max.slice(0)
this.curr = this.min.slice(0)
this.length = this.min.length
}
CustomCounter.prototype.increment = function() {
for (var i = this.length - 1, ii = 0; i >= ii; i--) {
this.curr[i] += 1
if (this.curr[i] > this.max[i]) {
this.curr[i] = 0
} else {
break
}
}
}
CustomCounter.prototype.is_max = function() {
for (var i = 0, ii = this.length; i < ii; ++i) {
if (this.curr[i] !== this.max[i]) {
return false
}
}
return true
}
var PhoneNumber = function(phone_number) {
this.phone_number = phone_number
this.combinations = []
}
PhoneNumber.number_to_combinations = {
1: ['1']
, 2: ['2', 'a', 'b', 'c']
, 3: ['3', 'd', 'e', 'f']
, 4: ['4', 'g', 'h', 'i']
, 5: ['5', 'j', 'k', 'l']
, 6: ['6', 'm', 'n', 'o']
, 7: ['7', 'p', 'q', 'r', 's']
, 8: ['8', 't', 'u', 'v']
, 9: ['9', 'w', 'x', 'y', 'z']
, 0: ['0', '+']
}
PhoneNumber.prototype.get_combination_by_digit = function(digit) {
return PhoneNumber.number_to_combinations[digit]
}
PhoneNumber.prototype.add_combination_by_indexes = function(indexes) {
var combination = ''
for (var i = 0, ii = indexes.length; i < ii; ++i) {
var phone_number_digit = this.phone_number[i]
combination += this.get_combination_by_digit(phone_number_digit)[indexes[i]]
}
this.combinations.Push(combination)
}
PhoneNumber.prototype.update_combinations = function() {
var min_indexes = []
, max_indexes = []
for (var i = 0, ii = this.phone_number.length; i < ii; ++i) {
var digit = this.phone_number[i]
min_indexes.Push(0)
max_indexes.Push(this.get_combination_by_digit(digit).length - 1)
}
var c = new CustomCounter(min_indexes, max_indexes)
while(true) {
this.add_combination_by_indexes(c.curr)
c.increment()
if (c.is_max()) {
this.add_combination_by_indexes(c.curr)
break
}
}
}
var phone_number = new PhoneNumber('120')
phone_number.update_combinations()
console.log(phone_number.combinations)
#include <sstream>
#include <map>
#include <vector>
map< int, string> keyMap;
void MakeCombinations( string first, string joinThis , vector<string>& eachResult )
{
if( !first.size() )
return;
int length = joinThis.length();
vector<string> result;
while( length )
{
string each;
char firstCharacter = first.at(0);
each = firstCharacter;
each += joinThis[length -1];
length--;
result.Push_back(each);
}
first = first.substr(1);
vector<string>::iterator begin = result.begin();
vector<string>::iterator end = result.end();
while( begin != end)
{
eachResult.Push_back( *begin);
begin++;
}
return MakeCombinations( first, joinThis, eachResult);
}
void ProduceCombinations( int inNumber, vector<string>& result)
{
vector<string> inputUnits;
int number = inNumber;
while( number )
{
int lastdigit ;
lastdigit = number % 10;
number = number/10;
inputUnits.Push_back( keyMap[lastdigit]);
}
if( inputUnits.size() == 2)
{
MakeCombinations(inputUnits[0], inputUnits[1], result);
}
else if ( inputUnits.size() > 2 )
{
MakeCombinations( inputUnits[0] , inputUnits[1], result);
vector<string>::iterator begin = inputUnits.begin();
vector<string>::iterator end = inputUnits.end();
begin += 2;
while( begin != end )
{
vector<string> intermediate = result;
vector<string>::iterator ibegin = intermediate.begin();
vector<string>::iterator iend = intermediate.end();
while( ibegin != iend)
{
MakeCombinations( *ibegin , *begin, result);
//resultbegin =
ibegin++;
}
begin++;
}
}
else
{
}
return;
}
int _tmain(int argc, _TCHAR* argv[])
{
keyMap[1] = "";
keyMap[2] = "abc";
keyMap[3] = "def";
keyMap[4] = "ghi";
keyMap[5] = "jkl";
keyMap[6] = "mno";
keyMap[7] = "pqrs";
keyMap[8] = "tuv";
keyMap[9] = "wxyz";
keyMap[0] = "";
string inputStr;
getline(cin, inputStr);
int number = 0;
int length = inputStr.length();
int tens = 1;
while( length )
{
number += tens*(inputStr[length -1] - '0');
length--;
tens *= 10;
}
vector<string> r;
ProduceCombinations(number, r);
cout << "[" ;
vector<string>::iterator begin = r.begin();
vector<string>::iterator end = r.end();
while ( begin != end)
{
cout << *begin << "," ;
begin++;
}
cout << "]" ;
return 0;
}
C'est le port C # de this answer.
Code
public class LetterCombinations
{
private static readonly Dictionary<string, string> Representations = new Dictionary<string, string>
{
{"2", "abc" },
{"3", "def" },
{"4", "ghi" },
{"5", "jkl" },
{"6", "mno" },
{"7", "pqrs" },
{"8", "tuv" },
{"9", "wxyz" },
};
public static List<string> FromPhoneNumber(string phoneNumber)
{
var result = new List<string> { string.Empty };
// go through each number in the phone
for (int i = 0; i < phoneNumber.Length; i++)
{
var pre = new List<string>();
foreach (var str in result)
{
var letters = Representations[phoneNumber[i].ToString()];
// go through each representation of the number
for (int j = 0; j < letters.Length; j++)
{
pre.Add(str + letters[j]);
}
}
result = pre;
}
return result;
}
}
Tests unitaires
public class UnitTest
{
[TestMethod]
public void One_Digit_Yields_Three_Representations()
{
var sut = "2";
var expected = new List<string>{ "a", "b", "c" };
var actualResults = LetterCombinations.FromPhoneNumber(sut);
CollectionAssert.AreEqual(expected, actualResults);
}
[TestMethod]
public void Two_Digits_Yield_Nine_Representations()
{
var sut = "22";
var expected = new List<string> { "aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc" };
var actualResults = LetterCombinations.FromPhoneNumber(sut);
CollectionAssert.AreEqual(expected, actualResults);
}
[TestMethod]
public void Three_Digits_Yield_ThirtyNine_Representations()
{
var sut = "222";
var actualResults = LetterCombinations.FromPhoneNumber(sut);
var possibleCombinations = Math.Pow(3,3); //27
Assert.AreEqual(possibleCombinations, actualResults.Count);
}
}
namespace WordsFromPhoneNumber
{
/// <summary>
/// Summary description for WordsFromPhoneNumber
/// </summary>
[TestClass]
public class WordsFromPhoneNumber
{
private static string[] Chars = { "0", "1", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ" };
public WordsFromPhoneNumber()
{
//
// TODO: Add constructor logic here
//
}
#region overhead
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void TestMethod1()
{
IList<string> words = Words(new int[] { 2 });
Assert.IsNotNull(words, "null");
Assert.IsTrue(words.Count == 3, "count");
Assert.IsTrue(words[0] == "A", "a");
Assert.IsTrue(words[1] == "B", "b");
Assert.IsTrue(words[2] == "C", "c");
}
[TestMethod]
public void TestMethod23()
{
IList<string> words = Words(new int[] { 2 , 3});
Assert.IsNotNull(words, "null");
Assert.AreEqual(words.Count , 9, "count");
Assert.AreEqual(words[0] , "AD", "AD");
Assert.AreEqual(words[1] , "AE", "AE");
Assert.AreEqual(words[2] , "AF", "AF");
Assert.AreEqual(words[3] , "BD", "BD");
Assert.AreEqual(words[4] , "BE", "BE");
Assert.AreEqual(words[5] , "BF", "BF");
Assert.AreEqual(words[6] , "CD", "CD");
Assert.AreEqual(words[7] , "CE", "CE");
Assert.AreEqual(words[8] , "CF", "CF");
}
[TestMethod]
public void TestAll()
{
int[] number = new int [4];
Generate(number, 0);
}
private void Generate(int[] number, int index)
{
for (int x = 0; x <= 9; x += 3)
{
number[index] = x;
if (index == number.Length - 1)
{
var w = Words(number);
Assert.IsNotNull(w);
foreach (var xx in number)
{
Console.Write(xx.ToString());
}
Console.WriteLine(" possible words:\n");
foreach (var ww in w)
{
Console.Write("{0} ", ww);
}
Console.WriteLine("\n\n\n");
}
else
{
Generate(number, index + 1);
}
}
}
#endregion
private IList<string> Words(int[] number)
{
List<string> words = new List<string>(100);
Assert.IsNotNull(number, "null");
Assert.IsTrue(number.Length > 0, "length");
StringBuilder Word = new StringBuilder(number.Length);
AddWords(number, 0, Word, words);
return words;
}
private void AddWords(int[] number, int index, StringBuilder Word, List<string> words)
{
Assert.IsTrue(index < number.Length, "index < length");
Assert.IsTrue(number[index] >= 0, "number >= 0");
Assert.IsTrue(number[index] <= 9, "number <= 9");
foreach (var c in Chars[number[index]].ToCharArray())
{
Word.Append(c);
if (index < number.Length - 1)
{
AddWords(number, index + 1, Word, words);
}
else
{
words.Add(Word.ToString());
}
Word.Length = Word.Length - 1;
}
}
}
}
Une solution Python est très économique et, du fait qu’elle utilise des générateurs, elle est efficace en termes d’utilisation de la mémoire.
import itertools
keys = dict(enumerate('::ABC:DEF:GHI:JKL:MNO:PQRS:TUV:WXYZ'.split(':')))
def words(number):
digits = map(int, str(number))
for ls in itertools.product(*map(keys.get, digits)):
yield ''.join(ls)
for w in words(258):
print w
De toute évidence, itertools.product
résout la plupart des problèmes pour vous. Mais l'écrire soi-même n'est pas difficile. Voici une solution à la volée qui consiste à réutiliser le tableau result
pour générer toutes les solutions, et une clôture f
pour capturer les mots générés. Combinés, ils donnent à O (log n) une utilisation de la mémoire dans product
.
package main
import (
"bytes"
"fmt"
"strconv"
)
func product(choices [][]byte, result []byte, i int, f func([]byte)) {
if i == len(result) {
f(result)
return
}
for _, c := range choices[i] {
result[i] = c
product(choices, result, i+1, f)
}
}
var keys = bytes.Split([]byte("::ABC:DEF:GHI:JKL:MNO:PQRS:TUV:WXYZ"), []byte(":"))
func words(num int, f func([]byte)) {
ch := [][]byte{}
for _, b := range strconv.Itoa(num) {
ch = append(ch, keys[b-'0'])
}
product(ch, make([]byte, len(ch)), 0, f)
}
func main() {
words(256, func(b []byte) { fmt.Println(string(b)) })
}
Utilisez une liste L où L [i] = les symboles que le chiffre i peut représenter.
L [1] = @,.,! (par exemple) L [2] = a, b, c
Etc.
Ensuite, vous pouvez faire quelque chose comme ça (pseudo-C):
void f(int k, int st[])
{
if ( k > numberOfDigits )
{
print contents of st[];
return;
}
for each character c in L[Digit At Position k]
{
st[k] = c;
f(k + 1, st);
}
}
En supposant que chaque liste contient 3 caractères, nous avons 3 ^ 7 possibilités pour 7 chiffres et 3 ^ 12 pour 12, ce qui n’est pas beaucoup. Si vous avez besoin de toutes les combinaisons, je ne vois pas de meilleure solution. Vous pouvez éviter la récursion et tout le reste, mais vous n'allez pas obtenir quelque chose de beaucoup plus rapide que cela, quoi qu'il arrive.
Vous trouvez la source (Scala) ici et un applet de travail ici.
Puisque 0 et 1 ne correspondent pas à des caractères, ils construisent des points de rupture naturels en nombres. Mais ils ne sont pas présents dans tous les nombres (sauf 0 au début). Des nombres plus longs, comme +49567892345 à partir de 9 chiffres, peuvent conduire à OutOfMemoryErrors. Il serait donc préférable de scinder un nombre en groupes comme
à voir, si vous pouvez comprendre les parties les plus courtes. J'ai écrit un tel programme et testé quelques chiffres de mes amis, mais je trouvais rarement des combinaisons de mots plus courts, qui pouvaient être vérifiées dans un dictionnaire pour les faire correspondre, sans parler de mots longs et simples.
Ma décision était donc de ne supporter que la recherche, pas d’automatisation complète, en affichant les combinaisons possibles, en encourageant la division manuelle du numéro, voire plusieurs fois.
J'ai donc trouvé + -RAD JUNG (+ -bycicle boy).
Si vous acceptez des fautes d'orthographe, des abréviations, des mots étrangers, des chiffres en tant que mots, des chiffres en mots et des noms, votre chance de trouver une solution est bien meilleure que de ne pas bidouiller.
246848 => 2hot4u (too hot for you)
466368 => goodn8 (good night)
1325 => 1FCK (Football club)
53517 => JDK17 (Java Developer Kit)
sont des choses qu'un humain pourrait observer - il est assez difficile de faire en sorte qu'un algorithme trouve de telles choses.
public class Permutation {
//display all combination attached to a 3 digit number
public static void main(String ar[]){
char data[][]= new char[][]{{'a','k','u'},
{'b','l','v'},
{'c','m','w'},
{'d','n','x'},
{'e','o','y'},
{'f','p','z'},
{'g','q','0'},
{'h','r','0'},
{'i','s','0'},
{'j','t','0'}};
int num1, num2, num3=0;
char tempdata[][]= new char[3][3];
StringBuilder number = new StringBuilder("324"); // a 3 digit number
//copy data to a tempdata array-------------------
num1= Integer.parseInt(number.substring(0,1));
tempdata[0] = data[num1];
num2= Integer.parseInt(number.substring(1,2));
tempdata[1] = data[num2];
num3= Integer.parseInt(number.substring(2,3));
tempdata[2] = data[num3];
//display all combinations--------------------
char temp2[][]=tempdata;
char tempd, tempd2;
int i,i2, i3=0;
for(i=0;i<3;i++){
tempd = temp2[0][i];
for (i2=0;i2<3;i2++){
tempd2 = temp2[1][i2];
for(i3=0;i3<3;i3++){
System.out.print(tempd);
System.out.print(tempd2);
System.out.print(temp2[2][i3]);
System.out.println();
}//for i3
}//for i2
}
}
}//end of class
Solution Scala:
def mnemonics(phoneNum: String, dict: IndexedSeq[String]): Iterable[String] = {
def mnemonics(d: Int, prefix: String): Seq[String] = {
if (d >= phoneNum.length) {
Seq(prefix)
} else {
for {
ch <- dict(phoneNum.charAt(d).asDigit)
num <- mnemonics(d + 1, s"$prefix$ch")
} yield num
}
}
mnemonics(0, "")
}
En supposant que chaque chiffre corresponde à au plus 4 caractères, le nombre d'appels récursifs T
satisfasse l'inégalité T(n) <= 4T(n-1)
, qui est de l'ordre 4^n
.
Cette approche utilise R et consiste à convertir d'abord le dictionnaire en sa représentation numérique correspondante, puis à l'utiliser comme référence.
La conversion ne prend que 1 seconde sur ma machine (à partir du dictionnaire Unix natif d’environ 100 000 mots), et les recherches typiques de 100 entrées de chiffres différentes prennent au total 0,1 seconde:
library(data.table)
#example dictionary
dict.orig = tolower(readLines("/usr/share/dict/american-english"))
#split each Word into its constituent letters
#words shorter than the longest padded with "" for simpler retrieval
dictDT = setDT(tstrsplit(dict.orig, split = "", fill = ""))
#lookup table for conversion
#NB: the following are found in the dictionary and would need
# to be handled separately -- ignoring here
# (accents should just be appended to
# matches for unaccented version):
# c("", "'", "á", "â", "å", "ä",
# "ç", "é", "è", "ê", "í", "ñ",
# "ó", "ô", "ö", "û", "ü")
lookup = data.table(num = c(rep('2', 3), rep('3', 3), rep('4', 3),
rep('5', 3), rep('6', 3), rep('7', 4),
rep('8', 3), rep('9', 4)),
let = letters)
#using the lookup table, convert to numeric
for (col in names(dictDT)) {
dictDT[lookup, (col) := i.num, on = setNames("let", col)]
}
#back to character vector
dict.num = do.call(paste0, dictDT)
#sort both for faster vector search
idx = order(dict.num)
dict.num = dict.num[idx]
dict.orig = dict.orig[idx]
possibilities = function(input) dict.orig[dict.num == input]
#sample output:
possibilities('269')
# [1] "amy" "bmw" "cox" "coy" "any" "bow" "box" "boy" "cow" "cox" "coy"
possibilities('22737')
# [1] "acres" "bards" "barer" "bares" "barfs" "baser" "bases" "caper"
# [9] "capes" "cards" "cares" "cases"
Je l'ai essayé dans Ruby, et ai proposé une méthode différente, ce n'est probablement pas efficace, comme le temps et l'espace O (?) À ce stade, mais j'aime bien parce qu'il utilise la méthode Array.product de Ruby. Qu'est-ce que tu penses?
EDIT: Je vois une solution très similaire dans Python ci-dessus, mais je ne l'avais pas vu quand j'ai ajouté ma réponse
def phone_to_abc(phone)
phone_abc = [
'0', '1', 'abc', 'def', 'ghi',
'jkl', 'mno', 'pqrs', 'tuv', 'wxyz'
]
phone_map = phone.chars.map { |x| phone_abc[x.to_i].chars }
result = phone_map[0]
for i in 1..phone_map.size-1
result = result.product(phone_map[i])
end
result.each { |x|
puts "#{x.join}"
}
end
phone_to_abc('86352')
J'ai réécrit la dernière réponse à ceci ( mentionné ci-dessus ), de C à Java. J'ai également inclus le support pour 0 et 1 (comme 0 et 1) car des nombres tels que 555-5055 ne fonctionnaient pas du tout avec le code ci-dessus.
C'est ici. Certains commentaires sont préservés.
public static void printPhoneWords(int[] number) {
char[] output = new char[number.length];
printWordsUtil(number,0,output);
}
static String[] phoneKeys= new String[]{"0", "1", "ABC", "DEF", "GHI", "JKL",
"MNO", "PQRS", "TUV", "WXYZ"};
private static void printWordsUtil(int[] number, int curDigIndex, char[] output) {
// Base case, if current output Word is done
if (curDigIndex == output.length) {
System.out.print(String.valueOf(output) + " ");
return;
}
// Try all 3-4 possible characters for the current digit in number[]
// and recurse for the remaining digits
char curPhoneKey[] = phoneKeys[number[curDigIndex]].toCharArray();
for (int i = 0; i< curPhoneKey.length ; i++) {
output[curDigIndex] = curPhoneKey[i];
printWordsUtil(number, curDigIndex+1, output);
if (number[curDigIndex] <= 1) // for 0 or 1
return;
}
}
public static void main(String[] args) {
int number[] = {2, 3, 4};
printPhoneWords(number);
System.out.println();
}
static final String[] keypad = {"", "", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"};
String[] printAlphabet(int num){
if (num >= 0 && num < 10){
String[] retStr;
if (num == 0 || num ==1){
retStr = new String[]{""};
} else {
retStr = new String[keypad[num].length()];
for (int i = 0 ; i < keypad[num].length(); i++){
retStr[i] = String.valueOf(keypad[num].charAt(i));
}
}
return retStr;
}
String[] nxtStr = printAlphabet(num/10);
int digit = num % 10;
String[] curStr = null;
if(digit == 0 || digit == 1){
curStr = new String[]{""};
} else {
curStr = new String[keypad[digit].length()];
for (int i = 0; i < keypad[digit].length(); i++){
curStr[i] = String.valueOf(keypad[digit].charAt(i));
}
}
String[] result = new String[curStr.length * nxtStr.length];
int k=0;
for (String cStr : curStr){
for (String nStr : nxtStr){
result[k++] = nStr + cStr;
}
}
return result;
}
private List<string> strs = new List<string>();
char[] numbersArray;
private int End = 0;
private int numberOfStrings;
private void PrintLetters(string numbers)
{
this.End = numbers.Length;
this.numbersArray = numbers.ToCharArray();
this.PrintAllCombinations(this.GetCharacters(this.numbersArray[0]), string.Empty, 0);
}
private void PrintAllCombinations(char[] letters, string output, int depth)
{
depth++;
for (int i = 0; i < letters.Length; i++)
{
if (depth != this.End)
{
output += letters[i];
this.PrintAllCombinations(this.GetCharacters(Convert.ToChar(this.numbersArray[depth])), output, depth);
output = output.Substring(0, output.Length - 1);
}
else
{
Console.WriteLine(output + letters[i] + (++numberOfStrings));
}
}
}
private char[] GetCharacters(char x)
{
char[] arr;
switch (x)
{
case '0': arr = new char[1] { '.' };
return arr;
case '1': arr = new char[1] { '.' };
return arr;
case '2': arr = new char[3] { 'a', 'b', 'c' };
return arr;
case '3': arr = new char[3] { 'd', 'e', 'f' };
return arr;
case '4': arr = new char[3] { 'g', 'h', 'i' };
return arr;
case '5': arr = new char[3] { 'j', 'k', 'l' };
return arr;
case '6': arr = new char[3] { 'm', 'n', 'o' };
return arr;
case '7': arr = new char[4] { 'p', 'q', 'r', 's' };
return arr;
case '8': arr = new char[3] { 't', 'u', 'v' };
return arr;
case '9': arr = new char[4] { 'w', 'x', 'y', 'z' };
return arr;
default: return null;
}
}
En voici un pour la douleur C. Celui-ci n’est probablement pas efficace (en fait, je ne le pense pas du tout). Mais il y a des aspects intéressants à cela.
Ce qui est bien à propos de cela, c'est qu'il n'y a pas de limite réelle à la taille de la chaîne (pas de limite de caractères). Cela vous permet de générer des chaînes de plus en plus longues au besoin en attendant simplement.
#include <stdlib.h>
#include <stdio.h>
#define CHARACTER_RANGE 95 // The range of valid password characters
#define CHARACTER_OFFSET 32 // The offset of the first valid character
void main(int argc, char *argv[], char *env[])
{
int i;
long int string;
long int worker;
char *guess; // Current Generation
guess = (char*)malloc(1); // Allocate it so free doesn't fail
int cur;
for ( string = 0; ; string++ )
{
worker = string;
free(guess);
guess = (char*)malloc((string/CHARACTER_RANGE+1)*sizeof(char)); // Alocate for the number of characters we will need
for ( i = 0; worker > 0 && i < string/CHARACTER_RANGE + 1; i++ ) // Work out the string
{
cur = worker % CHARACTER_RANGE; // Take off the last digit
worker = (worker - cur) / CHARACTER_RANGE; // Advance the digits
cur += CHARACTER_OFFSET;
guess[i] = cur;
}
guess[i+1] = '\0'; // NULL terminate our string
printf("%s\t%d\n", guess, string);
}
}
/**
* Simple Java implementation without any input/error checking
* (expects all digits as input)
**/
public class PhoneSpeller
{
private static final char[][] _letters = new char[][]{
{'0'},
{'1'},
{'A', 'B', 'C'},
{'D', 'E', 'F'},
{'G', 'H', 'I'},
{'J', 'K', 'L'},
{'M', 'N', 'O'},
{'P', 'Q', 'R', 'S'},
{'T', 'U', 'V'},
{'W', 'X', 'Y', 'Z'}
};
public static void main(String[] args)
{
if (args.length != 1)
{
System.out.println("Please run again with your phone number (no dashes)");
System.exit(0);
}
recursive_phoneSpell(args[0], 0, new ArrayList<String>());
}
private static void recursive_phoneSpell(String arg, int index, List<String> results)
{
if (index == arg.length())
{
printResults(results);
return;
}
int num = Integer.parseInt(arg.charAt(index)+"");
if (index==0)
{
for (int j = 0; j<_letters[num].length; j++)
{
results.add(_letters[num][j]+"");
}
recursive_phoneSpell(arg, index+1, results);
}
else
{
List<String> combos = new ArrayList<String>();
for (int j = 0; j<_letters[num].length; j++)
{
for (String result : results)
{
combos.add(result+_letters[num][j]);
}
}
recursive_phoneSpell(arg, index+1, combos);
}
}
private static void printResults(List<String> results)
{
for (String result : results)
{
System.out.println(result);
}
}
}
C'est un algorithme récursif en C++ 11.
#include <iostream>
#include <array>
#include <list>
std::array<std::string, 10> pm = {
"0", "1", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"
};
void generate_mnemonic(const std::string& numbers, size_t i, std::string& m,
std::list<std::string>& mnemonics)
{
// Base case
if (numbers.size() == i) {
mnemonics.Push_back(m);
return;
}
for (char c : pm[numbers[i] - '0']) {
m[i] = c;
generate_mnemonic(numbers, i + 1, m, mnemonics);
}
}
std::list<std::string> phone_number_mnemonics(const std::string& numbers)
{
std::list<std::string> mnemonics;
std::string m(numbers.size(), 0);
generate_mnemonic(numbers, 0, m, mnemonics);
return mnemonics;
}
int main() {
std::list<std::string> result = phone_number_mnemonics("2276696");
for (const std::string& s : result) {
std::cout << s << std::endl;
}
return 0;
}
Une option dans Objective-C:
- (NSArray *)lettersForNumber:(NSNumber *)number {
switch ([number intValue]) {
case 2:
return @[@"A",@"B",@"C"];
case 3:
return @[@"D",@"E",@"F"];
case 4:
return @[@"G",@"H",@"I"];
case 5:
return @[@"J",@"K",@"L"];
case 6:
return @[@"M",@"N",@"O"];
case 7:
return @[@"P",@"Q",@"R",@"S"];
case 8:
return @[@"T",@"U",@"V"];
case 9:
return @[@"W",@"X",@"Y",@"Z"];
default:
return nil;
}
}
- (NSArray *)letterCombinationsForNumbers:(NSArray *)numbers {
NSMutableArray *combinations = [[NSMutableArray alloc] initWithObjects:@"", nil];
for (NSNumber *number in numbers) {
NSArray *lettersNumber = [self lettersForNumber:number];
//Ignore numbers that don't have associated letters
if (lettersNumber.count == 0) {
continue;
}
NSMutableArray *currentCombinations = [combinations mutableCopy];
combinations = [[NSMutableArray alloc] init];
for (NSString *letter in lettersNumber) {
for (NSString *letterInResult in currentCombinations) {
NSString *newString = [NSString stringWithFormat:@"%@%@", letterInResult, letter];
[combinations addObject:newString];
}
}
}
return combinations;
}
</ pre> </ code>
J'ai mis en place une mémoire cache qui a permis de réduire le nombre de récursions. Ce cache évitera de scanner les lettres qu'il avait déjà faites pour les combinaisons précédentes. Dans un cas, il s'agissait de boucles de 120 000 $, après la mise en œuvre du cache, il a été réduit à 40 000 $.
private List<String> generateWords(String phoneNumber) {
List<String> words = new LinkedList<String>();
List<String> wordsCache = new LinkedList<String>();
this.generatePossibleWords("", phoneNumber, words, wordsCache);
return words;
}
private void generatePossibleWords(String prefix, String remainder,
List<String> words, List<String> wordsCache) {
int index = Integer.parseInt(remainder.substring(0, 1));
for (int i = 0; i < phoneKeyMapper.get(index).size(); i++) {
String mappedChar = phoneKeyMapper.get(index).get(i);
if (prefix.equals("") && !wordsCache.isEmpty()) {
for (String Word : wordsCache) {
words.add(mappedChar + Word);
}
} else {
if (remainder.length() == 1) {
String stringToBeAdded = prefix + mappedChar;
words.add(stringToBeAdded);
wordsCache.add(stringToBeAdded.substring(1));
LOGGER.finest("adding stringToBeAdded = " + stringToBeAdded.substring(1));
} else {
generatePossibleWords(prefix + mappedChar,
remainder.substring(1), words, wordsCache);
}
}
}
}
private void createPhoneNumberMapper() {
if (phoneKeyMapper == null) {
phoneKeyMapper = new ArrayList<>();
phoneKeyMapper.add(0, new ArrayList<String>());
phoneKeyMapper.add(1, new ArrayList<String>());
phoneKeyMapper.add(2, new ArrayList<String>());
phoneKeyMapper.get(2).add("A");
phoneKeyMapper.get(2).add("B");
phoneKeyMapper.get(2).add("C");
phoneKeyMapper.add(3, new ArrayList<String>());
phoneKeyMapper.get(3).add("D");
phoneKeyMapper.get(3).add("E");
phoneKeyMapper.get(3).add("F");
phoneKeyMapper.add(4, new ArrayList<String>());
phoneKeyMapper.get(4).add("G");
phoneKeyMapper.get(4).add("H");
phoneKeyMapper.get(4).add("I");
phoneKeyMapper.add(5, new ArrayList<String>());
phoneKeyMapper.get(5).add("J");
phoneKeyMapper.get(5).add("K");
phoneKeyMapper.get(5).add("L");
phoneKeyMapper.add(6, new ArrayList<String>());
phoneKeyMapper.get(6).add("M");
phoneKeyMapper.get(6).add("N");
phoneKeyMapper.get(6).add("O");
phoneKeyMapper.add(7, new ArrayList<String>());
phoneKeyMapper.get(7).add("P");
phoneKeyMapper.get(7).add("Q");
phoneKeyMapper.get(7).add("R");
phoneKeyMapper.get(7).add("S");
phoneKeyMapper.add(8, new ArrayList<String>());
phoneKeyMapper.get(8).add("T");
phoneKeyMapper.get(8).add("U");
phoneKeyMapper.get(8).add("V");
phoneKeyMapper.add(9, new ArrayList<String>());
phoneKeyMapper.get(9).add("W");
phoneKeyMapper.get(9).add("X");
phoneKeyMapper.get(9).add("Y");
phoneKeyMapper.get(9).add("Z");
}
}
Au cours d'un entretien d'embauche, j'ai reçu cette question concernant la création d'un tableau et l'impression de toutes les combinaisons de lettres possibles d'un numéro de téléphone. Au cours de l'entretien, l'intervieweur m'a murmuré à propos de la récursivité et de l'impossibilité d'utiliser des boucles. Très anormal pour moi de recevoir les commentaires d'un autre programmeur, j'ai fait confiance à ses conseils plutôt qu'à mes propres cours et j'ai procédé à la rédaction d'un désordre de récursion bâclé. Ça ne s'est pas si bien passé. Avant de recevoir des commentaires, comme je n’avais jamais eu ce problème auparavant, mon cerveau calculait la formule mathématique reproductible sous-jacente. Des chuchotements à couper le souffle, "je ne peux pas simplement multiplier par trois, certains d'entre eux sont quatre" alors que mon esprit commençait à courir contre une horloge courte en pensant à une réponse tout en commençant à en écrire une autre. Ce n'est que vers la fin de la semaine que j'ai reçu mon appel pour me faire savoir la triste nouvelle. C'était plus tard cette nuit-là, j'ai décidé de voir s'il s'agissait vraiment d'un problème de récursivité. Il s'avère que pour moi ce n'est pas.
Ma solution ci-dessous est codée en PHP, est non-récursive, fonctionne avec n'importe quelle longueur d'entrée et j'ai même inclus quelques commentaires pour aider à décrire la signification de mes variables. C'est ma réponse finale officielle et immuable à cette question. J'espère que cela aidera quelqu'un d'autre à l'avenir, n'hésitez pas à le traduire dans d'autres langues.
La méthode Me consiste à calculer le nombre total de combinaisons et à créer un tampon suffisamment grand pour contenir chaque octet. La longueur de ma mémoire tampon est la même que celle que vous attendez d'un algorithme récursif fonctionnel. Je fais un tableau qui contient les groupes de lettres qui représentent chaque nombre. Ma méthode fonctionne principalement parce que votre total sera toujours divisible par le nombre de lettres du groupe actuel. Si vous pouvez imaginer dans votre tête une liste verticale de la sortie de cet algorithme, ou voir la liste verticalement par opposition à une liste horizontale des combinaisons, mon algorithme commencera à avoir un sens. Cet algorithme nous permet de parcourir chaque octet verticalement de haut en bas en commençant par la gauche plutôt que horizontalement de gauche à droite et de renseigner chaque octet individuellement sans nécessiter de récursion. J'utilise le tampon comme si c'était un tableau d'octets pour gagner du temps et de l'énergie.
NON RECURSIF, ITERATIVE PHP
<?php
// Display all possible combinations of letters for each number.
$input = '23456789';
// ====================
if(!isset($input[0]))
die('Nothing to see here!');
$phone_letters = array(
2 => array('a', 'b', 'c'),
3 => array('d', 'e', 'f'),
4 => array('g', 'h', 'i'),
5 => array('j', 'k', 'l'),
6 => array('m', 'n', 'o'),
7 => array('p', 'q', 'r', 's'),
8 => array('t', 'u', 'v'),
9 => array('w', 'x', 'y', 'z')
);
$groups = array();
$combos_total = 1;
$l = strlen($input);
for($i = 0; $i < $l; ++$i) {
$groups[] = $phone_letters[$input[$i]];
$combos_total *= count($phone_letters[$input[$i]]);
}
$count = $combos_total / count($groups[0]);
$combos = array_fill(0, $combos_total, str_repeat(chr(0), strlen($input)));
for(
$group = 0, // Index for the current group of letters.
$groups_count = count($groups), // Total number of letter groups.
$letters = count($groups[0]), // Total number of letters in the current group.
$width = $combos_total, // Number of bytes to repeat the current letter.
$repeat = 1; // Total number of times the group will repeat.
;
) {
for($byte = 0, $width /= $letters, $r = 0; $r < $repeat; ++$r)
for($l = 0; $l < $letters; ++$l)
for($w = 0; $w < $width; ++$w)
$combos[$byte++][$group] = $groups[$group][$l];
if(++$group < $groups_count) {
$repeat *= $letters;
$letters = count($groups[$group]);
}
else
break;
}
// ====================
if(is_array($combos)) {
print_r($combos);
echo 'Total combos:', count($combos), "\n";
}
else
echo 'No combos.', "\n";
echo 'Expected combos: ', $combos_total, "\n";
OBJET PHP NON RÉCURSIF, NON ITERATIF, SANS BUFFER, FILE AU FILE, MAIS UNIQUEMENT +, NON RECURSIF ET UTILISANT UN GRAND ENDIAN MULTI-BASE
Tandis que je travaillais sur la nouvelle maison l’autre jour, j’ai réalisé que je pouvais utiliser les mathématiques de ma première fonction, associées à ma connaissance de base, pour traiter toutes les combinaisons de lettres possibles de mes entrées sous forme de nombre multidimensionnel.
Mon objet fournit les fonctions nécessaires pour stocker une combinaison préférée dans une base de données, convertir des lettres et des chiffres si nécessaire, choisir une combinaison n'importe où dans l'espace de combinaison en utilisant une combinaison ou un octet préféré, et tout fonctionne très bien avec le multi-threading. .
Cela étant dit, en utilisant mon objet, je peux fournir une deuxième réponse qui utilise la base, pas de tampon, pas d'itérations et surtout pas de récursion.
<?php
class phone {
public static $letters = array(
2 => array('a', 'b', 'c'),
3 => array('d', 'e', 'f'),
4 => array('g', 'h', 'i'),
5 => array('j', 'k', 'l'),
6 => array('m', 'n', 'o'),
7 => array('p', 'q', 'r', 's'),
8 => array('t', 'u', 'v'),
9 => array('w', 'x', 'y', 'z')
);
// Convert a letter into its respective number.
public static function letter_number($letter) {
if(!isset($letter[0]) || isset($letter[1]))
return false;
for($i = 2; $i < 10; ++$i)
if(in_array($letter, phone::$letters[$i], true))
return $i;
return false;
}
// Convert letters into their respective numbers.
public static function letters_numbers($letters) {
if(!isset($letters[0]))
return false;
$length = strlen($letters);
$numbers = str_repeat(chr(0), $length);
for($i = 0; $i < $length; ++$i) {
for($j = 2; $j < 10; ++$j) {
if(in_array($letters[$i], phone::$letters[$j], true)) {
$numbers[$i] = $j;
break;
}
}
}
return $numbers;
}
// Calculate the maximum number of combinations that could occur within a particular input size.
public static function combination_size($groups) {
return $groups <= 0 ? false : pow(4, $groups);
}
// Calculate the minimum bytes reqired to store a group using the current input.
public static function combination_bytes($groups) {
if($groups <= 0)
return false;
$size = $groups * 4;
$bytes = 0;
while($groups !== 0) {
$groups >> 8;
++$bytes;
}
return $bytes;
}
public $input = '';
public $input_len = 0;
public $combinations_total = 0;
public $combinations_length = 0;
private $iterations = array();
private $branches = array();
function __construct($number) {
if(!isset($number[0]))
return false;
$this->input = $number;
$input_len = strlen($number);
$combinations_total = 1;
for($i = 0; $i < $input_len; ++$i) {
$combinations_total *= count(phone::$letters[$number[$i]]);
}
$this->input_len = $input_len;
$this->combinations_total = $combinations_total;
$this->combinations_length = $combinations_total * $input_len;
for($i = 0; $i < $input_len; ++$i) {
$this->branches[] = $this->combination_branches($i);
$this->iterations[] = $this->combination_iteration($i);
}
}
// Calculate a particular combination in the combination space and return the details of that combination.
public function combination($combination) {
$position = $combination * $this->input_len;
if($position < 0 || $position >= $this->combinations_length)
return false;
$group = $position % $this->input_len;
$first = $position - $group;
$last = $first + $this->input_len - 1;
$combination = floor(($last + 1) / $this->input_len) - 1;
$bytes = str_repeat(chr(0), $this->input_len);
for($i = 0; $i < $this->input_len; ++$i)
$bytes[$i] = phone::$letters[$this->input[$i]][($combination / $this->branches[$i]) % count(phone::$letters[$this->input[$i]])];
return array(
'combination' => $combination,
'branches' => $this->branches[$group],
'iterations' => $this->iterations[$group],
'first' => $first,
'last' => $last,
'bytes' => $bytes
);
}
// Calculate a particular byte in the combination space and return the details of that byte.
public function combination_position($position) {
if($position < 0 || $position >= $this->combinations_length)
return false;
$group = $position % $this->input_len;
$group_count = count(phone::$letters[$this->input[$group]]);
$first = $position - $group;
$last = $first + $this->input_len - 1;
$combination = floor(($last + 1) / $this->input_len) - 1;
$index = ($combination / $this->branches[$group]) % $group_count;
$bytes = str_repeat(chr(0), $this->input_len);
for($i = 0; $i < $this->input_len; ++$i)
$bytes[$i] = phone::$letters[$this->input[$i]][($combination / $this->branches[$i]) % count(phone::$letters[$this->input[$i]])];
return array(
'position' => $position,
'combination' => $combination - 1,
'group' => $group,
'group_count' => $group_count,
'group_index' => $index,
'number' => $this->input[$group],
'branches' => $this->branches[$group],
'iterations' => $this->iterations[$group],
'first' => $first,
'last' => $last,
'byte' => phone::$letters[$this->input[$group]][$index],
'bytes' => $bytes
);
}
// Convert letters into a combination number using Multi-Base Big Endian.
public function combination_letters($letters) {
if(!isset($letters[$this->input_len - 1]) || isset($letters[$this->input_len]))
return false;
$combination = 0;
for($byte = 0; $byte < $this->input_len; ++$byte) {
$base = count(phone::$letters[$this->input[$byte]]);
$found = false;
for($value = 0; $value < $base; ++$value) {
if($letters[$byte] === phone::$letters[$this->input[$byte]][$value]) {
$combination += $value * $this->branches[$byte];
$found = true;
break;
}
}
if($found === false)
return false;
}
return $combination;
}
// Calculate the number of branches after a particular group.
public function combination_branches($group) {
if($group >= 0 && ++$group < $this->input_len) {
$branches = 1;
for($i = $group; $i < $this->input_len; ++$i)
$branches *= count(phone::$letters[$this->input[$i]]);
return $branches === 1 ? 1 : $branches;
}
elseif($group === $this->input_len)
return 1;
else
return false;
}
// Calculate the number of iterations before a particular group.
public function combination_iteration($group) {
if($group > 0 && $group < $this->input_len) {
$iterations = 1;
for($i = $group - 1; $i >= 0; --$i)
$iterations *= count(phone::$letters[$this->input[$i]]);
return $iterations;
}
elseif($group === 0)
return 1;
else
return false;
}
// Iterations, Outputs array of all combinations using a buffer.
public function combinations() {
$count = $this->combinations_total / count(phone::$letters[$this->input[0]]);
$combinations = array_fill(0, $this->combinations_total, str_repeat(chr(0), $this->input_len));
for(
$group = 0, // Index for the current group of letters.
$groups_count = $this->input_len, // Total number of letter groups.
$letters = count(phone::$letters[$this->input[0]]), // Total number of letters in the current group.
$width = $this->combinations_total, // Number of bytes to repeat the current letter.
$repeat = 1; // Total number of times the group will repeat.
;
) {
for($byte = 0, $width /= $letters, $r = 0; $r < $repeat; ++$r)
for($l = 0; $l < $letters; ++$l)
for($w = 0; $w < $width; ++$w)
$combinations[$byte++][$group] = phone::$letters[$this->input[$group]][$l];
if(++$group < $groups_count) {
$repeat *= $letters;
$letters = count(phone::$letters[$this->input[$group]]);
}
else
break;
}
return $combinations;
}
}
// ====================
$phone = new phone('23456789');
print_r($phone);
//print_r($phone->combinations());
for($i = 0; $i < $phone->combinations_total; ++$i) {
echo $i, ': ', $phone->combination($i)['bytes'], "\n";
}
Une solution R utilisant des boucles imbriquées:
# Create phone pad
two <- c("A", "B", "C")
three <- c("D", "E", "F")
four <- c("G", "H", "I")
five <- c("J", "K", "L")
six <- c("M", "N", "O", "P")
seven <- c("Q", "R", "S")
eight <- c("T", "U", "V")
nine <- c("W", "X", "Y", "Z")
# Choose three numbers
number_1 <- two
number_2 <- three
number_3 <- six
# create an object to save the combinations to
combinations <- NULL
# Loop through the letters in number_1
for(i in number_1){
# Loop through the letters in number_2
for(j in number_2){
# Loop through the letters in number_3
for(k in number_3){
# Add each of the letters to the combinations object
combinations <- c(combinations, paste0(i, j, k))
}
}
}
# Print all of the possible combinations
combinations
J'ai posté une autre solution R plus bizarre, utilisant davantage de boucles et d'échantillons sur mon blog .
Oracle SQL: Utilisable avec n'importe quelle longueur de numéro de téléphone et peut facilement prendre en charge la localisation.
CREATE TABLE digit_character_map (digit number(1), character varchar2(1));
SELECT replace(permutations,' ','') AS permutations
FROM (SELECT sys_connect_by_path(map.CHARACTER,' ') AS permutations, LEVEL AS lvl
FROM digit_character_map map
START WITH map.digit = substr('12345',1,1)
CONNECT BY digit = substr('12345',LEVEL,1))
WHERE lvl = length('12345');
Cette version en C # est relativement efficace et fonctionne pour les chiffres non occidentaux (comme "" par exemple).
static void Main(string[] args)
{
string phoneNumber = null;
if (1 <= args.Length)
phoneNumber = args[0];
if (string.IsNullOrEmpty(phoneNumber))
{
Console.WriteLine("No phone number supplied.");
return;
}
else
{
Console.WriteLine("Alphabetic phone numbers for \"{0}\":", phoneNumber);
foreach (string phoneNumberText in GetPhoneNumberCombos(phoneNumber))
Console.Write("{0}\t", phoneNumberText);
}
}
public static IEnumerable<string> GetPhoneNumberCombos(string phoneNumber)
{
phoneNumber = RemoveNondigits(phoneNumber);
if (string.IsNullOrEmpty(phoneNumber))
return new List<string>();
char[] combo = new char[phoneNumber.Length];
return GetRemainingPhoneNumberCombos(phoneNumber, combo, 0);
}
private static string RemoveNondigits(string phoneNumber)
{
if (phoneNumber == null)
return null;
StringBuilder sb = new StringBuilder();
foreach (char nextChar in phoneNumber)
if (char.IsDigit(nextChar))
sb.Append(nextChar);
return sb.ToString();
}
private static IEnumerable<string> GetRemainingPhoneNumberCombos(string phoneNumber, char[] combo, int nextDigitIndex)
{
if (combo.Length - 1 == nextDigitIndex)
{
foreach (char nextLetter in phoneNumberAlphaMapping[(int)char.GetNumericValue(phoneNumber[nextDigitIndex])])
{
combo[nextDigitIndex] = nextLetter;
yield return new string(combo);
}
}
else
{
foreach (char nextLetter in phoneNumberAlphaMapping[(int)char.GetNumericValue(phoneNumber[nextDigitIndex])])
{
combo[nextDigitIndex] = nextLetter;
foreach (string result in GetRemainingPhoneNumberCombos(phoneNumber, combo, nextDigitIndex + 1))
yield return result;
}
}
}
private static char[][] phoneNumberAlphaMapping = new char[][]
{
new char[] { '0' },
new char[] { '1' },
new char[] { 'a', 'b', 'c' },
new char[] { 'd', 'e', 'f' },
new char[] { 'g', 'h', 'i' },
new char[] { 'j', 'k', 'l' },
new char[] { 'm', 'n', 'o' },
new char[] { 'p', 'q', 'r', 's' },
new char[] { 't', 'u', 'v' },
new char[] { 'w', 'x', 'y', 'z' }
};
Je suis plutôt un débutant, alors corrigez-moi là où je me trompe.
La première chose à examiner est la complexité de l'espace et du temps. Ce qui est vraiment mauvais, car factorielso pour factoriel (7) = 5040, tout algorithme récursif ferait l'affaire. Mais pour factorial (12) ~ = 4 * 10 ^ 8 ce qui peut provoquer un débordement de pile en solution récursive.
Donc, je ne tenterais pas un algorithme récursif. La solution en boucle est très simple avec "Next Permutation".
Je créerais donc un tableau {0, 1, 2, 3, 4, 5} et générerais toutes les permutations; tout en imprimant, je les remplacerais par des caractères respectifs, par exemple. 0 = A, 5 = F
L'algorithme Next Perm fonctionne comme suit. Par exemple, étant donné 1,3,5,4 permutation suivante est 1,4,3,5
Étapes pour trouver la prochaine perm.
De droite à gauche, trouver le premier numéro décroissant. par exemple 3
De gauche à droite, trouvez le plus petit nombre supérieur à 3, par exemple. 4
Échangez ces nombres en inversant le sous-ensemble. 1,4,5,3 inverse sous-ensemble 1,4,3,5
En utilisant Next permutation (ou rotation), vous générez un sous-ensemble spécifique de permutations, par exemple, vous souhaitez afficher 1000 permutations à partir d'un numéro de téléphone particulier. Cela peut vous éviter d'avoir tous les numéros en mémoire. Si je stocke les nombres sous forme d’entiers sur 4 octets, 10 ^ 9 octets = 1 Go!.
Voici le code de travail pour le même ... ... c'est une récursion à chaque étape, en vérifiant la possibilité de chaque combinaison lors de l'occurrence du même chiffre dans une série ... point de vue.....
S'il vous plaît laissez-moi savoir pour toute question ....
import Java.util.ArrayList;
public class phonenumbers {
/**
* @param args
*/
public static String mappings[][] = {
{"0"}, {"1"}, {"A", "B", "C"}, {"D", "E", "F"}, {"G", "H", "I"},
{"J", "K", "L"}, {"M", "N", "O"}, {"P", "Q", "R", "S"},
{"T", "U", "V"}, {"W", "X", "Y", "Z"}
};
public static void main(String[] args) {
// TODO Auto-generated method stub
String phone = "3333456789";
ArrayList<String> list= generateAllnums(phone,"",0);
}
private static ArrayList<String> generateAllnums(String phone,String sofar,int j) {
// TODO Auto-generated method stub
//System.out.println(phone);
if(phone.isEmpty()){
System.out.println(sofar);
for(int k1=0;k1<sofar.length();k1++){
int m=sofar.toLowerCase().charAt(k1)-48;
if(m==-16)
continue;
int i=k1;
while(true && i<sofar.length()-2){
if(sofar.charAt(i+1)==' ')
break;
else if(sofar.charAt(i+1)==sofar.charAt(k1)){
i++;
}else{
break;
}
}
i=i-k1;
//System.out.print(" " + m +", " + i + " ");
System.out.print(mappings[m][i%3]);
k1=k1+i;
}
System.out.println();
return null;
}
int num= phone.charAt(j);
int k=0;
for(int i=j+1;i<phone.length();i++){
if(phone.charAt(i)==num){
k++;
}
}
if(k!=0){
int p=0;
ArrayList<String> list2= generateAllnums(phone.substring(p+1), sofar+phone.charAt(p)+ " ", 0);
ArrayList<String> list3= generateAllnums(phone.substring(p+1), sofar+phone.charAt(p), 0);
}
else{
ArrayList<String> list1= generateAllnums(phone.substring(1), sofar+phone.charAt(0), 0);
}
return null;
}
}