Given a string containing only digits, restore it by returning all possible valid IP address combinations.

Example:

Input: "25525511135"
Output: ["255.255.11.135", "255.255.111.35"]

这道题要求是复原IP地址,IP地址对我们并不陌生,就算我们不是学CS的,只要我们是广大网友之一,就应该对其并不陌生。IP地址由32位二进制数组成,为便于使用,常以XXX.XXX.XXX.XXX形式表现,每组XXX代表小于或等于255的10进制数。所以说IP地址总共有四段,每一段可能有一位,两位或者三位,范围是[0, 255],题目明确指出输入字符串只含有数字,所以当某段是三位时,我们要判断其是否越界(>255),还有一点很重要的是,当只有一位时,0可以成某一段,如果有两位或三位时,像 00, 01, 001, 011, 000等都是不合法的,所以我们还是需要有一个判定函数来判断某个字符串是否合法。这道题其实也可以看做是字符串的分段问题,在输入字符串中加入三个点,将字符串分为四段,每一段必须合法,求所有可能的情况。根据目前刷了这么多题,得出了两个经验,一是只要遇到字符串的子序列或配准问题首先考虑动态规划DP,二是只要遇到需要求出所有可能情况首先考虑用递归。这道题并非是求字符串的子序列或配准问题,更符合第二种情况,所以我们要用递归来解。我们用k来表示当前还需要分的段数,如果k = 0,则表示三个点已经加入完成,四段已经形成,若这时字符串刚好为空,则将当前分好的结果保存。若k != 0, 则对于每一段,我们分别用一位,两位,三位来尝试,分别判断其合不合法,如果合法,则调用递归继续分剩下的字符串,最终和求出所有合法组合,代码如下:

C++ 解法一:

class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> res;
restore(s, , "", res);
return res;
}
void restore(string s, int k, string out, vector<string> &res) {
if (k == ) {
if (s.empty()) res.push_back(out);
}
else {
for (int i = ; i <= ; ++i) {
if (s.size() >= i && isValid(s.substr(, i))) {
if (k == ) restore(s.substr(i), k - , out + s.substr(, i), res);
else restore(s.substr(i), k - , out + s.substr(, i) + ".", res);
}
}
}
}
bool isValid(string s) {
if (s.empty() || s.size() > || (s.size() > && s[] == '')) return false;
int res = atoi(s.c_str());
return res <= && res >= ;
}
};

我们也可以省掉isValid函数,直接在调用递归之前用if语句来滤掉不符合题意的情况,这里面用了k != std::to_string(val).size(),其实并不难理解,比如当k=3时,说明应该是个三位数,但如果字符是"010",那么转为整型val=10,再转回字符串就是"10",此时的长度和k值不同了,这样就可以找出不合要求的情况了,参见代码如下;

C++ 解法二:

class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> res;
helper(s, , "", res);
return res;
}
void helper(string s, int n, string out, vector<string>& res) {
if (n == ) {
if (s.empty()) res.push_back(out);
} else {
for (int k = ; k < ; ++k) {
if (s.size() < k) break;
int val = atoi(s.substr(, k).c_str());
if (val > || k != std::to_string(val).size()) continue;
helper(s.substr(k), n + , out + s.substr(, k) + (n == ? "" : "."), res);
}
}
}
};

Java 解法二:

public class Solution {
public List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<String>();
helper(s, 0, "", res);
return res;
}
public void helper(String s, int n, String out, List<String> res) {
if (n == 4) {
if (s.isEmpty()) res.add(out);
return;
}
for (int k = 1; k < 4; ++k) {
if (s.length() < k) break;
int val = Integer.parseInt(s.substring(0, k));
if (val > 255 || k != String.valueOf(val).length()) continue;
helper(s.substring(k), n + 1, out + s.substring(0, k) + (n == 3 ? "" : "."), res);
}
}
}

由于每段数字最多只能有三位,而且只能分为四段,所以情况并不是很多,我们可以使用暴力搜索的方法,每一段都循环1到3,然后当4段位数之和等于原字符串长度时,我们进一步判断每段数字是否不大于255,然后滤去不合要求的数字,加入结果中即可,参见代码如下;

C++ 解法三:

class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> res;
for (int a = ; a < ; ++a)
for (int b = ; b < ; ++b)
for (int c = ; c < ; ++c)
for (int d = ; d < ; ++d)
if (a + b + c + d == s.size()) {
int A = stoi(s.substr(, a));
int B = stoi(s.substr(a, b));
int C = stoi(s.substr(a + b, c));
int D = stoi(s.substr(a + b + c, d));
if (A <= && B <= && C <= && D <= ) {
string t = to_string(A) + "." + to_string(B) + "." + to_string(C) + "." + to_string(D);
if (t.size() == s.size() + ) res.push_back(t);
}
}
return res;
}
};

Java 解法三:

public class Solution {
public List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<String>();
for (int a = 1; a < 4; ++a)
for (int b = 1; b < 4; ++b)
for (int c = 1; c < 4; ++c)
for (int d = 1; d < 4; ++d)
if (a + b + c + d == s.length()) {
int A = Integer.parseInt(s.substring(0, a));
int B = Integer.parseInt(s.substring(a, a + b));
int C = Integer.parseInt(s.substring(a + b, a + b + c));
int D = Integer.parseInt(s.substring(a + b + c));
if (A <= 255 && B <= 255 && C <= 255 && D <= 255) {
String t = String.valueOf(A) + "." + String.valueOf(B) + "." + String.valueOf(C) + "." + String.valueOf(D);
if (t.length() == s.length() + 3) res.add(t);
}
}
return res;
}
}

类似题目:

IP to CIDR

参考资料:

https://leetcode.com/problems/restore-ip-addresses/

https://leetcode.com/problems/restore-ip-addresses/discuss/30972/who-can-beat-this-code

https://leetcode.com/problems/restore-ip-addresses/discuss/31098/easy-java-code-of-backtracking-within-16-lines

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Restore IP Addresses 复原IP地址的更多相关文章

  1. [LeetCode] 93. Restore IP Addresses 复原IP地址

    Given a string containing only digits, restore it by returning all possible valid IP address combina ...

  2. 093 Restore IP Addresses 复原IP地址

    给定一个只包含数字的字符串,复原它并返回所有可能的IP地址格式.例如:给定 "25525511135",返回 ["255.255.11.135", " ...

  3. Leetcode93. Restore IP Addresses复原IP地址

    给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式. 示例: 输入: "25525511135" 输出: ["255.255.11.135", ...

  4. [LintCode] Restore IP Address 复原IP地址

    Given a string containing only digits, restore it by returning all possible valid IP address combina ...

  5. leetcode刷题-93复原IP地址

    题目 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式. 有效的 IP 地址正好由四个整数(每个整数位于 0 到 255 之间组成),整数之间用 '.' 分隔. 示例: 输入: &q ...

  6. 【一天一道LeetCode】#93. Restore IP Addresses

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  7. LeetCode解题报告—— Reverse Linked List II & Restore IP Addresses & Unique Binary Search Trees II

    1. Reverse Linked List II Reverse a linked list from position m to n. Do it in-place and in one-pass ...

  8. leetcode -day29 Binary Tree Inorder Traversal &amp; Restore IP Addresses

    1.  Binary Tree Inorder Traversal Given a binary tree, return the inorder traversal of its nodes' ...

  9. LeetCode:复原IP地址【93】

    LeetCode:复原IP地址[93] 题目描述 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式. 示例: 输入: "25525511135" 输出: [&qu ...

随机推荐

  1. 使用ViewPager实现自动轮播

    很多APP中都实现了类似引导页的自动轮播,不由得想到昨天的引导页上修改一下代码实现轮播. 其实大体上只需要添加一个线程循环执行就可以了. 项目已同步至:https://github.com/nanch ...

  2. How to implement equals() and hashCode() methods in Java[reproduced]

    Part I:equals() (javadoc) must define an equivalence relation (it must be reflexive, symmetric, and ...

  3. .NET 实现并行的几种方式(二)

    本随笔续接:.NET 实现并行的几种方式(一) 四.Task 3)Task.NET 4.5 中的简易方式 在上篇随笔中,两个Demo使用的是 .NET 4.0 中的方式,代码写起来略显麻烦,这不 .N ...

  4. Angular2中对ASP.NET MVC跨域访问

    应用场景 项目开发决定使用angular2进行前后端分离开发,由我负责后端服务的开发,起初选择的是web api进行开发.对跨域访问通过API中间件+过滤器对跨域访问进行支持.开发一段后,通知需要移植 ...

  5. 设计模式(九)装饰者模式(Decorator Pattern)

    一.引言 在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).A ...

  6. K60——寄存器

    (1)PTx_BASE_PTR为GPIO寄存器结构体基址指针(PTR即point to register,x=A/B/C/D/E) /* GPIO - Peripheral instance base ...

  7. JavaScript--面向对象--猜拳游戏

    //html代码 <!doctype html> <html> <head> <meta charset="UTF-8"> < ...

  8. js拖拽

  9. H5 meta小结

    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1, ...

  10. Spring in Action 学习笔记一

    Spring 核心       Spring的主要特性仅仅是 依赖注入DI和面向切面编程AOP       JavaBean 1996.12 Javav 规范针对Java定义了软件组件模型,是简单的J ...