记录编程之美的一道经典题目--电话号

问题:
电话的号码盘一般可以用于输入字母,如用2可以输入a,b,c,用3可以输入d,e,f等。
对于号码5869872,可以依次输出其代表的所有字母组合。如:jtmwtpa,jtmwtpb………
1、您能否可以根据这样的对应关系设计一个程序,尽可能快地从这些字母组合中找到一个有意义的单词来描述一个电话号码呢?如:可以用单词“computer”来描述号码26678837。

分析与解法:
对于问题1,不妨掏出电话来研究,我们可以发现,除了0,1之外,其他数字上最少都有3个字符,其中7和9上有4个字符,我们可以假设0,1都是空字符

首先将问题简单化,若电话号码只有一位数,比如说4,那么其代表的单词为g,h,i,据此可以画出一颗排列树,如图
这里写图片描述
接着若电话号码升级到两位数,比如42,又将如何呢?分两步走,从左到右,在选择一个第一位数字所代表的字符的基础上,遍历第二位数字所代表的字符,直到遍历完第一位数字代表的所有字符。就拿42来说,4所能代表的字符为ghi,2所能代表的字符为abc,首先让4代表g,接着遍历2所能代表的所有字符,即可得到ga,gb,gc,然后再让4代表h,再次遍历2所能代表的所有字符,即可得到ha,hb,hc,最后让4代表i,那么同理可得到ia,ib,ic。如图
这里写图片描述
问题1解法一:直接循环

/*将每个数字所能代表的字母记录在一个二维数组c中,其中0、1代表空字符*/
char c[10][10] =
{
    " ",        //0
    " ",        //1
    "ABC",      //2
    "DEF",      //3
    "GHI",      //4
    "JKL",      //5
    "MNO",      //6
    "PQRS",     //7
    "TUV",      //8
    "WXYZ"      //9
};
/*将每个数字所能代表的字母的总数记录在total数组中*/
int total[10] = {0, 0, 3, 3, 3, 3, 3, 4, 3, 4};
/*将电话号码记录在number数组中*/
int number[TellLength] = {……};
/*将数字目前所代表的字母在c数组中的列数下标记录在answer数组中*/
/*初始化时answer[i] = 0*/
int answer[TellLength] = {……};

举例,若number[0] = 4, 即电话号码的第一个数字是4,若answer[0] = 2,则4目前所代表的字母是
c[number[0]][answer[0]] = c[4][2] = ‘I’

先分析简单的例子,假设电话号码有3位

for(answer[0] = 0; answer[0] < total[number[0]]; answer[0]++)
    for(answer[1] = 0; answer[0] < total[number[1]]; answer[1]++)
        for(answer[2] = 0; answer[0] < total[number[2]]; answer[2]++)
            for(int i = 0; i < 3; i++)
                printf("%c\n", c[number[i]][answer[i]]);

但是若电话号码有n位,则需要n层循环,于是改进后的代码如下

while(true)
{
    for(int i = 0; i < n; i++)
        printf("%c\n", c[number[i]][answer[i]]);
    for(int k = n - 1; k >= 0; k--)
    {
        if(answer[k] < total[number[k]] - 1)
        {
            answer[k]++;
            break;
        }
        else
        {
            answer[k] = 0;
            k--;
        }
    }
    if(index < 0)
        break;
}

问题1的解法二:递归

/*index是指对电话号码的第几位进行操作,n是电话号码的位数*/
/*递归初始调用为RecursiveSearch(number, answer, 0, n)*/
void RecursiveSearch(int* number, int* answer, int index, int n)
{
    if(index == n)
    {
        for(int i = 0; i < n; i++)
            printf("%c\n", c[number[i]][answer[i]]);
        return;
    }
    for(answer[index] = 0; answer[index] < total[number[index]]; answer[index]++)
        RecursiveSearch(number, answer, index + 1, n);
}

相当于是对之前n层循环使用递归方法的改进

猜你喜欢

转载自blog.csdn.net/qq_36946274/article/details/80863092