6.复原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 地址。
给定一个只包含数字的字符串 s
,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s
中插入 '.'
来形成。你 不能 重新排序或删除 s
中的任何数字。你可以按 任何 顺序返回答案。
示例 1:
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
示例 2:
输入:s = "0000"
输出:["0.0.0.0"]
示例 3:
输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
- 思路分析
本题本质上是一个切割字符串的问题,并且要求切割的子串满足一定的规律,我们仍然可以用回溯算法去解决此类问题。这一我们上一题目分割回文子串方法很相近,只是多了一步在小数点的增添,下面我们以一个例子来分析一下本题的解法
1.初始化:
使用StringBuilder来构建当前的IPv4地址段(称为path)。
使用ArrayList来保存所有找到的有效IPv4地址(称为result)。2.回溯函数 backtrack(String s, int pointSum):
s是当前还未处理的字符串部分。
pointSum表示当前已经添加了多少个点(即,已经找到了多少个数字段)。
每次通过检验未处理的字符串部分来进行递归3.终止条件:
当pointSum等于3时,意味着我们已经找到了三个点,即四个数字段。此时,我们需要检查剩余的字符串s是否有效,并且长度不为0(因为每个数字段至少包含一个字符)。如果满足条件,则将当前path中的字符串添加到result中,并回退状态。4.回溯搜索:
在每次回溯调用中,我们遍历字符串s的所有可能的前缀,检查它们是否是有效的数字段(通过isValid函数)。
如果找到有效的数字段,我们将其添加到path中,并添加一个点。
然后,我们对剩余的字符串s的剩余部分进行递归回溯调用。
在递归返回后,我们需要回退状态,即从path中删除之前添加的数字段和点,并将pointSum减1,以便尝试其他可能的组合。
- Java代码实现
StringBuilder path = new StringBuilder();List<String> result = new ArrayList<>();public List<String> restoreIpAddresses(String s) {backtrack(s, 0);return result;}private void backtrack(String s, int pointSum) {if (pointSum == 3) {if (!s.equals("") && isValid(s)) {path.append(s);result.add(new String(path));path.delete(path.length() - s.length(), path.length());}return;}for (int i = 0; i < s.length(); i++) {String before = s.substring(0, i + 1);if (isValid(before)) {path.append(before);path.append(".");pointSum++;String after = s.substring(i + 1);backtrack(after, pointSum);path.delete(path.length() - before.length() - 1, path.length());pointSum--;}}}private Boolean isValid(String s) {if (s.length() != 1 && s.charAt(0) == '0') { // 0开头的数字不合法return false;}int num = 0;for (int i = 0; i < s.length(); i++) {num = num * 10 + (s.charAt(i) - '0');if (num > 255) { // 如果⼤于255了不合法return false;}}return true;}