0
点赞
收藏
分享

微信扫一扫

[典型]BM74 数字字符串转化成IP地址-中等

​​BM74 数字字符串转化成IP地址​​

知识点​​字符串​​​​回溯​​

描述

现在有一个只包含数字的字符串,将该字符串转化成IP地址的形式,返回所有可能的情况。例如:给出的字符串为"25525522135",返回["255.255.22.135", "255.255.221.35"]. (顺序没有关系)

数据范围:字符串长度 [典型]BM74 数字字符串转化成IP地址-中等_回溯要求:空间复杂度 [典型]BM74 数字字符串转化成IP地址-中等_回溯_02,时间复杂度 [典型]BM74 数字字符串转化成IP地址-中等_回溯_02

注意:ip地址是由四段数字组成的数字序列,格式如 "x.x.x.x",其中 x 的范围应当是 [0,255]。

示例1

输入:

"25525522135"

复制返回值:

["255.255.22.135","255.255.221.35"]

复制

示例2

输入:

"1111"

复制返回值:

["1.1.1.1"]

复制

示例3

输入:

"000256"

复制返回值:

"[]"

题解

递归+回溯解法

一个ip由4个16bit的二进制数组成,我们称每一个16bit的数字为一个分节。每个分节的取值范围是0~255,其长度使用字符串表示最短为1个字节,最长为3个。对于任意的一个分节,我们每次可以从输入数据中选取1~3个字节之后,再选取下一分解。

我们可以实现一个函数用于求解从索引index开始,处于第counter个分解的所有ip的情况。步骤如下:

  1. 开始条件:索引index从0开始,counter也从0开始表示还没有选取分解
  2. 本层实现:在选取第counter个分解的时候只要剩余的数据足够长我们都可以选取1~3个字符,假设我们选取k个字符,那么进入下一层的索引index = index + k,counter+=1,ip = ip + s.sub_str(index,k)。限制条件:所选取字符不能有前导0,他们的值不能大于255。
  3. 终止条件:如果counter等于4,表示选取到最后一个,如果刚好走完整个数组则表示一个合法的ip


代码如下:

#include <bits/stdc++.h>

using namespace std;

// BM74 数字字符串转化成IP地址
// https://www.nowcoder.com/practice/ce73540d47374dbe85b3125f57727e1e?tpId=295&tqId=653&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295

int append_str(std::string &ip, const std::string &s, int start, int len)
{
if (start + len > s.size())
{
return 0;
}

int res = len;
if (!ip.empty())
{
ip.append(1, '.');
res++;
}
ip.append(s.substr(start, len));
return res;
}

void pop_str(std::string &ip, int count)
{
for (int i = 0; i < count; ++i)
{
ip.pop_back();
}
}

void solve(const std::string &s, int index, std::string &ip, int counter, std::vector<std::string> &res)
{
// 非法的条件~~
if (counter > 4 || index > s.size() || (counter == 4 && index < s.size() - 1))
{
return;
}

// 终止条件,此时将ip放入结果队列中
if (index == s.size() && counter == 4)
{
res.push_back(ip);
return;
}

for (int k = 0; k < 3; ++k)// 每次可以选择1~3个子杰
{
if (index + k >= s.size())// 防止越界
{
break;
}

if (k > 0 && s[index] == '0')// 如果选择1个以上字节的时候,不能有前导0
{
break;
}
if (k == 2)// 防止大于255的数据坐无畏的递归
{
int value = 0;
for (int i = index; i <= index + k; ++i)
{
value = value * 10 + (s[i] - '0');
}

if (value > 255)
{
continue;
}
}
int len = append_str(ip, s, index, k + 1);// 将当前的字符放入ip中
solve(s, index + k + 1, ip, counter + 1, res);
pop_str(ip, len);// 回溯
}
}

vector<string> restoreIpAddresses(string s)
{
std::string ip;
int counter{0};
int num{0};
int index{0};
std::vector<std::string> res;
solve(s, index, ip, counter, res);
return res;
}

int main()
{
std::vector<std::string> cases = {
"25525522135"};
for (auto &s : cases)
{
auto res = restoreIpAddresses(s);
for (auto &ip : res)
{
std::cout << ip << std::endl;
}
}
return 0;
}


暴力求解法

我们可以把求解看做在这个字符串中插入3个'.'号。用一个3层的for循环分别表示插入第一、第二、第三个点的位置

具体做法:

  • 依次枚举这三个点的位置。
  • 然后截取出四段数字。
  • 比较截取出来的数字,不能大于255,且除了0以外不能有前导0,然后才能组装成IP地址加入答案中。



代码略~

举报

相关推荐

0 条评论