题目:
有效 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 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。
你不能重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
-- -- -- -- -- -- -- -- -- -- -
输入:s = "25525511135"
输出:[ "255.255.11.135" , "255.255.111.35" ]
输入:s = "0000"
输出:[ "0.0.0.0" ]
输入:s = "1111"
输出:[ "1.1.1.1" ]
输入:s = "010010"
输出:[ "0.10.0.10" , "0.100.1.0" ]
输入:s = "101023"
输出:[ "1.0.10.23" , "1.0.102.3" , "10.1.0.23" , "10.10.2.3" , "101.0.2.3" ]
-- -- -- -- -- -- -- -- -- -- -- -
思路:
回溯三部曲:
在131. 分割回文串中我们就提到切割问题类似组合问题。
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
本题我们还需要一个变量pointNum,记录添加逗点的数量。
所以代码如下:
vector< string> result;
void backtracking ( string& s, int startIndex, int pointNum) {
递归终止条件
终止条件和131. 分割回文串情况就不同了,本题明确要求只会分成4 段,
所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
pointNum表示逗点数量,pointNum为3 说明字符串分成了4 段了。
然后验证一下第四段是否合法,如果合法就加入到结果集里
代码如下:
if ( pointNum == 3 ) {
if ( isValid ( s, startIndex, s. size ( ) - 1 ) ) {
result. push_back ( s) ;
}
return ;
}
单层搜索的逻辑
在131. 分割回文串 中已经讲过在循环遍历中如何截取子串。
在for ( int i = startIndex; i < s. size ( ) ; i++ ) 循环中 [ startIndex, i] 这个区间就是截取的子串,
需要判断这个子串是否合法。
如果合法就在字符串后面加上符号. 表示已经分割。
如果不合法就结束本层循环,如图中剪掉的分支:
然后就是递归和回溯的过程:
递归调用时,下一层递归的startIndex要从i+ 2 开始(因为需要在字符串中加入了分隔符. ),
同时记录分割符的数量pointNum 要 + 1 。
回溯的时候,就将刚刚加入的分隔符. 删掉就可以了,pointNum也要- 1 。
代码如下:
for ( int i = startIndex; i < s. size ( ) ; i++ ) {
if ( isValid ( s, startIndex, i) ) {
s. insert ( s. begin ( ) + i + 1 , '.' ) ;
pointNum++ ;
backtracking ( s, i + 2 , pointNum) ;
pointNum-- ;
s. erase ( s. begin ( ) + i + 1 ) ;
} else break ;
}
判断子串是否合法:
最后就是在写一个判断段位是否是有效段位了。
主要考虑到如下三点:
段位以0 为开头的数字不合法
段位里有非正整数字符不合法
段位如果大于255 了不合法
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
代码:
class Solution {
List < String > res = new ArrayList < > ( ) ;
public List < String > restoreIpAddresses ( String s) {
if ( s. length ( ) > 12 ) return res;
backTracking ( s, 0 , 0 ) ;
return res;
}
private void backTracking ( String s, int startIndex, int pointNum) {
if ( pointNum == 3 ) {
if ( isValid ( s, startIndex, s. length ( ) - 1 ) ) {
res. add ( s) ;
}
return ;
}
for ( int i = startIndex; i < s. length ( ) ; i++ ) {
if ( isValid ( s, startIndex, i) ) {
s = s. substring ( 0 , i + 1 ) + "." + s. substring ( i + 1 ) ;
pointNum++ ;
backTracking ( s, i + 2 , pointNum) ;
pointNum-- ;
s = s. substring ( 0 , i + 1 ) + s. substring ( i + 2 ) ;
} else break ;
}
}
private boolean isValid ( String s, int startIndex, int end) {
if ( startIndex > end) return false ;
if ( s. charAt ( startIndex) == '0' && startIndex != end) return false ;
int num = 0 ;
for ( int i = startIndex; 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 ;
}
}
力扣链接