剑指Offer-46:把数字翻译成字符串

题目描述

        给定一个数字,我们按照如下规则把它翻译为字符串:0翻译成‘a’,1翻译成‘b’,……,11翻译成‘l’,……,25翻译成‘z’。一个数值可能翻译成多个字符串。例如:12258有5种不同的翻译,分别是“bccfi”、“bwfi”、“bczi”、“mcfi”、“mzi”。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。


        以12258为例分析,如何从数字的第一位开始一步步计算不同翻译方法的数目。有两种不同的选择来翻译第一位数字1 。第一种是选择是数字1单独翻译成‘b’ ,剩下的数字为2258;第二种是1和紧挨着的2一起翻译成‘m’,后面剩下数字258 。
        当最开始的一个或者两个数字被翻译成一个字符后,接着翻译后面剩下的数字,这样就变成了一个简单的递归问题,有点像以前做过的青蛙跳台阶。显然,可以用一个递归函数来计算翻译的数目。
        定义函数f(i)表示从第i位数字开始的不同翻译的数目,那么f(i)=f(i+1)+g(i,i+1)×f(i+2)。当第i位和第i+1位两位数字拼接起来的数字在10~25范围之内时,g(i,i+1)的值为1,否则为0 。
        虽然用递归来分析问题,但是由于存在重复存在的子问题,因此此思路不是最优。依然以12258为例,翻译12258可以分解成两个子问题:1和2258,以及翻译12和258 。接下来翻译第一个子问题中剩下的2和258,可以发现,这个时候258就重复出现了。
        递归从最大的问题开始自上而下解决问题。我们也可以从最小的子问题开始自下而上解决问题,这样就可以消除重复的子问题。即从数字的末尾开始,从右到左的翻译并计算不同翻译的数目。
以下为参考代码:

public int TranslateNumberCore(int number) {
    	//使用DP解决此题 ret[i]表示索引位置为0-i的number可以翻译成字符串的数目。 
    	//后发现这样计算会存在重复,更好地办法是从后往前,及ret2[i]表示从i位开始到最后的字符串种类
    	//计算number的长度
    	String s = String.valueOf(number);
    	int len = s.length();
    	int[] ret = new int[len-1];
    	ret[0] = 1;
    	for(int i=1; i< len; i++) {
    		//如果该位置的数和前一个数也可以构成一个字符串   注意前一位为0的时候
    		if(Integer.valueOf(s.substring(i-1, 1)) <=25 && Integer.valueOf(s.substring(i-1, 1)) >=10) {
    			ret[i] = ret[i-1];
    			if(i-2 >= 0)
    				ret[i] += ret[i-2];
    		}else
    			ret[i] = ret[i-1];
    	}
    	return ret[len-1];
}

猜你喜欢

转载自blog.csdn.net/qq_32534441/article/details/89204516