注:本题使用了分治的思想。
解题方法:递归法、暴力求解法
Leetcode 93
Given a string containing only digits, restore it by returning all possible valid IP address combinations.
For example:
Given “25525511135”,
return [“255.255.11.135”, “255.255.111.35”]. (Order does not matter)
题意:
- 给出一个字符串,然后你的程序需要解析出该字符串可能符合的所有合法ip地址并将之存储在容器中。
思路:
先考虑合法ip地址的格式: “{0-255}.{0-255}.{0-255}.{0-255}”
ip地址由四个part和三个dot组成,每个part的位数为1~3,每个part的值在0~255之间,且如果位数不是1位时,不能以0开头,即不能存在011,01等情况。
先采用分治的思想
因为ip地址是由四部分组成,每部分的构造与合法性要求是一致的,故我可以将分割字符串这个问题分成四个相同的小问题,然后采取递归的方式去解决它
因为有四个相同的小问题,很明显,要得到一个合法的ip地址,需要执行四层递归 ,所以需要传入参数n来标识进行到第几层递归。
然后需要传入未切割的字符串、存储当前递归得到的合法ip地址(一个)的String变量、还有存储所有合法ip地址的vector容器
因为对于每一个部分,有三种情况切割,即1位、2位、3位,故在递归函数中定义一层for循环用于分类讨论,然后将各种分割情况的剩余字符串传入下一层递归函数中
代码如下:
/*2017/9/10 93. Restore_IP_Address 的递归写法(分治思想) 思路: 1.ip地址是四个部分,即需要将字符串切割成四部分; 2.需要对每一部分进行分类讨论,即每部分是1位、2位或者是3位,且要对每一部分的合法性进行验证,故 可以将问题分解成四个相同的小部分,然后用递归实现; 3.在每一次的递归中,由于需要分类讨论,所以还需要一层for循环。 */ class Solution { public: vector<string> restoreIpAddresses(string s) { vector<string> result; Calc(0, s, result, ""); return result; } /* @func Calc:处理每部分part的递归函数 @param n:递归层数 @param s:切割后剩余字符串 @param result: 存储所有合法ip地址的容器 @param output: 存储当前递归合法ip地址的变量*/ void Calc(int n, string s, vector<string>& result, string output) { // result 记得加& // n == 0,1,2,3 分别代表第一、二、三、四层递归 // n == 4 用于终止递归,如果s为空,说明分割准确 if (n == 4) { if (s.empty()) result.push_back(output); } else { for (int k = 1; k <= 3; k++) { // 如果剩余字符串不足以分割,则分割不合法 if (s.size() < k) break; int val = atoi(s.substr(0, k).c_str()); // 当出现以0开头的part,如011, k != std::to_string(val).size() if (val <= 255 && k == std::to_string(val).size()) { Calc(n+1, s.substr(k), result, output+s.substr(0, k)+(n == 3? "" : ".")); } } } } };
补充,由于分割情况不多,这道题可以使用暴力求解法。
假设四个部分的长度分别为a,b,c,d, 那么我可以用四层循环得出所有分割组合,即满足a+b+c+d = s.size(),然后分别检测所有分割组合的合法性,将合法的存入vector容器中
代码如下:
/* 2017/9/10 93. Restore_IP_Address 的递归写法(暴力求解) 思路: ip地址分成四部分,每部分的长度最大为3,这个数字很小, 要得到所有情况,可用暴力求解法 即四层for循环,得到所有符合的组合 a+b+c+d = s.size() 然后对组合分别进行检验,将符合的加入到容器中 */ class Solution { public: vector<string> restoreIpAddresses(string s) { vector<string> result; string output; for (int a = 1; a <= 3; a++) { for (int b = 1; b <= 3; b++) { for (int c = 1; c <= 3; c++) { for (int d = 1; d <= 3; d++) { if (a+b+c+d == s.size()) { int A = atoi(s.substr(0, a).c_str()); int B = atoi(s.substr(a, b).c_str()); int C = atoi(s.substr(a+b, c).c_str()); int D = atoi(s.substr(a+b+c).c_str()); if (A <= 255 && B <= 255 && C <= 255 && D <= 255) { output = std::to_string(A) + "." + std::to_string(B) + "." + std::to_string(C) + "." + std::to_string(D); // 如果有一个part出现以0开头的,如011, // 那么output.size()!=s.size() + 3 if (output.size() == s.size() + 3) result.push_back(output); } } } } } } return result; } };
以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!