题目:
Given a string containing only digits, restore it by returning all possible valid IP address combinations.
Example:
Input: “25525511135”
Output: [“255.255.11.135”, “255.255.111.35”]
解答:
这类问题基本采用回溯递归的方法
IP有效的地址范围为:1.0.0.1~255.255.255.255
IP地址总共分为四段,每一段有一位,两位或三位,因此我们可以进行分段处理,对原字符串进行分段获取,并对获取的每段判断是否有效。每一段无效的情况可以分为两种:
①每一段的范围必须在 [0, 255] 之间;
②当这段只有一位时,可以为0,但如果超过一位,为两位或三位时,首位不能为0(如01,001都是无效的)
具体思路如下:
- 对输入字符串进行异常处理。若输入字符串的长度小于4或大于12,则不能构成有效IP地址
- 通过递归对字符串进行处理。其中递归的参数包括当前获取字符串的起始标志位 start 和当前获取到的第几段标志 count
- 通过 String.substring() 获取当前段字符串,并进行有效性判断。若该段有效,则StringBuilder.append(),不要忘记加入“.”,并继续递归
- 当前递归返回后,要删除当前字符串中,最后出现“.”至字符串末尾的这段字符串,便于进行下一次递归
- 若字符串已遍历完成start == s.length(),且字符串共有四段 count==4,则生成有效IP地址,将该字符串加入最终数组,其中记得去掉第一段中首位增加的字符“.”
代码实现如下:
class Solution {
//IP有效地址范围:1.0.0.1~255.255.255.255
public List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<>();
//处理一些异常输入
if(s.length() < 4 || s.length() > 12) {
return res;
}
StringBuilder str = new StringBuilder();
Recursive(s, res, str, 0, 0);
return res;
}
private void Recursive(String s, List<String> res, StringBuilder str, int start, int count) {
//判断若为有效IP地址
if(start == s.length() && count == 4) {
res.add(str.toString().substring(1)); //substring(1)是因为第一次str.append("." + cur)时,会导致最终的IP地址首位是".",需去除首位的"."
return;
}
for(int i=start; i<s.length(); i++) {
//当截取的字符串超过3位数,则return
if(i-start > 3) {
return;
}
String cur = s.substring(start, i+1);
//排除非有效IP,若为0*或者0**的情况,则为无效直接return
if(cur.charAt(0) == '0' && cur.length() > 1) {
return;
}
//若为有效IP的一段
if(Integer.parseInt(cur) <= 255) {
str.append("." + cur);
Recursive(s, res, str, i+1, count+1);
str.delete(str.lastIndexOf("."), str.length());
}
}
}
}
补充:
上述解法中运用到了很多String类和StringBuilder类的API,这里再回顾整理一下:
String substring(int index)
:字符串的截取,截取从参数位置一直到字符串末尾,返回新的字符串
String substring(int begin, int end)
:截取从 begin 开始,一直到 end 结束中间的字符串。[begin, end),包含 begin,不包含 end
Strint lastIndexOf(String str)
:返回指定字符串在字符串中最后出现的索引位置,没有则返回-1
string str = "abcdefg";
str = str.substring(0, str.LastIndexOf("c"));
System.out.println(str); //Output:ab
StringBuilder delete(int a,int b)
:删除索引从 a 到 b 的所有字符,包括a但不包括b
StringBuilder deleteCharAt(int s)
:删除索引 a 处的字符。
还有 Number 类中:
static int parseInt(String s)
:将字符串类型转换为数值类型,返回值为十进制表示的整数
static int parseInt(String s, int radix)
:使用 radix 指定的基数,将字符串参数解析为有符号的整数,基数可以是 10, 2, 8, 或 16 等进制数
public class Test{
public static void main(String args[]){
int x =Integer.parseInt("9");
double c = Double.parseDouble("5");
int b = Integer.parseInt("444",16);
System.out.println(x); //9
System.out.println(c); //5.0
System.out.println(b); //1092
}
}
此外还有一种在转化字符串时常用到的方法:
Integer.valueOf(String str)
,返回值是一个保存了str值的Integer类