求一个数字字符串的所有合法的IP地址

近日在面试美团的时候手撕一道回溯法的算法题,题意如下:

给定一个数字字符串,要求将这个数字字符串进行分割,使得分割的结果为有效的IP地址。

样例输入:

25525511135

样例输出:

255.255.11.135, 255.255.111.35

 这道题其实可以看做是字符串分段问题,再输入的字符串中加入三个点,将字符串分割成四段,每一段必须合法,求所有可能的情况。目前遇到字符串的处理经验为:1、若题目问的是字符串的子序列问题首先考虑使用动态规划的方法,2、如果题目问的是求出所有可能的情况,那么首先考虑使用递归的方法。所以这道题使用递归的方法求解。

使用n表示当前已经分了几个分段,注意到此处的输入为字符串类型,那么如果想将将其转化成int类型变量的话可以先使用c_str()函数将其转化成字符数组,然后使用atoi()函数将其转化成int型数据,这样就可以和0-255这个范围进行比较了。

递归的大致思路如下:

1. 将最后的结果存入一个全局的字符串向量res中。

2. 递归的函数有四个参数,分别是剩下的字符串s,已经分段的个数n,分割过程中产生的临时结果out,结果向量res。

3. 如果已经完成了四段的分割,那么将结果push_back()入res中

4. 否则的话,下一个分段的长度为1-3,对于每一种长度,都要求大小在0-255之间,而且除了0以外不能够以0开头。如果满足条件的话。进入5。

5.递归,递归参数为余下的字符串,n+1,out+s.substr(0,k)+(n==3?"":"."),结果向量res。

代码如下:

#include 
#include 
#include 
using namespace std;

void helper(string s, int n, string out, vector& res) {
    if (n == 4) {
        if (s.empty()) res.push_back(out);
    }    
    else {
        for (int k = 1; k < 4; ++k) {
            if (s.size() < k) break;
            int val = atoi(s.substr(0, k).c_str());
            if (val > 255 || k != to_string(val).size()) continue;
            helper(s.substr(k), n + 1, out + s.substr(0, k) + (n == 3 ? "" : "."), res);
        }
    }
}

int main() {
    string strIP;
    cin >> strIP;
    vector res;
    string out;
    helper(strIP,0,out,res);
    for (int i = 0; i < res.size(); i++) {
        cout << res[i] << endl;
    }
}

上述代码中有一段非常巧妙的代码(当然不是我想的,下次我应该可以想的出来:( ):

int val = atoi(s.substr(0, k).c_str());
if (val > 255 || k != to_string(val).size()) continue;

这里atoi可以将字符数组转化成整型数字

第二行的又使用to_string来将数字转化成字符串,然后通过比较这两个字符串的长度就可以判断是不是以0开头的不为0的数字了。


通过以上的分析,我们可以得出一个递归处理字符串所有可能子串的题目的一般方法:

1. 判断分段是否结束,如果结束,那么将临时结果存入最终结果中,否则的话执行2

2. 从一个分段的起始条件开始,判断当前分段是否满足题意,如果满足题意,那么递归,否则的话,增加字符串的长度,重复执行2.


参考资料:https://www.cnblogs.com/ariel-dreamland/p/9159611.html

你可能感兴趣的:(数据结构与算法)