【LeetCode每日一题】(8.9)复原IP地址(回溯)
复原IP地址
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 IP 地址正好由四个整数(每个整数位于 0 到 255 之间组成),整数之间用 ‘.’ 分隔。
示例:
输入: "25525511135"
输出: ["255.255.11.135", "255.255.111.35"]
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/restore-ip-addresses 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
这题之前做过,不过上次做的一头雾水。 现在一看就知道是回溯了。
做第一步时我们有几种 选择 ?以 “25525511135” 为例:
选 "2" 作为第一个片段 选 "25" 作为第一个片段 选 "255" 作为第一个片段
每次有三种选择,做了选择后,又面临三种选择:切出一种长度的片段作为第二个片段。 这会像树一样向下分支,我们用 DFS 去遍历所有选择,并且是回溯,为什么是回溯? 因为你每一步选择可能累积生一个错误结果,这时要撤销最后一个选择,去试探另一个选择。 穷举出所有可能,才能找出所有组合。好,我们现在讲完 回溯的第一个要点——选择。
回溯的第二个要点——约束
这道题的约束条件是: 一个片段的长度是 1~3 片段的值范围是 0~255 不能是 "0x"、"0xx" 形式(这个是测试用例告诉我们的) 这些约束都将应用在我们的 DFS 函数中,达到剪枝的效果。
回溯的第三个要点——目标
我们目标决定了我们的 DFS 什么时候捕捉答案,什么时候该砍掉死支(然后回溯)。 我们目标是生成 4 个有效片段,并且我们要用光 IP 字符串的字符。 当遍历的节点满足该条件时,说明生成了一个有效组合,推入结果数组。 生成了4个有效片段,但没用过所有字符,则不往下递归,选择回溯。
定义dfs函数
dfs函数传什么,用什么代表不同节点的状态? 选择切出一个长度的片段后,剩余的子串继续递归,我们可以用指向剩余子串起始位置的指针,加上当前已经生成的片段数组,作为状态,传入 dfs 函数。 dfs 函数做的是「复原从指针 start 开始的子串」。
代码实现
vector<string> restoreIpAddresses(string s, int index)
{
vector<string> vip;
if (index == 3) {
if (s.size() == 0 || s.size() > 3 || (s.size() > 1 && s[0] == '0'))
return vip;
int val = atoi(s.c_str());
if (val >= 0 && val <= 255) {
vip.push_back(s);
}
return vip;
} else {
for (int i = 1; i < 4 && i <= s.size(); i++) {
string tmp = s.substr(0, i);
if (i > 1 && s[0] == '0')
continue;
int val = atoi(tmp.c_str());
if (val >= 0 && val <= 255) {
vector<string> nextv = restoreIpAddresses(s.substr(i), index+1);
for (int k = 0; k < nextv.size(); ++k) {
string ip(tmp);
ip.append(".").append(nextv[k]);
vip.push_back(ip);
}
}
}
}
return vip;
}
vector<string> restoreIpAddresses(string s) {
return restoreIpAddresses(s, 0);
}
- java-FFmpeg(一) 实现视频的转码和截图功能
- websocket(二) websocket的简单实现,识别用户属性的群聊
- websocket教程(一) 非常有趣的理解websocket
- 前端插件——头像截图上传插件的使用(带后台)
- 如何减轻ajax定时触发对服务器造成的压力和带宽的压力?ajax-长轮训
- Spark源码之Standalone模式下master持久化引擎讲解
- spring整合quartz
- android沉浸式状态栏的实现
- Jayrock: JSON and JSON-RPC for .NET
- rabbitMQ教程(三) spring整合rabbitMQ代码实例
- 谈谈序列化—实体bean一定要实现Serializable接口?
- Kafka源码系列之通过源码分析Producer性能瓶颈
- 微软在动态语言支持上超越了Java?
- JAVA图片批量上传JS-带预览功能
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- [Oracle故障处理]记一次INST_DRTLD_MISMATCH导致的version count过多的问题
- 查表法实现十进制转化成其他进制
- ArrayList源码分析
- java_String类、StringBuilder类、Arrays类、Math类的使用
- 抽象类与接口
- java_static、final、super、this关键字的使用
- Lambda表达式
- java_字节流、字符流
- HashMap源码分析
- [周末往期回顾]使用cx_Oracle连接Oracle
- java_数组的定义与操作
- LinkedList源码分析
- MarkDown语法的详细使用教程
- java_内部类、匿名内部类的使用
- [周末往期回顾]使用BBED定位数据位置