Given a string s
containing only digits, return all possible valid IP addresses that can be obtained from s
. You can return them in any order.
A valid IP address consists of exactly four integers, each integer is between 0
and 255
, separated by single dots and cannot have leading zeros. For example, "0.1.2.201" and "192.168.1.1" are valid IP addresses and "0.011.255.245", "192.168.1.312" and "192.168@1.1" are invalid IP addresses.
Example 1:
Input: s = "25525511135" Output: ["255.255.11.135","255.255.111.35"]
Example 2:
Input: s = "0000" Output: ["0.0.0.0"]
Example 3:
Input: s = "1111" Output: ["1.1.1.1"]
Example 4:
Input: s = "010010" Output: ["0.10.0.10","0.100.1.0"]
Example 5:
Input: s = "101023" Output: ["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
Constraints:
0 <= s.length <= 3000
s
consists of digits only.
复原IP地址。
题意是给一个字符串,请你把它还原成IP地址。
首先明确一下一个valid的IP地址,是需要满足如下几个条件的
- 只能分成4段
- 每段最多只有3个digit
- 每段是一个不超过255的整数,且这个数字不是0的话,是不能以0开头的(比如01这种就是错的)
两种思路,一是暴力解;二是回溯backtracking。
首先给出暴力解。既然要满足如上几个条件,那么暴力解是需要把input分成三段的,每段的长度介于[1, 3]之间,同时需要一个helper函数判断是否是一个valid的segment,valid的条件就是如上几条。代码如下,
时间O(n^3)
空间O(1)
Java实现
1 class Solution { 2 public List<String> restoreIpAddresses(String s) { 3 List<String> res = new ArrayList<>(); 4 int n = s.length(); 5 for (int i = 0; i < 3; i++) { 6 for (int j = i + 1; j < i + 4; j++) { 7 for (int k = j + 1; k < j + 4; k++) { 8 if (i < n && j < n && k < n) { 9 String tmp1 = s.substring(0, i + 1); 10 String tmp2 = s.substring(i + 1, j + 1); 11 String tmp3 = s.substring(j + 1, k + 1); 12 String tmp4 = s.substring(k + 1); 13 if (helper(tmp1) && helper(tmp2) && helper(tmp3) && helper(tmp4)) { 14 res.add(tmp1 + '.' + tmp2 + '.' + tmp3 + '.' + tmp4); 15 } 16 } 17 } 18 } 19 } 20 return res; 21 } 22 23 private boolean helper(String tmp) { 24 if (tmp == null || tmp.length() == 0 || tmp.length() > 3 || (tmp.charAt(0) == '0' && tmp.length() > 1) 25 || Integer.parseInt(tmp) > 255) { 26 return false; 27 } 28 return true; 29 } 30 }
接下来是回溯,我参考了这个帖子
时间O(1) - 有效的IP地址的个数是有限的
空间O(1) - 有效的IP地址的个数是有限的
Java实现
1 class Solution { 2 public List<String> restoreIpAddresses(String s) { 3 List<String> ans = new ArrayList<>(); 4 if (s == null || s.length() == 0) { 5 return ans; 6 } 7 // 回溯 8 helper(s, 0, new ArrayList<>(), ans); 9 return ans; 10 } 11 12 // 中间两个参数解释:pos-当前遍历到 s 字符串中的位置,cur-当前存放已经确定好的 ip 段的数量 13 private void helper(String s, int pos, List<String> cur, List<String> ans) { 14 if (cur.size() == 4) { 15 // 如果此时 pos 也刚好遍历完整个 s 16 if (pos == s.length()) { 17 // join 用法:例如 [[255],[255],[111],[35]] -> 255.255.111.35 18 ans.add(String.join(".", cur)); 19 } 20 return; 21 } 22 23 // ip 地址每段最多有三个数字 24 for (int i = 1; i <= 3; i++) { 25 // 如果当前位置距离 s 末尾小于 3 就不用再分段了,直接跳出循环即可。 26 if (pos + i > s.length()) { 27 break; 28 } 29 // 将 s 的子串开始分段 30 String segment = s.substring(pos, pos + i); 31 // 剪枝条件:段的起始位置不能为 0,段拆箱成 int 类型的长度不能大于 255 32 if (segment.startsWith("0") && segment.length() > 1 || (i == 3 && Integer.parseInt(segment) > 255)) { 33 continue; 34 } 35 // 符合要求就加入到 cur 数组中 36 cur.add(segment); 37 // 继续递归遍历下一个位置 38 helper(s, pos + i, cur, ans); 39 // 回退到上一个元素,即回溯 40 cur.remove(cur.size() - 1); 41 } 42 } 43 }
另一种回溯实现
1 class Solution { 2 public List<String> restoreIpAddresses(String s) { 3 List<String> res = new ArrayList<>(); 4 if (s == null || s.length() > 12 || s.length() < 4) { 5 return res; 6 } 7 helper(res, s, "", 0, 0); 8 return res; 9 } 10 11 private void helper(List<String> res, String s, String cur, int index, int count) { 12 if (count > 4) { 13 return; 14 } 15 if (count == 4 && index == s.length()) { 16 res.add(cur); 17 return; 18 } 19 for (int i = 1; i < 4; i++) { 20 if (index + i > s.length()) { 21 break; 22 } 23 String temp = s.substring(index, index + i); 24 if (temp.startsWith("0") && temp.length() > 1) { 25 continue; 26 } 27 if (i == 3 && Integer.parseInt(temp) >= 256) { 28 continue; 29 } 30 helper(res, s, cur + temp + (count == 3 ? "" : "."), index + i, count + 1); 31 } 32 } 33 }