93.复原IP地址
93.复原IP地址
题目
给定一个只包含数字的字符串,用以表示一个 IP 地址,返回所有可能从 s 获得的 有效 IP 地址 。你可以按任何顺序返回答案。
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。
示例 1:
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
示例 2:
输入:s = "0000"
输出:["0.0.0.0"]
示例 3:
输入:s = "1111"
输出:["1.1.1.1"]
示例 4:
输入:s = "010010"
输出:["0.10.0.10","0.100.1.0"]
示例 5:
输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/restore-ip-addresses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
思路
这道题感觉和131题分割字符串有点像
区别:这道题明确了切三次
相同点:思路是先考虑可以分割成哪些字串,再考虑字串是否符合规定
切割问题就可以使用回溯搜索法把所有可能性搜出来
递归的参数和返回值
每一条路径都是一个字符串,那么应该从分隔符.
来确定分割的次数,就需要一个参数pointNum来记录分隔符的数量,分隔符的数量为3说明切了三次,说明递归结束了。
startIndex来记录起始的位置
List<String> res;
StringBuffer path;//需要频繁操作字符串
void backtracking(String s,int pointNum,int startIndex);
递归的终止条件
pointNum==3说明了分割了三次,分割三次后,如果剩下的字符串符合条件则把该path加入res集合
if(pointNum==3){
//StringBuffer转换成string,判断合法函数区间[start,end];
if(isValue(s,startIndex,s.length()-1))
{
path.add(s.substring(startIndex))
res.add(path.toString());
}
return;
}
判断字符串合法函数
因为截取字符串是消耗性能的,因此,采用传子串下标的方式判断一个子串是否是符合规则,不符合规则就不需要截取了
参数
String s
判断区域[start,end]
返回值
true 符合规则
false 不符合规则
规则
1.0~255之间
2.不能0开头
3.除数字以外的值
boolean isValue(String s,int start,int end){
//0开头的数字
if(s.charAt(start)=='0'&& start!=end) return false;
int num = 0;
for(int i=start;i<=end;i++){
//除数字以外的
if(s.charAt(i)>'9'||s.charAt(i)<'0')return false;
//计算方式 字符串中的数字依次取出+本次的数值
num = num*10+s.charAt(i)-'0';
if(num>255)return false;
}
return true;
}
单层递归逻辑
剪枝:如果有一个字串的长度超过4了,那么必然不可能,不用进入判断合法函数判断,后面长度5、长度6..也不用继续循环了
注意回溯的适合需要把原来添加的子串和 . 一起删除。
错误
这里我删.的时候用了path.deleteCharAt(path.lenthg()-1)
这个是错误的,没有考虑255.255.11.135这种情况!
正确的做法path.deleteCharAt(path.lastIndexOf(".");
删除添加的最后一次出现的.(也就是最后添加的.)删除之后是255.255.11135,再删除11135,最后对11135重新进行截取
for(int i = startIndex; i<s.length();i++){
//剪枝
if(i-startIndex==3)break;
//先判断当前子串是否合法,不合法就采用下一种截法
if(!isValue(s,startIndex,i))continue;
//说明合法了
path.append(s.substring(startIndex,i+1));
path.append('.');
backtracking(s,pointNum+1,i+1);
//这里回溯还要把原来添加的s.substring(startIndex,i+1)和'.'一起删除了
path.deleteCharAt(path.lastIndexOf(".");
int pointLastNum = path.lastIndexOf(".");
path.delete(pointLastNum + 1, path.length());
}
代码
class Solution {
List<String> res;
StringBuffer path;
public List<String> restoreIpAddresses(String s) {
res = new ArrayList<>();
path = new StringBuffer();
if(s.length()>12)return res;
backtracking(s,0,0);
return res;
}
void backtracking(String s,int pointNum,int startIndex){
if(pointNum==3){
if(isValue(s,startIndex,s.length()-1)){
path.append(s.substring(startIndex));
res.add(path.toString());
}
return;
}
for(int i = startIndex; i<s.length();i++){
if(isValue(s,startIndex,i)){
path.append(s.substring(startIndex,i+1));
path.append('.');
backtracking(s,pointNum+1,i+1);
path.deleteCharAt(path.lastIndexOf("."));
int pointLastNum = path.lastIndexOf(".");
path.delete(pointLastNum + 1, path.length());
}else{
break;
};
}
}
boolean isValue(String s,int start,int end){
if(start>end) return false;
if(s.charAt(start)=='0'&& start!=end) return false;
int num = 0;
for(int i=start;i<=end;i++){
if(s.charAt(i)>'9'||s.charAt(i)<'0')return false;
num = num*10+(s.charAt(i)-'0');
if(num>255)return false;
}
return true;
}
}
总结
String 纯数字类型与int类型的转换
String纯字符串转int
Integer.parseInt(str);
其他类型转String
//方法1
String.valueOf( value); // 其中 value 为任意一种数字类型。
//方法2
Integer.toString(i);
//方法3 常用
"" + i;
复习一下之前学习的char数字类型转换与int类型的转换
//int型转化成char数字型型
(char) (1+'0') //49,这里会把'0'转化成ASC码+1 = '1'
//char数字型转化成int类型
('1'-'0') //ASC码相减=int