1. 前言
本文的一些图片, 资料 截取自编程之美
2. 问题描述
3. 问题分析
一个数字, 对应一个字符数组, 这个问题其实就是穷举出这个数字数组能够表示的所有的字符的拼凑, 然后找出为单词的序列
这里 我只做了穷举 “数字数组 -> 字符序列”
解法 : 使用一个pos数组, 来表示使用第i个数字的第pos[i]个字符, 然后设计一个累增的方法incPos来控制pos的增长, 至于迭代方式 可以选用循环, 也可以使用递归
这里的wordsToNumber01 表示输入一个字符序列, 获取其数字表示, 比较简单 这里就不说了
4. 代码
/**
* file name : Test04PhoneNumberMapWords.java
* created at : 9:38:08 AM May 27, 2015
* created by 970655147
*/
package com.hx.test04;
public class Test04PhoneNumberMapWords {
// 枚举出手机号码 到字符的所有映射
public static void main(String []args) {
int[] numberLen = new int[] {0, 0, 3, 3, 3, 3, 3, 4, 3, 4 };
char[][] numberMap = initNumberMap(numberLen);
int[] number = new int[] {9, 2, 3 };
int[] pos = new int[] {0, 0, 0 } ;
// phoneNumberMapWords01(numberMap, numberLen, number, pos);
phoneNumberMapWords02(numberMap, numberLen, number, pos);
char[] str = new char[] {'z', 'c', 'e' };
int[] dict = initDict(numberLen);
wordsToNumber01(dict, str);
}
// 思路 : 更新pos的最后一位 如果需要进位 在循环更新pos最后一位之前的数据
// numberMap 表示数字到字母的映射, numberLen表示每一个映射的长度
// number 表示号码是多少, pos表示当前字符在对应号码的索引
public static void phoneNumberMapWords01(char[][] numberMap, int[] numberLen, int[] number, int[] pos) {
int lastOne = pos.length - 1;
boolean isEnd = false;
while(!isEnd ) {
for(int i=0; i<number.length; i++) {
Log.logWithoutLn(numberMap[number[i]][pos[i]] + " ");
}
Log.enter();
// 更新pos
isEnd = incPos(numberLen, number, pos);
}
}
// 递归实现 不过本质基本一样[尾递归会优化为循环]
public static void phoneNumberMapWords02(char[][] numberMap, int[] numberLen, int[] number, int[] pos) {
for(int i=0; i<number.length; i++) {
Log.logWithoutLn(numberMap[number[i]][pos[i]] + " ");
}
Log.enter();
boolean isEnd = incPos(numberLen, number, pos);
if(!isEnd ) {
phoneNumberMapWords02(numberMap, numberLen, number, pos);
}
}
// 利用字母到数字的映射 映射str的每一个字符
public static void wordsToNumber01(int[] dict, char[] str) {
int[] res = new int[str.length];
int a = 'a';
int idx = 0;
for(int i=0; i<str.length; i++) {
int idx0 = str[i] - a;
res[idx ++] = dict[idx0];
}
Log.logWithoutPosition(res);
}
// 递增pos 如果到达了最大值 则返回false
private static boolean incPos(int[] numberLen, int[] number, int[] pos) {
int lastOne = pos.length - 1;
pos[lastOne] ++;
int idx = lastOne;
while(pos[idx] == numberLen[number[idx] ] ) {
if(idx == 0) {
return true;
}
pos[idx] = 0;
idx --;
pos[idx] ++;
}
return false;
}
// 初始化数字到字母的映射表
private static char[][] initNumberMap(int[] numberLen) {
char[][] numberMap = new char[10][4];
char idx = 'a';
for(int i=0; i<numberLen.length; i++) {
for(int j=0; j<numberLen[i]; j++) {
numberMap[i][j] = idx++;
}
}
return numberMap;
}
// 初始化字符到数字的映射表
private static int[] initDict(int[] numberLen) {
int[] res = new int[26];
int a = 'a', z = 'z';
int idx = 0, cnt = 0;
for(int i=a; i<=z; i++) {
while(cnt == numberLen[idx]) {
idx ++;
cnt = 0;
}
res[i-a] = idx;
cnt ++;
}
return res;
}
}
5. 运行结果
6. 总结
这个问题不是很难, 但是设计方法的时候, 需要注意一些细节的问题
注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!