题目
给定一个全是数字的字符串,返回可以转成合法IP的数量
示例
例如:101111
可以转成:
1.0.1.111, 1.0.11.11, 1.0.111.1
10.1.1.11, 10.1.11.1, 10.11.1.1
101.1.1.1
所以返回7
分析:每一个IP由4段组成,每一个小段的数字在0-255之间,并且每一个小段不能有以0开始的长度不是1的段,即不能出现.012.类似的IP段
首先使用递归函数实现
public static int convertNum1(String str) {
if (str == null || str.length() < 4 || str.length() > 12) {//字符串的长度必须在4到12之间
return 0;
}
char[] chas = str.toCharArray();
return process(chas, 0, 0);//在第0个位置的时候形成的ip数量是0个
}
//chas:字符串转换成的字符数组
//i:当前位置
//parts:已经形成的ip段数目
public static int process(char[] chas, int i, int parts) {
if (i > chas.length || parts > 4) {//当前位置超过了字符数组的最终位置或者已经形成的ip段数量大于了4
return 0;
}
if (i == chas.length) {//当前位置达到了字符数组的最后位置,如果此时已经形成的ip段是4则返回1,否则返回0
return parts == 4 ? 1 : 0;
}
int res = process(chas, i + 1, parts + 1);//递归调用。下一个位置,已形成的ip段+1
if (chas[i] == '0') {//如果当前字符是0,为了使ip段合法(不出现以0开头的ip段),返回前面已形成的ip段数量
return res;
}
res += process(chas, i + 2, parts + 1);//当前位置不为0的情况下,当前位置可以向后跳动2个位置,同时已形成的ip段+1
if (i + 2 < chas.length) {
int sum = (chas[i] - '0') * 100 + (chas[i + 1] - '0') * 10 + (chas[i + 2] - '0');
if (sum < 256) {//保证行成的ip段范围是0-255之间
return res + process(chas, i + 3, parts + 1);//如果在此范围内,当前位置可以向后跳动三个位置
} else {
return res;
}
} else {
return res;
}
}
优化之后的动态规划实现
public static int convertNum2(String str) {
if (str == null || str.length() < 4 || str.length() > 12) {
return 0;
}
char[] chas = str.toCharArray();
int size = chas.length;
int[][] dp = new int[size + 3][5];
dp[size][4] = 1;
for (int parts = 3; parts >= 0; parts--) {
for (int i = size - 1; i >= parts; i = Math.min(i - 1, parts * 3)) {
dp[i][parts] = dp[i + 1][parts + 1];
if (chas[i] != '0') {
dp[i][parts] += dp[i + 2][parts + 1];
if (i + 2 < chas.length) {
int sum = (chas[i] - '0') * 100 + (chas[i + 1] - '0') * 10 + (chas[i + 2] - '0');
if (sum < 256) {
dp[i][parts] += dp[i + 3][parts + 1];
}
}
}
}
}
return dp[0][0];
}