剑指offer面试题46(java版):把数字翻译成字符串
题目描述
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成
“z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
class Solution {
public int translateNum ( int num) {
String s = String. valueOf ( num) ;
int n = s. length ( ) ;
int [ ] dp = new int [ n+ 1 ] ;
dp[ 0 ] = 1 ;
for ( int i= 1 ; i<= n; i++ ) {
dp[ i] += dp[ i- 1 ] ;
if ( i- 2 >= 0 && s. substring ( i- 2 , i) . compareTo ( "25" ) <= 0 && s. substring ( i- 2 , i) . compareTo ( "10" ) >= 0 ) {
dp[ i] += dp[ i- 2 ] ;
}
}
return dp[ n] ;
}
}
class Solution {
public int translateNum ( int num) {
String s = String. valueOf ( num) ;
return core ( s, 0 ) ;
}
private int core ( String s, int i) {
int n = s. length ( ) ;
if ( i== n) {
return 1 ;
}
if ( i> n) {
return 0 ;
}
int res = 0 ;
res += core ( s, i+ 1 ) ;
if ( i+ 1 < n && ( s. substring ( i, i+ 2 ) . compareTo ( "25" ) <= 0 && s. substring ( i, i+ 2 ) . compareTo ( "10" ) >= 0 ) ) {
res += core ( s, i+ 2 ) ;
}
return res;
}
}
第一次做; 动态规划; 核心: 1) dp[i]表示考虑前i个数时, 不同的翻译数量 2) 写dp循环主体时才知道dp[0]需要初始化为0, 具体地, i==2时过一遍循环就知道了
class Solution {
public int translateNum ( int num) {
if ( num< 0 )
return 0 ;
char [ ] chs = String. valueOf ( num) . toCharArray ( ) ;
int n = chs. length;
int [ ] dp = new int [ n+ 1 ] ;
dp[ 0 ] = 1 ;
dp[ 1 ] = 1 ;
for ( int i= 2 ; i<= n; i++ ) {
dp[ i] = dp[ i- 1 ] ;
int tmp = Integer. parseInt ( new StringBuilder ( ) . append ( chs[ i- 2 ] ) . append ( chs[ i- 1 ] ) . toString ( ) ) ;
if ( tmp>= 10 && tmp<= 25 )
dp[ i] = dp[ i] + dp[ i- 2 ] ;
}
return dp[ n] ;
}
}
第一次做; 递归, 核心:1)设递归函数f(i)表示以chs[i]开头的不同的翻译数量; 2) 使用memo数组记录已处理过的结果, 避免重复子问题的计算
class Solution {
public int translateNum ( int num) {
if ( num< 0 )
return 0 ;
char [ ] chs = String. valueOf ( num) . toCharArray ( ) ;
int [ ] memo = new int [ chs. length] ;
int res = core ( memo, chs, 0 ) ;
return res;
}
private int core ( int [ ] memo, char [ ] chs, int i) {
if ( i== chs. length) {
return 1 ;
}
if ( memo[ i] > 0 )
return memo[ i] ;
int res = 0 ;
char ch = chs[ i] ;
if ( ch>= '0' && ch<= '9' )
res += core ( memo, chs, i+ 1 ) ;
if ( i+ 1 < chs. length) {
int tmp = Integer. parseInt ( new StringBuilder ( ) . append ( chs[ i] ) . append ( chs[ i+ 1 ] ) . toString ( ) ) ;
if ( tmp>= 10 && tmp<= 25 )
res += core ( memo, chs, i+ 2 ) ;
}
memo[ i] = res;
return res;
}
}
第一次做; 递归, 核心: 设递归函数f(i)表示以索引i对应元素开头, 有f(i)种不同的翻译; 缺点: 递归中有很多重复子问题, 比如说num=12345, 处理1时, 还剩2345, 接着处理2, 此时还剩345; 如果一开始处理12, 那么剩345, 这样出现了两次345, 重复处理
class Solution {
public int translateNum ( int num) {
if ( num< 0 )
return 0 ;
char [ ] chs = String. valueOf ( num) . toCharArray ( ) ;
int res = core ( chs, 0 ) ;
return res;
}
private int core ( char [ ] chs, int i) {
if ( i== chs. length) {
return 1 ;
}
int res = 0 ;
char ch = chs[ i] ;
if ( ch>= '0' && ch<= '9' )
res += core ( chs, i+ 1 ) ;
if ( i+ 1 < chs. length) {
int tmp = Integer. parseInt ( new StringBuilder ( ) . append ( chs[ i] ) . append ( chs[ i+ 1 ] ) . toString ( ) ) ;
if ( tmp>= 10 && tmp<= 25 )
res += core ( chs, i+ 2 ) ;
}
return res;
}
}
力扣优秀题解 substring()和compareTo()用的很好, 两个两位数比较, 其字典序就是正常比较的结果