|
|
package class19;
|
|
|
|
|
|
public class Code02_ConvertToLetterString {
|
|
|
|
|
|
// str只含有数字字符0~9
|
|
|
// 返回多少种转化方案
|
|
|
public static int number(String str) {
|
|
|
if (str == null || str.length() == 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
return process(str.toCharArray(), 0);
|
|
|
}
|
|
|
|
|
|
// str[0..i-1]转化无需过问
|
|
|
// str[i.....]去转化,返回有多少种转化方法
|
|
|
public static int process(char[] str, int i) {
|
|
|
if (i == str.length) {
|
|
|
return 1;
|
|
|
}
|
|
|
// i没到最后,说明有字符
|
|
|
if (str[i] == '0') { // 之前的决定有问题
|
|
|
return 0;
|
|
|
}
|
|
|
// str[i] != '0'
|
|
|
// 可能性一,i单转
|
|
|
int ways = process(str, i + 1);
|
|
|
if (i + 1 < str.length && (str[i] - '0') * 10 + str[i + 1] - '0' < 27) {
|
|
|
ways += process(str, i + 2);
|
|
|
}
|
|
|
return ways;
|
|
|
}
|
|
|
|
|
|
// 从右往左的动态规划
|
|
|
// 就是上面方法的动态规划版本
|
|
|
// dp[i]表示:str[i...]有多少种转化方式
|
|
|
public static int dp1(String s) {
|
|
|
if (s == null || s.length() == 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
char[] str = s.toCharArray();
|
|
|
int N = str.length;
|
|
|
int[] dp = new int[N + 1];
|
|
|
dp[N] = 1;
|
|
|
for (int i = N - 1; i >= 0; i--) {
|
|
|
if (str[i] != '0') {
|
|
|
int ways = dp[i + 1];
|
|
|
if (i + 1 < str.length && (str[i] - '0') * 10 + str[i + 1] - '0' < 27) {
|
|
|
ways += dp[i + 2];
|
|
|
}
|
|
|
dp[i] = ways;
|
|
|
}
|
|
|
}
|
|
|
return dp[0];
|
|
|
}
|
|
|
|
|
|
// 从左往右的动态规划
|
|
|
// dp[i]表示:str[0...i]有多少种转化方式
|
|
|
public static int dp2(String s) {
|
|
|
if (s == null || s.length() == 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
char[] str = s.toCharArray();
|
|
|
int N = str.length;
|
|
|
if (str[0] == '0') {
|
|
|
return 0;
|
|
|
}
|
|
|
int[] dp = new int[N];
|
|
|
dp[0] = 1;
|
|
|
for (int i = 1; i < N; i++) {
|
|
|
if (str[i] == '0') {
|
|
|
// 如果此时str[i]=='0',那么他是一定要拉前一个字符(i-1的字符)一起拼的,
|
|
|
// 那么就要求前一个字符,不能也是‘0’,否则拼不了。
|
|
|
// 前一个字符不是‘0’就够了嘛?不够,还得要求拼完了要么是10,要么是20,如果更大的话,拼不了。
|
|
|
// 这就够了嘛?还不够,你们拼完了,还得要求str[0...i-2]真的可以被分解!
|
|
|
// 如果str[0...i-2]都不存在分解方案,那i和i-1拼成了也不行,因为之前的搞定不了。
|
|
|
if (str[i - 1] == '0' || str[i - 1] > '2' || (i - 2 >= 0 && dp[i - 2] == 0)) {
|
|
|
return 0;
|
|
|
} else {
|
|
|
dp[i] = i - 2 >= 0 ? dp[i - 2] : 1;
|
|
|
}
|
|
|
} else {
|
|
|
dp[i] = dp[i - 1];
|
|
|
if (str[i - 1] != '0' && (str[i - 1] - '0') * 10 + str[i] - '0' <= 26) {
|
|
|
dp[i] += i - 2 >= 0 ? dp[i - 2] : 1;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return dp[N - 1];
|
|
|
}
|
|
|
|
|
|
// 为了测试
|
|
|
public static String randomString(int len) {
|
|
|
char[] str = new char[len];
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
str[i] = (char) ((int) (Math.random() * 10) + '0');
|
|
|
}
|
|
|
return String.valueOf(str);
|
|
|
}
|
|
|
|
|
|
// 为了测试
|
|
|
public static void main(String[] args) {
|
|
|
int N = 30;
|
|
|
int testTime = 1000000;
|
|
|
System.out.println("测试开始");
|
|
|
for (int i = 0; i < testTime; i++) {
|
|
|
int len = (int) (Math.random() * N);
|
|
|
String s = randomString(len);
|
|
|
int ans0 = number(s);
|
|
|
int ans1 = dp1(s);
|
|
|
int ans2 = dp2(s);
|
|
|
if (ans0 != ans1 || ans0 != ans2) {
|
|
|
System.out.println(s);
|
|
|
System.out.println(ans0);
|
|
|
System.out.println(ans1);
|
|
|
System.out.println(ans2);
|
|
|
System.out.println("Oops!");
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
System.out.println("测试结束");
|
|
|
}
|
|
|
|
|
|
}
|