[编程之美] PSet3.2 电话号码对应英语单词



问题描述:

       对如非全键盘的手机上的数字,每个数字都对应一些字母,比如2对应ABC,3对应DEF.........,8对应TUV,9对应WXYZ,要求对一段数字,输出其代表的所有可能的字母组合,如5869,可能代表JTMW、JTMX.................


思路:

          将各个数字所能代表的字符存储在一个二维数组c[][]中,其中假设0、1所代表的字符为空字符。见下面代码:

const char c[10][10]={//存储各个数字所能代表的字符
	"",         //0
	"",         //1
	"ABC",      //2
	"DEF",      //3
	"GHI",      //4
	"JKL",      //5
	"MNO",      //6
	"PQRS",     //7
	"TUV",      //8
	"WXYZ",     //9
};
const int total[10]={0,0,3,3,3,3,3,4,3,4};//存储各个数字所能代表的字符总数
/*
用一个数组存储电话号码int number[TelLength];//TelLength为电话号码的位数
将数字目前所能表达的位置用answer[TelLength];
于是对于电话号码第一位c[number[0]][answer[0]]=c[4][2]='I';
*/

解法一:直接循环法

见代码:如果多加一个数字,就得多加一个位置循环以遍历该数字对应的所有字符

void printWord(int number[],int numLen)
{
	int *answer = new int[numLen];
	
	for(answer[0]=0 ; answer[0]<total[number[0]] ; answer[0]++)//遍历三个数字对应的所有字符
		for(answer[1]=0 ; answer[1]<total[number[1]] ; answer[1]++)
			for(answer[2]=0 ; answer[2]<total[number[2]] ; answer[2]++){
				for(int i=0 ; i<numLen ; i++)//遍历所有数字
						cout<<c[number[i]][answer[i]];
				cout<<endl;
			}
	
	delete []answer;
}

下面有一个直接循环法的改良版,免去了多加循环的烦恼,每个数字对应字符位置变化一次就跳出循环输出一次。按照这个思路,下面是代码:

//直接循环法改良
//个人觉得这种方法很难想到
void printWord(int number[],int numLen)
{
	int *answer = new int [numLen];
	memset(answer,0,sizeof(int)*numLen);
	while (true)
	{
		for(int i=0 ; i<numLen ; i++)
			cout<<c[number[i]][answer[i]];
		cout<<endl;
		int k = numLen-1;//当回滚至上一个数字answer[k-1]++后返回大循环,又开始从最后一位向前回滚。体现了递归的思想
		while(k>=0){
			if(answer[k] < total[number[k]]-1){
				answer[k]++;//每变动一下就出去输出一次,直到answer[k]变到最后一个位置
				break;
			}
			else{//answer[k]到尾部,则清零本数字对应字符位置,并回滚至上一个数字对应字符位置
				answer[k]=0;
				k--;
			}
		}
		if(k<0)
			break;
	}

	delete[]answer;
}

解法二:递归解法

       每层的for循环其实可以看成是一个递归函数的调用。代码如下:

//递归解法
//index说明对电话号码的第几位进行循环
void printWord(int number[],int answer[] , int index , int numLen)
{
	if(index == numLen){//叶子节点处输出所有情况
		for(int i=0 ; i<numLen ; i++)//遍历所有号码
			cout<<c[number[i]][answer[i]];
		cout<<endl;
		return;
	}
	for(answer[index]=0 ; answer[index]<total[number[index]] ; answer[index]++)//每改变本层字母一次都需要改变接下来所有情况
		printWord(number,answer,index+1,numLen);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值