[LeetCode] 93. Restore IP Addresses

A valid IP address consists of exactly four integers separated by single dots. Each integer is between 0 and 255 (inclusive) and cannot have leading zeros.

  • For example, "0.1.2.201" and "192.168.1.1" are valid IP addresses, but "0.011.255.245""192.168.1.312" and "192.168@1.1" are invalid IP addresses.

Given a string s containing only digits, return all possible valid IP addresses that can be formed by inserting dots into s. You are not allowed to reorder or remove any digits in s. You may return the valid IP addresses in any order.

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 = "101023"
Output: ["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]

Constraints:

  • 1 <= s.length <= 20
  • s consists of digits only.

复原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 中的任何数字。你可以按 任何 顺序返回答案。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/restore-ip-addresses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

首先明确一下一个 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 }

 

LeetCode 题目总结

posted @ 2020-05-01 12:02  CNoodle  阅读(450)  评论(0编辑  收藏  举报