复原 IP 地址的思路探讨与源码
复原 IP 地址的题目如下图,该题属于字符串和回溯类型的题目,主要考察对于回溯遍历方法的使用和字符串本身特性的理解。本文的题目作者想到2种方法,分别是直接多次循环方法和回溯方法,其中回溯方法使用Java进行编写,而直接多次循环方法使用Python进行编写,当然这可能不是最优的解法,还希望各位大佬给出更快的算法。
本人认为该题目可以使用回溯方法解决,首先对于字符串的长度进行判断。如果是小于4或者大于12说明本身就不合法,直接排除并返回。然后初始化参数和队列,并且调用回溯搜索函数。在函数内部,我们会判断初始位置和字符串长度是否相等,并且是否尾部的位置是否为0,如果是则直接插入到结果列表里并返回,然后开始循环遍历,因为每个节点可以选择的截取方式只有三种情况,所以这边有三个条件判断,如果初始位置比数组长度要大就直接结束循环,如果尾部的位置乘以3比数组长度减去当前位置的值要小就结束本次循环,如果满足校验函数的结果就将结果加入到列表并继续调用回溯函数,并且将队列的最后一个元素弹出。在校验函数的内部是对IP值本身的范围值和特殊情况值进行校验。最终经过回溯遍历后返回最终结果。那么按照这个思路我们的Java代码如下:
#喷火龙与水箭龟
import java.util.ArrayDeque;
import java.util.ArrayList;
public class Solution {
public List<String> restoreIpAddresses(String s) {
int lenNum = s.length();
List<String> resFinal = new ArrayList<>();
if (lenNum < 4 || lenNum > 12) {
return resFinal;
}
int step = 4;
Deque<String> queueList = new ArrayDeque<>(step);
dfsSearch(s, lenNum, 0, step, queueList, resFinal);
return resFinal;
}
private void dfsSearch(String s, int lenNum, int start, int over, Deque<String> queueList, List<String> resFinal) {
if (start == lenNum) {
if (over == 0) {
resFinal.add(String.join(".", queueList));
}
return;
}
for (int ir = start; ir < start + 3; ir++) {
if (ir >= lenNum) {
break;
}
if (over * 3 < lenNum - ir) {
continue;
}
if (examWord(s, start, ir)) {
String rs = s.substring(start, ir + 1);
queueList.addLast(rs);
dfsSearch(s, lenNum, ir + 1, over - 1, queueList, resFinal);
queueList.removeLast();
}
}
}
private boolean examWord(String s, int begin, int end) {
int lenNum = end - begin + 1;
if (lenNum > 1 && s.charAt(begin) == '0') {
return false;
}
int flag = 0;
while (begin <= end) {
flag = flag * 10 + s.charAt(begin) - '0';
begin = begin + 1;
}
return flag >= 0 && flag <= 255;
}
}
显然,我们看到回溯方法的效果还不错,同时还可以使用直接多次遍历搜索的方法进行处理。首先是定义一个函数判断字符串长度是否为1或者2或者3,然后定义参数和初始化列表,并且开始进行三重for循环遍历的操作,如果最里面的循环的下标比字符串长度要大就直接终止循环,否则就调用检验函数进行分段的比较,只有当每一个部分的结果都满足条件,才能将结果插入到列表里,最终返回结果。所以按照这个思路就可以解决,下面是Python代码部分:
#喷火龙与水箭龟
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
def examWord(word: str) -> bool:
n = len(word)
if(n == 1):
return True
if(n == 2):
return int(word[0]) > 0
if(n == 3):
if(int(word[0]) > 0):
return int(word)<= 255
return False
step = 4
resFinal = []
for ir in range(1,step):
for jr in range(ir+1,ir+step):
for kr in range(jr+1,jr+step):
if(kr >= len(s)):
break
if examWord(s[:ir]) and examWord(s[ir:jr]) and examWord(s[jr:kr]) and examWord(s[kr:]):
resFinal.append(s[:ir] + "." + s[ir:jr] + "." + s[jr:kr] + "." + s[kr:])
return resFinal
从结果来说Java版本的回溯方法的效率还不错,而Python版本的直接多次遍历方法的速度一般,但应该是有更多的方法可以进一步提速的,希望朋友们能够多多指教,非常感谢。