93. 复原IP地址
思路:题目:
Given "25525511135",
return ["255.255.11.135", "255.255.111.35"].
由题目可知我们的目的就是找到三个分割点使分割出来的IP地址是一个合法的IP地址,显然可以用回溯法来解题,一个一个的分割点尝试如果合法则加入结果集中,由于结果集需要在回溯函数里用到,所以我们可以定义结果集在函数外(当然也可以让结果集作为回溯函数的参数,但是为了函数的简洁我就不这么做了)
->
接下来考虑回溯函数的构造,首先回溯函数需要哪些参数呢?S是必须的,因为这是被分割的对象,其次每次分割的起始点不同,用start来标记起始点,由于分割点不能超过三个,所以还需要记录已有的分割点的个数以及已分割好的字符串:
public List<String> res = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
if (s.length() < 4 || s.length() > 16) //非法输入
return res;
backtrack(s, 0, new StringBuilder(), 0);
return res;
}
这里用到StringBuilder是因为我们需要对字符串进行加减操作,如果直接用String类型会导致很多不必要的对象的创建,所以为了节省时间和空间就用StringBuilder。->
接下来就是定义回溯函数的出口了,也是很重要的一步,出口定义的原因详细写在注释中:
//if (pointNumOfSb > 4) //大于三个点,则剪枝,这里大于4是因为最后一次还会加一
//return;
if (start == s.length() && pointNumOfSb == 4) { //pointNumOfSb==4,则是一个合法的IP
res.add(sb.toString().substring(1)); //substring(1)是因为每次append(".xxx"),第零个位置是"."
return ;
}
接下来分割字符串:
for (int i = start; i < s.length() && i - start < 3; i++) { //i-start < 3,如果大于三位数则返回
String x = s.substring(start, i + 1);
if (x.charAt(0) == '0' && x.length() > 1) //如果是0xx这种则返回
return ;
if (Integer.parseInt(x) <= 255) {
sb.append("." + x);
backtrack(s, i + 1, sb, pointNumOfSb + 1);
sb.delete(sb.lastIndexOf("."), sb.length());
}
}
这里要注意的是,遇到0开头的,只允许是0,所以再往后划分就没有意义了,直接return即可,完整的回溯函数的代码如下:
public void backtrack(String s, int start, StringBuilder sb, int pointNumOfSb) {
//if (pointNumOfSb > 4) //大于三个点,则剪枝,这里大于4是因为最后一次还会加一
//return;
if (start == s.length() && pointNumOfSb == 4) { //pointNumOfSb==4,则是一个合法的IP
res.add(sb.toString().substring(1)); //substring(1)是因为每次append(".xxx"),第零个位置是"."
return ;
}
for (int i = start; i < s.length() && i - start < 3; i++) { //i-start < 3,如果大于三位数则返回
String x = s.substring(start, i + 1);
if (x.charAt(0) == '0' && x.length() > 1) //如果是0xx这种则返回
return ;
if (Integer.parseInt(x) <= 255) {
sb.append("." + x);
backtrack(s, i + 1, sb, pointNumOfSb + 1);
sb.delete(sb.lastIndexOf("."), sb.length());
}
}
}