这里是:
static char[][] letters = {"Ee".toCharArray(), // 0
"JNQjnq".toCharArray(), // 1
"RWXrwx".toCharArray() // 2
//.... add remaining
};
static Set<String> words = new HashSet<>(Arrays.asList(
"Stack",
"Overflow",
"foo",
"bar"
//... add other words
));
// main method
public void generateAndCheckAll(String number) {
int[] num = new int[number.length()]; // store number as digits
int[] ind = new int[number.length()]; // store letter indices
int i = 0;
for (char c : number.toCharArray()) { // convert String to int array
num[i++] = c - '0';
}
do {
String word = generateWord(num, ind);
System.out.println(word + (words.contains(word) ? " is contained" : " is not contained"));
} while (next(num, ind));
}
// generate word by number array and index array
public String generateWord(int[] num, int[] ind) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ind.length; i++)
sb.append(letters[num[i]][ind[i]]);
return sb.toString();
}
// switch index array to next
public boolean next(int[] num, int[] ind) {
int i = ind.length - 1;
while (i >= 0 && ind[i] == letters[num[i]].length - 1) // search for the index that can be incremented
i--;
if (i < 0)
return false;
ind[i]++; // increment such index
for (int j = i + 1; j < num.length; j++) // change remaining indices to 0
ind[j] = 0;
return true;
}
这里的主要思想是在每次迭代时存储字母索引数组并基于它生成一个新单词。例如,对于数字 201 和索引数组 [0, 0, 5],将生成单词 REq:第 0 个字母代表数字 2,第 0 个字母代表数字 0,第 5 个字母代表数字 @ 987654327@。
然后在字典中查找该单词并将索引数组切换到下一个。从末尾扫描我们搜索可以递增的索引(这样就不会溢出给定位置的数字的字母数):我们不能递增“5”(因为数字1只有6个字母),但是我们可以增加“0”。所以索引数组被更改为[0, 1, 0],一切都一遍又一遍地重复,直到所有索引都达到最大值。
要查看它是如何工作的,请在逐步模式下调试此代码。很容易理解并将相同的想法应用于许多其他类似的任务。
顺便说一句,这不是最有效的方法,因为字典大小(我想是 10-100K)很可能小于组合计数(10 位数字约为 60M)。如果你真的不需要生成所有的组合,你可以进行字典的准备:
为字典中的每个单词生成一个数字,
将每个生成的数字映射到对应的单词(words),并将这些映射收集到哈希集合中。
然后,对于您收到的号码,您只需查看给定号码是否存在一个单词(单词)。这种方法需要较长的准备阶段和较大的空间,但查找速度显着提高。