1. 问题描述:
描述
给定一个字符串str,str全部由数字字符组成,如果str中某一个或者某相邻两个字符组成的子串在1~26之间,则这个子串可以转换为一个字母。
规定“1”转换为“A”,“2”转换为“B”……“26”转换为“Z”。求str有多少种不同的转换结果。
输入
字符串str(|str|<20)
输出
可转换结果的数目
样例输入
12345678
样例输出
3
2. 对于这类问题,我们经常是采用dfs算法进行试探,尝试走遍每一条路径,假如这条路径不行那么退回来走另外的一条路,因为它涉及到相邻字符串的问题,所以这里使用到了Java中的substring方法进行字符串的截取,这里在截取字符串的时候特别要注意字符串截取越界的问题。通过对相邻字符串的截取,我们发现很明显这道题目存在着两个平行状态,对应着截取的两个字符串
因为有的路径不能够把数字转换成字母所以这里我们使用if语句进行提前的剪枝,当前这个状态下可以截取字符串才截取,不满足条件那么就不截取字符串,这样就会大大减少搜索的次数
3. 具体的代码如下:(提交到代码平台之后才得了80分,可能是有的情况没有考虑完全导致结果出现部分错误了)
import java.util.Scanner;
public class Main{
static int count = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
int n = s.length();
if(!s.equals("")){
dfs(s, 0, n);
}
System.out.println(count);
sc.close();
}
private static void dfs(String s, int k, int n){
if(k == n){
count++;
return;
}
//加上if判断条件是为了在截取字符串的时候不发生字符串的越界的情况//因为截取到最后的时候有的可能不能够再截取两个字符串了
if(k + 1 <= n){
String left = s.substring(k, k + 1);
int leftToNum = Integer.parseInt(left);
if(leftToNum >= 1 && leftToNum <= 26){
dfs(s, k + 1, n);
}
}
if(k + 2 <= n){
String right = s.substring(k, k + 2);
int rightToNum = Integer.parseInt(right);
//if条件可以进行提前剪枝
if(rightToNum >= 1 && rightToNum <=26){
dfs(s, k + 2, n);
}
}
}
}
这道题目的难点在于如何截取字符串的问题,而且在截取的时候如何确保不发生越界的问题,注意截取的时候也有技巧的:首先要截取"1",然后截取"12",不能够一开始就截取"1",然后截取"23",这样会导致后面的总的数量少于正确答案的数量的
下面以123456789为例:
""
1 12
2 23 3 34(x)
3 34(x) 4 45 4 ....
4 ... 5 5
5 6 6
6 7 7
7 8 8
8 9 9
9
凡是不能够转换成字母的路径都会在if语句里面被剪断了,那么就不会搜索这条路径了
其中我们也可以记录下中间的结果来查看程序转换的结果是否正确 ,这里我们是要List进行记录,当我们增加一个元素退回来之后删除一个元素,这样就会保证每一次List加入的元素是正确的,具体的代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main{
static int count = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
int n = s.length();
List<String> rec = new ArrayList<String>();
char alps[] = new char[26];
for(int i = 0; i < 26; i++){
alps[i] = (char)('A' + i);
}
if(!s.equals("")){
dfs(s, 0, n, rec, alps);
}
System.out.println(count);
sc.close();
}
private static void dfs(String s, int k, int n, List<String> rec, char alps[]){
if(k == n){
count++;
System.out.println(rec);
return;
}
if(k + 1 <= n){
String left = s.substring(k, k + 1);
int leftToNum = Integer.parseInt(left);
if(leftToNum >= 1 && leftToNum <= 26){
//使用list记录的过程与前面的过程是一样的加入一个退回来之后删除一个
rec.add(alps[leftToNum - 1]+ "");
dfs(s, k + 1, n, rec, alps);
//回溯
rec.remove(rec.size() - 1);
}
}
if(k + 2 <= n){
String right = s.substring(k, k + 2);
int rightToNum = Integer.parseInt(right);
if(rightToNum >= 1 && rightToNum <=26){
rec.add(alps[rightToNum - 1]+ "");
dfs(s, k + 2, n, rec, alps);
//回溯
rec.remove(rec.size() - 1);
}
}
}
}
记录下中间的结果有助于我们更好地理解其中的dfs过程,培养自己对于类似题目的条件发射