1
1
## 题目地址
2
- https://leetcode-cn.com/problems/restore-ip-addresses/
3
2
4
- # 93. 复原IP地址
3
+ > 一些录友表示跟不上现在的节奏,想从头开始打卡学习起来,可以在公众号左下方,「算法汇总」可以找到历史文章,都是按系列排好顺序的,挨个看就可以了,看文章下的留言你就会发现,有很多录友都在从头打卡,你并不孤单!
4
+
5
+ # 93.复原IP地址
6
+
7
+ 题目地址:https://leetcode-cn.com/problems/restore-ip-addresses/
5
8
6
9
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
7
10
8
11
有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
9
12
10
13
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效的 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效的 IP 地址。
11
14
12
-
13
-
14
- 示例 1:
15
+ 示例 1:
15
16
输入:s = "25525511135"
16
17
输出:[ "255.255.11.135","255.255.111.35"]
17
18
@@ -36,17 +37,44 @@ https://leetcode-cn.com/problems/restore-ip-addresses/
36
37
s 仅由数字组成
37
38
38
39
39
- ## 思路
40
+ # 思路
41
+
42
+ 做这道题目之前,最好先把[ 回溯算法:分割回文串] ( https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q ) 这个做了。
40
43
41
- 这道题目相信大家刚看时看到的时候 ,应该会一脸茫然。
44
+ 这道题目相信大家刚看的时候 ,应该会一脸茫然。
42
45
43
- 那么只要意识到这是切割问题,那么切割问题就可以使用回溯搜索法把所有可能性搜出来,和 [ 0131. 分割回文串] ( https://github. com/youngyangyang04/leetcode/blob/master/problems/0131.分割回文串.md ) 类似 。
46
+ 其实只要意识到这是切割问题, ** 切割问题就可以使用回溯搜索法把所有可能性搜出来 ** ,和刚做过的 [ 回溯算法: 分割回文串] ( https://mp.weixin.qq. com/s/Pb1epUTbU8fHIht-g_MS5Q ) 就十分类似了 。
44
47
45
- 那么切割问题可以抽象为树型结构 ,如图:
48
+ 切割问题可以抽象为树型结构 ,如图:
46
49
47
50
<img src =' ../pics/93.复原IP地址.png ' width =600 > </img ></div >
48
51
49
- 终止条件: 和[ 0131.分割回文串] ( https://github.com/youngyangyang04/leetcode/blob/master/problems/0131.分割回文串.md ) 不同,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
52
+
53
+ ## 回溯三部曲
54
+
55
+ * 递归参数
56
+
57
+ 在[ 回溯算法:分割回文串] ( https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q ) 中我们就提到切割问题类似组合问题。
58
+
59
+ startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
60
+
61
+ 本题我们还需要一个变量pointNum,记录添加逗点的数量。
62
+
63
+ 所以代码如下:
64
+
65
+ ```
66
+ vector<string> result;// 记录结果
67
+ // startIndex: 搜索的起始位置,pointNum:添加逗点的数量
68
+ void backtracking(string& s, int startIndex, int pointNum) {
69
+ ```
70
+
71
+ * 递归终止条件
72
+
73
+ 终止条件和[ 回溯算法:分割回文串] ( https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q ) 情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
74
+
75
+ pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
76
+
77
+ 然后验证一下第四段是否合法,如果合法就加入到结果集里
50
78
51
79
代码如下:
52
80
@@ -60,24 +88,40 @@ if (pointNum == 3) { // 逗点数量为3时,分隔结束
60
88
}
61
89
```
62
90
63
- 那么再来看循环遍历的过程如何截取子串。
91
+ * 单层搜索的逻辑
92
+
93
+ 在[ 回溯算法:分割回文串] ( https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q ) 中已经讲过在循环遍历中如何截取子串。
94
+
95
+ 在` for (int i = startIndex; i < s.size(); i++) ` 循环中 [ startIndex, i] 这个区间就是截取的子串,需要判断这个子串是否合法。
64
96
65
- 在` for (int i = startIndex; i < s.size(); i++) ` 循环中 [ startIndex, i] 这个区间就是截取的子串,需要判断这个子串是否合法,如果合法就在字符串后面加上符号` . ` 表示已经分割。
97
+ 如果合法就在字符串后面加上符号` . ` 表示已经分割。
98
+
99
+ 如果不合法就结束本层循环,如图中剪掉的分支:
100
+
101
+ <img src =' ../pics/93.复原IP地址.png ' width =600 > </img ></div >
66
102
67
103
然后就是递归和回溯的过程:
68
104
69
- 递归调用时,下一层递归的startIndex要从i+2开始(因为刚刚在字符串中加入了分隔符 ` . ` ),同时记录分割符的数量pointNum 要 +1。
105
+ 递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入了分隔符 ` . ` ),同时记录分割符的数量pointNum 要 +1。
70
106
71
- 回溯的时候,就将刚刚加入的分隔符` . ` 删掉就可以了,** pointNum其实也要减一,但是 pointNum+1 的逻辑放在递归函数的参数里了,这里相当于隐藏了回溯pointNum的过程 ** 。
107
+ 回溯的时候,就将刚刚加入的分隔符` . ` 删掉就可以了,pointNum也要-1 。
72
108
73
- 递归和回溯代码如下 :
109
+ 代码如下 :
74
110
75
111
```
76
- // 插入逗点之后下一个子串的起始位置为i+2
77
- backtracking(s, i + 2, pointNum + 1);
78
- s.erase(s.begin() + i + 1); // 回溯时删掉逗点
112
+ for (int i = startIndex; i < s.size(); i++) {
113
+ if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的子串是否合法
114
+ s.insert(s.begin() + i + 1 , '.'); // 在i的后面插入一个逗点
115
+ pointNum++;
116
+ backtracking(s, i + 2, pointNum); // 插入逗点之后下一个子串的起始位置为i+2
117
+ pointNum--; // 回溯
118
+ s.erase(s.begin() + i + 1); // 回溯删掉逗点
119
+ } else break; // 不合法,直接结束本层循环
120
+ }
79
121
```
80
122
123
+ ## 判断子串是否合法
124
+
81
125
最后就是在写一个判断段位是否是有效段位了。
82
126
83
127
主要考虑到如下三点:
@@ -111,9 +155,27 @@ bool isValid(const string& s, int start, int end) {
111
155
}
112
156
```
113
157
114
- 关键代码已经讲完,整体代码如下:
158
+ ## C++代码
159
+
115
160
116
- ## C++代码
161
+ 根据[ 关于回溯算法,你该了解这些!] ( https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw ) 给出的回溯算法模板:
162
+
163
+ ```
164
+ void backtracking(参数) {
165
+ if (终止条件) {
166
+ 存放结果;
167
+ return;
168
+ }
169
+
170
+ for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
171
+ 处理节点;
172
+ backtracking(路径,选择列表); // 递归
173
+ 回溯,撤销处理结果
174
+ }
175
+ }
176
+ ```
177
+
178
+ 可以写出如下回溯算法C++代码:
117
179
118
180
```
119
181
class Solution {
@@ -128,16 +190,14 @@ private:
128
190
}
129
191
return;
130
192
}
131
- // 从起始位置开始构造字段字符串串
132
193
for (int i = startIndex; i < s.size(); i++) {
133
- // 判断 [startIndex,i] 这个区间的子串是否合法
134
- if (isValid(s, startIndex, i)) {
135
- // 合法,在i的后面插入一个逗点
136
- s.insert(s.begin() + i + 1 , '.');
137
- // 插入逗点之后下一个子串的起始位置为i+2
138
- backtracking(s, i + 2, pointNum + 1);
139
- s.erase(s.begin() + i + 1); // 回溯时删掉逗点
140
- } else break;
194
+ if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的子串是否合法
195
+ s.insert(s.begin() + i + 1 , '.'); // 在i的后面插入一个逗点
196
+ pointNum++;
197
+ backtracking(s, i + 2, pointNum); // 插入逗点之后下一个子串的起始位置为i+2
198
+ pointNum--; // 回溯
199
+ s.erase(s.begin() + i + 1); // 回溯删掉逗点
200
+ } else break; // 不合法,直接结束本层循环
141
201
}
142
202
}
143
203
// 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法
@@ -167,6 +227,27 @@ public:
167
227
return result;
168
228
}
169
229
};
230
+
170
231
```
171
232
172
- > 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。
233
+ # 总结
234
+
235
+ 在[ 回溯算法:分割回文串] ( https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q ) 中我列举的分割字符串的难点,本题都覆盖了。
236
+
237
+ 而且本题还需要操作字符串添加逗号作为分隔符,并验证区间的合法性。
238
+
239
+ 可以说是[ 回溯算法:分割回文串] ( https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q ) 的加强版。
240
+
241
+ 在本文的树形结构图中,我已经把详细的分析思路都画了出来,相信大家看了之后一定会思路清晰不少!
242
+
243
+ ** 就酱,「代码随想录」值得推荐给你的朋友们!**
244
+
245
+
246
+ 一些录友表示跟不上现在的节奏,想从头开始打卡学习起来,可以在在公众号左下方,「算法汇总」可以找到历史文章,都是按系列排好顺序的,挨个看就可以了,别忘了打卡。
247
+
248
+ ** 很多录友都在从头开始打卡学习,看看前面文章的留言区就知道了,你并不孤单!**
249
+
250
+
251
+
252
+ > 我是[ 程序员Carl] ( https://github.com/youngyangyang04 ) ,更多[ 精彩算法文章] ( https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect ) 尽在:[ 代码随想录] ( https://img-blog.csdnimg.cn/20200815195519696.png ) ,期待你的关注!
253
+
0 commit comments