如何打印出给定电话号码可能代表的所有可能的字母组合?

时间:2010-02-26 20:10:41

标签: algorithm language-agnostic combinatorics

我刚刚尝试过我的第一次编程访谈,其中一个问题是编写一个给出7位数电话号码的程序,可以打印每个号码可能代表的所有可能的字母组合。

问题的第二部分就是如果这是一个12位数的国际号码呢?这会对你的设计产生什么影响。

我没有在采访中写的代码,但我觉得他对此不满意 这样做的最佳方式是什么?

31 个答案:

答案 0 :(得分:40)

在Python中,迭代:

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是目前为止的结果列表;最初它填充了一个项目,空字符串。然后,对于输入字符串中的每个字符,它会从顶部定义的字典中查找与其匹配的字母列表。然后,它将列表ret替换为现有前缀和可能字母的每个组合。

答案 1 :(得分:15)

它类似于一个名为letter combinations of a phone number的问题, 这是我的解决方案 它适用于任意数量的数字,只要结果不超过内存限制。

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', "");
    }} ;
}

我不确定12位国际数字如何影响设计。

编辑:国际号码也将被处理

答案 2 :(得分:4)

在Java中使用递归:

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);
        }
    }
}

答案 3 :(得分:3)

显而易见的解决方案是将数字映射到键列表,然后生成可能组合的函数:

第一个是显而易见的,第二个更有问题,因为你有大约3 ^个数字组合,这可能是一个非常大的数字。

一种方法是将数字匹配的每种可能性看作数字中的数字(在基数4上)并实现接近计数器的某些东西(跳过某些实例,因为通常少于4个字母可映射到一个数字)。

更明显的解决方案是嵌套循环或递归,这些都不太优雅,但在我看来是有效的。

必须注意的另一件事是避免可伸缩性问题(例如,将可能性保留在内存中等),因为我们正在谈论很多组合。

P.S。问题的另一个有趣的扩展是本地化。

答案 4 :(得分:3)

在数字键盘中,文本和数字放在同一个键上。例如,如果我们想要写一些以'A'开头的东西,我们需要输入一次键2,那么2有“ABC”。如果我们想输入'B',按键2两次,然后输入'C'三次。下面是这种键盘的图片。

keypad http://d2o58evtke57tz.cloudfront.net/wp-content/uploads/phoneKeyboard.png

给定图中所示的键盘和n位数字,按下这些数字列出所有可能的单词。

例如,如果输入数字是234,则可以形成的可能单词是(按字母顺序排列): adg adi adi aeg aeh aei afg afh afi bdg bdh bdi beg beh bei bfg bfh bfi cdg cdh cdi ceg ceh cei cfg cfh cfh

我们先做一些计算。七位数可能有多少个单词,每个数字代表n个字母?对于第一个数字,我们最多有四个选项,对于第一个字母的每个选项,我们最多有四个选择第二个数字,依此类推。所以这是简单的数学,它将是O(4 ^ n)。由于键0和1没有任何相应的字母表,并且许多字符有3个字符,因此4 ^ n将是单词数量的上限而不是最小单词。

现在让我们举一些例子。

对于234以上的数字。你看到任何模式吗?是的,我们注意到最后一个字符总是G,H或I,每当它将其值从I重置为G时,它左边的数字就会改变。 类似地,每当第二个最后一个字母表重置其值时,第三个最后一个字母表将获得更改,依此类推当我们生成所有单词时,第一个字符只重置一次。这也可以从另一端看。也就是说,无论何时位置i处的角色发生变化,位置i + 1处的角色都会经历所有可能的角色,并且它会产生连锁反应,直到我们到达终点。 由于0和1没有任何与之关联的字符。我们应该打破,因为这些数字不会迭代。

让我们采用第二种方法,因为使用递归很容易实现它。我们一直走到最后,一个接一个地回来。递归的完美条件。让我们搜索基本案例。 当我们到达最后一个字符时,我们打印带有最后一个数字的所有可能字符的单词并返回。简单的基本情况。当我们到达最后一个字符时,我们打印带有最后一个数字的所有可能字符的单词并返回。简单的基础案例。

以下是C实现的递归方法,以打印对应于n位输入数字的所有可能的单词。请注意,输入数字表示为一个数组,以简化代码。

#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;
}

输出:

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

时间复杂度:

上述代码的时间复杂度为O(4 ^ n),其中n是输入数字中的位数。

参考文献:

http://www.flipkart.com/programming-interviews-exposed-secrets-landing-your-next-job-3rd/p/itmdxghumef3sdjn?pid=9788126539116&affid=sandeepgfg

答案 5 :(得分:3)

在C ++中(递归):

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;
}
}

可以使用'k'调用此函数,并且'i'等于零。

任何需要更多插图来理解逻辑的人都可以将递归技术与以下输出结合起来:

ADG
ADH
ADI

AEG
AEH
AEI

AFG
AFH
AFI


BDG
BDH
BDI

BEG
BEH
BEI

BFG
BFH
...

答案 6 :(得分:2)

此问题类似于this leetcode问题。这是我针对leetcode提交的针对此问题的答案(请检查githubvideo以获得解释)。

因此,我们需要的第一件事是一些方法来保持一个数字的映射,我们可以使用相关地图:

private Map<Integer, String> getDigitMap() {
        return Stream.of(
                new AbstractMap.SimpleEntry<>(2, "abc"),
                new AbstractMap.SimpleEntry<>(3, "def"),
                new AbstractMap.SimpleEntry<>(4, "ghi"),
                new AbstractMap.SimpleEntry<>(5, "jkl"),
                new AbstractMap.SimpleEntry<>(6, "mno"),
                new AbstractMap.SimpleEntry<>(7, "pqrs"),
                new AbstractMap.SimpleEntry<>(8, "tuv"),
                new AbstractMap.SimpleEntry<>(9, "wxyz"))
               .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, 
                                AbstractMap.SimpleEntry::getValue));
}

上述方法正在准备地图,而我要使用的下一个方法是为所提供的数字提供映射:

private String getDigitMappings(String strDigit, Map<Integer,String> digitMap) {
        int digit = Integer.valueOf(strDigit);
        return digitMap.containsKey(digit) ? digitMap.get(digit) : "";
}

可以使用回溯解决此问题,并且回溯解决方案通常具有一种结构,其中方法签名将包含:结果容器,临时结果,带有索引的原始源等。因此,方法结构的形式为:

private void compute(List<String> result, StringBuilder temp, String digits, int start, Map<Integer, String> digitMap) {
       // Condition to populate temp value to result
       // explore other arrangements based on the next input digit
       // Loop around the mappings of a digit and then to explore invoke the same method recursively
       // Also need to remove the digit which was in temp at last so as to get proper value in temp for next cycle in loop
}

现在方法主体可以填充为(结果将保存在列表中,字符串生成器中保存为临时文件,等等)

private void compute(List<String> result, StringBuilder temp, String digits, int start, Map<Integer, String> digitMap) {
        if(start >= digits.length()) { // condition
            result.add(temp.toString());
            return;
        }

        String letters = getDigitMappings(digits.substring(start, start + 1), digitMap); // mappings of a digit to loop around
        for (int i = 0; i < letters.length(); i++) {
            temp.append(letters.charAt(i));
            compute(result, temp, digits, start+1, digitMap); //explore for remaining digits
            temp.deleteCharAt(temp.length() - 1); // remove last in temp
        }
}

最后,该方法可以调用为:

public List<String> letterCombinations(String digits) {
        List<String> result = new ArrayList<>();
        if(digits == null || digits.length() == 0) return result;
        compute(result, new StringBuilder(), digits, 0, getDigitMap());
        return result;
}

现在,一个数字的最大映射字符数可以为4(例如9个具有wxyz),回溯涉及穷举搜索以探索所有可能的排列(状态空间树),因此对于大小为n的数字,我们将具有4x4x4....n times,即复杂度为O(4^n)

答案 7 :(得分:2)

在JavaScript中。 CustomCounter类负责递增索引。然后输出不同的可能组合。

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)

答案 8 :(得分:1)

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;
            }
        }
    }
}

答案 9 :(得分:1)

这是this回答的C#端口。

<强>代码

 
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;
    }
}

单元测试

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);
    }
}

答案 10 :(得分:1)

Python解决方案非常经济,因为它使用生成器在内存使用方面是高效的。

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

显然itertools.product正在为您解决大部分问题。但是写自己并不困难。这是go中的一个解决方案,它小心地重用数组result来生成所有解决方案,并使用闭包f来捕获生成的单词。结合使用,可以在product内使用O(log n)内存。

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)) })
}

答案 11 :(得分:1)

#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;
}

答案 12 :(得分:1)

You find source (Scala) herean working applet here.

由于0和1不与字符匹配,因此它们在数字中构建自然断点。但它们不会出现在每个数字中(开头的0除外)。从9位数字开始,更长的数字如+49567892345,可能会导致OutOfMemoryErrors。所以最好将数字分成像

这样的组
  • 01723 5864
  • 0172 35864

看,如果从较短的部分可以理解。我写了这样一个程序,并测试了我的朋友的一些数字,但很少发现较短的单词组合,可以在字典中检查匹配,更不用说单个,长单词。

所以我的决定是仅支持搜索,没有完全自动化,通过显示可能的组合,鼓励手动分割数量,可能是多次。

所以我找到了+ -RAD JUNG(+ -bycicle boy)。

如果你接受拼写错误,缩写,外来词,数字作为单词,单词和单词,你找到解决方案的机会要好得多,而不是摆弄。

246848 => 2hot4u (too hot for you) 
466368 => goodn8 (good night) 
1325   => 1FCK   (Football club)
53517  => JDK17  (Java Developer Kit)

是人类可能观察到的东西 - 让算法发现这样的事情相当困难。

答案 13 :(得分:1)

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

答案 14 :(得分:1)

使用列表L,其中L [i] =数字i可以表示的符号。

L [1] = @,。,! (例如) L [2] = a,b,c

然后你可以做这样的事情(伪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);
  }
}

假设每个列表包含3个字符,我们对7个数字有3 ^ 7个可能性,12个有3 ^ 12个,这不是很多。如果你需要所有组合,我看不到更好的方法。你可以避免递归等等,但无论如何你都不会比这更快。

答案 15 :(得分:0)

我实现了一个缓存,有助于减少递归次数。此缓存将避免扫描它已经为之前的组合所做的字母。对于一个实例,它是120k循环,在缓存实现后它减少到40k。

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");
    }
}

答案 16 :(得分:0)

在求职面试中,我收到一个有关创建电话号码阵列并打印出所有可能的字母组合的问题。在面试期间,我从面试官那里窃窃私语,关于递归以及如何使用循环无法实现递归。对于我来说,从另一个程序员那里获得输入是非常不自然的,我信任他的建议而不是我自己的学费,然后写了一个草率的递归混乱。进行得不太顺利。在接收输入之前,因为我以前从未遇到过这个问题,所以我的大脑正在计算潜在的可复制数学公式。我的呼吸开始低语,“不能只乘以三,有些是四”,因为我的脑子开始争分夺秒地思考着一个答案,而开始写另一个答案。直到下周末,我才接到电话通知我这个不幸的消息。那天晚上晚些时候,我决定看看这是否真的是递归问题。对我来说不是。

我下面的解决方案是用PHP编码的,是非递归的,适用于任何长度的输入,我什至包括了一些注释来帮助描述变量的含义。这是我对这个问题的不变的最终答案。希望以后对其他人有帮助,请随时将其翻译成其他语言。

Me方法涉及计算组合总数,并创建一个足以容纳每个字节的缓冲区。我的缓冲区的长度与您期望从有效的递归算法中收到的长度相同。我制作了一个包含代表每个数字的字母组的数组。我的方法之所以有效,是因为您的组合总数始终可以被当前组中的字母数整除。如果您可以在脑海中想象该算法输出的垂直列表,或者垂直查看列表而不是水平组合列表,则我的算法将变得有意义。该算法使我们可以从左开始而不是从左到右从上到下垂直循环遍历每个字节,并且不需要递归地单独填充每个字节。我将缓冲区当作字节数组来使用,以节省时间和精力。


非递归迭代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";

非递归,非迭代,无缓冲,友好,仅数学运算+使用多基础大字节序的非递归,迭代PHP对象

前几天我在新房子里工作时,我意识到我可以使用我的第一个函数中的数学加上我的基础知识来将输入的所有可能的字母组合视为一个多维数

我的对象提供了必要的功能,可以将首选的组合存储到数据库中,如果需要,可以转换字母和数字,使用首选的组合或字节从组合空间中的任何位置挑选出一个组合,并且所有这些都可以很好地发挥作用多线程。

话虽如此,使用我的对象,我可以提供第二个答案,该答案使用基数,没有缓冲区,没有迭代,最重要的是没有递归。

<?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";
}

答案 17 :(得分:0)

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, "")
}

假设每个数字最多映射4个字符,则递归调用的数量T满足不等式T(n) <= 4T(n-1),其不等式为4^n

答案 18 :(得分:0)

此方法使用R并基于首先将字典转换为其对应的数字表示,然后将其用作查找。

我的机器只需要1秒的转换(从大约100,000字的原生Unix字典转换),最多100个不同数字输入的典型查找总共需要0.1秒:

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"

答案 19 :(得分:0)

使用嵌套循环的R解决方案:

# 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

我发布了另一个更奇怪的R解决方案,使用更多循环并对on my blog进行采样。

答案 20 :(得分:0)

C#中的这个版本效率相当高,适用于非西方数字(例如“1234567”)。

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' }
};

答案 21 :(得分:0)

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;
}

答案 22 :(得分:0)

Oracle SQL:可用于任何电话号码长度,并且可以轻松支持本地化。

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');

答案 23 :(得分:0)

这是相同的工作代码.. 它是每一步的递归,检查每个组合在一系列中出现相同数字的可能性......我不确定是否有更好的解决方案,从复杂的角度来看......

如有任何问题,请告诉我....

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;

    }

}

答案 24 :(得分:0)

这是痛苦的一个。这个是非常有效的(实际上我认为它根本不存在)。但它有一些有趣的方面。

  1. 需要一个数字并将其转换为字符串
  2. 每次只提高一次种子数以创建下一个连续字符串
  3. 对此很好的是,对字符串的大小没有实际限制(没有字符限制)这允许您生成更长和更长的字符串,如果需要只是等待。

    #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);
        }
    }
    

答案 25 :(得分:0)

    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;
        }
    }

答案 26 :(得分:0)

我重写了这个(referred above)的最新答案,从C到 Java 。我还包括对0和1(0和1)的支持,因为555-5055之类的数字在上述代码中根本不起作用。

在这里。一些评论被保留。

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();
}

答案 27 :(得分:0)

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;
    }

答案 28 :(得分:0)

这是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;
}

答案 29 :(得分:0)

/**
 * 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);
        }
    }
}

答案 30 :(得分:0)

我是一个新手,所以无论我错在哪里都请纠正我。

第一件事就是研究空间和时间复杂性。这是非常糟糕的,因为它是因子 所以对于factorial(7)= 5040,任何递归算法都可以。但是对于阶乘(12)〜= 4 * 10 ^ 8,它可能导致递归解决方案中的堆栈溢出。

所以我不会尝试递归算法。循环解决方案使用“Next Permutation”非常直接。

所以我会创建和数组{0,1,2,3,4,5}并生成所有排列,而打印时用相应的字符替换它们,例如。 0 = A,5 = F

Next Perm算法的工作原理如下。例如,给定1,3,5,4下一个排列是1,4,3,5

寻找下一个烫发的步骤。

  1. 从右到左,找到第一个减少的数字。例如3

  2. 从左到右,找到大于3的最小数字,例如。 4

  3. 将这些数字作为反向子集交换。 1,4,5,3反向子集1,4,3,5

  4. 使用下一个排列(或旋转),您可以生成特定的排列子集,例如,您希望从特定的电话号码开始显示1000个排列。这可以避免让你在内存中拥有所有数字。如果我将数字存储为4字节整数,则10 ^ 9字节= 1 GB!