题目描述
给定一个数字,我们按照如下规则把它翻译为字符串: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就重复出现了。
递归从最大的问题开始自上而下解决问题。我们也可以从最小的子问题开始自下而上解决问题,这样就可以消除重复的子问题。即从数字的末尾开始,从右到左的翻译并计算不同翻译的数目。
以下为参考代码:
using System;
namespace 把数字翻译成字符串
{
class Program
{
static void Main(string[] args)
{
Solution s = new Solution();
int num1 = 12258;
int num2 = 126525;
int num3 = -1;
int num4 = 0;
Console.WriteLine("Test1:\n{0}\t" + s.TranslateNumber(num1), num1);
Console.WriteLine("Test2:\n{0}\t" + s.TranslateNumber(num2), num2);
Console.WriteLine("Test3:\n{0}\t" + s.TranslateNumber(num3), num3);
Console.WriteLine("Test4:\n{0}\t" + s.TranslateNumber(num4), num4);
}
}
class Solution
{
public int TranslateNumber(int number)
{
if (number < 0)
return 0;
string num = number.ToString();
return TranslateNumber(num);
}
private int TranslateNumber(string number)
{
int length = number.Length;
int count = 0; //统计有多少种可翻译的方法
int[] counts = new int[length];
for (int i = length-1; i >= 0; i--)
{
if (i < length-1)
count = counts[i + 1];
else
count = 1;
if (i < length-1)
{
int digit1 = number[i] - '0';
int digit2 = number[i + 1] - '0';
int num = 10 * digit1 + digit2;
if (num >= 10 && num <= 25)
{
if (i < length - 2)
count += counts[i + 2];
else
count += 1;
}
}
counts[i] = count;
}
count = counts[0];
return count;
}
}
}