diff --git a/README.md b/README.md
index 2f204e10..69c285bc 100644
--- a/README.md
+++ b/README.md
@@ -138,6 +138,7 @@
* [本周小结!(回溯算法系列一)](https://mp.weixin.qq.com/s/m2GnTJdkYhAamustbb6lmw)
* [回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)
* [回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)
+ * [回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)
(持续更新中....)
@@ -336,6 +337,7 @@
|[0113.路径总和II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0113.路径总和II.md) |二叉树树 |简单|**深度优先搜索/递归** **回溯** **栈**|
|[0116.填充每个节点的下一个右侧节点指针](https://github.com/youngyangyang04/leetcode/blob/master/problems/0116.填充每个节点的下一个右侧节点指针.md) |二叉树 |中等|**递归** **迭代/广度优先搜索**|
|[0117.填充每个节点的下一个右侧节点指针II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0117.填充每个节点的下一个右侧节点指针II.md) |二叉树 |中等|**递归** **迭代/广度优先搜索**|
+|[0127.单词接龙](https://github.com/youngyangyang04/leetcode/blob/master/problems/ 0127.单词接龙.md) |广度优先搜索 |中等|**广度优先搜索**|
|[0129.求根到叶子节点数字之和](https://github.com/youngyangyang04/leetcode/blob/master/problems/0129.求根到叶子节点数字之和.md) |二叉树 |中等|**递归/回溯** 递归里隐藏着回溯,和113.路径总和II类似|
|[0131.分割回文串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0131.分割回文串.md) |回溯 |中等|**回溯**|
|[0141.环形链表](https://github.com/youngyangyang04/leetcode/blob/master/problems/0141.环形链表.md) |链表 |简单|**快慢指针/双指针**|
@@ -377,6 +379,7 @@
|[0434.字符串中的单词数](https://github.com/youngyangyang04/leetcode/blob/master/problems/0434.字符串中的单词数.md) |字符串 |简单|**模拟**|
|[0450.删除二叉搜索树中的节点](https://github.com/youngyangyang04/leetcode/blob/master/problems/0450.删除二叉搜索树中的节点.md) |树 |中等|**递归**|
|[0454.四数相加II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0454.四数相加II.md) |哈希表 |中等| **哈希**|
+|[0455.分发饼干](https://github.com/youngyangyang04/leetcode/blob/master/problems/0455.分发饼干.md) |贪心 |简单| **贪心**|
|[0459.重复的子字符串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0459.重复的子字符串.md) |字符创 |简单| **KMP**|
|[0486.预测赢家](https://github.com/youngyangyang04/leetcode/blob/master/problems/0486.预测赢家.md) |动态规划 |中等| **递归** **记忆递归** **动态规划**|
|[0491.递增子序列](https://github.com/youngyangyang04/leetcode/blob/master/problems/0491.递增子序列.md) |深度优先搜索 |中等|**深度优先搜索/回溯算法**|
diff --git a/pics/127.单词接龙.png b/pics/127.单词接龙.png
new file mode 100644
index 00000000..581bb558
Binary files /dev/null and b/pics/127.单词接龙.png differ
diff --git a/pics/455.分发饼干.png b/pics/455.分发饼干.png
new file mode 100644
index 00000000..ae66b57f
Binary files /dev/null and b/pics/455.分发饼干.png differ
diff --git a/problems/0057.插入区间.md b/problems/0057.插入区间.md
index 8d6ecc42..79dba1c4 100644
--- a/problems/0057.插入区间.md
+++ b/problems/0057.插入区间.md
@@ -1,4 +1,8 @@
+# 链接
+https://leetcode-cn.com/problems/insert-interval/
+
+# 思路
这道题目合并的情况有很多种,想想都让人头疼。
我把这道题目化为三步:
diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md
index 3da5002c..ab6621d8 100644
--- a/problems/0093.复原IP地址.md
+++ b/problems/0093.复原IP地址.md
@@ -1,7 +1,10 @@
## 题目地址
-https://leetcode-cn.com/problems/restore-ip-addresses/
-# 93. 复原IP地址
+> 一些录友表示跟不上现在的节奏,想从头开始打卡学习起来,可以在公众号左下方,「算法汇总」可以找到历史文章,都是按系列排好顺序的,挨个看就可以了,看文章下的留言你就会发现,有很多录友都在从头打卡,你并不孤单!
+
+# 93.复原IP地址
+
+题目地址:https://leetcode-cn.com/problems/restore-ip-addresses/
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
@@ -9,9 +12,7 @@ https://leetcode-cn.com/problems/restore-ip-addresses/
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效的 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效的 IP 地址。
-
-
-示例 1:
+示例 1:
输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
@@ -36,17 +37,44 @@ https://leetcode-cn.com/problems/restore-ip-addresses/
s 仅由数字组成
-## 思路
+# 思路
-这道题目相信大家刚看时看到的时候,应该会一脸茫然。
+做这道题目之前,最好先把[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)这个做了。
-那么只要意识到这是切割问题,那么切割问题就可以使用回溯搜索法把所有可能性搜出来,和[0131.分割回文串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0131.分割回文串.md) 类似。
+这道题目相信大家刚看的时候,应该会一脸茫然。
-那么切割问题可以抽象为树型结构,如图:
+其实只要意识到这是切割问题,**切割问题就可以使用回溯搜索法把所有可能性搜出来**,和刚做过的[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)就十分类似了。
+
+切割问题可以抽象为树型结构,如图:
-终止条件: 和[0131.分割回文串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0131.分割回文串.md) 不同,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
+
+## 回溯三部曲
+
+* 递归参数
+
+在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中我们就提到切割问题类似组合问题。
+
+startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
+
+本题我们还需要一个变量pointNum,记录添加逗点的数量。
+
+所以代码如下:
+
+```
+ vector result;// 记录结果
+ // startIndex: 搜索的起始位置,pointNum:添加逗点的数量
+ void backtracking(string& s, int startIndex, int pointNum) {
+```
+
+* 递归终止条件
+
+终止条件和[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
+
+pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
+
+然后验证一下第四段是否合法,如果合法就加入到结果集里
代码如下:
@@ -60,24 +88,40 @@ if (pointNum == 3) { // 逗点数量为3时,分隔结束
}
```
-那么再来看循环遍历的过程如何截取子串。
+* 单层搜索的逻辑
-在`for (int i = startIndex; i < s.size(); i++)`循环中 [startIndex, i]这个区间就是截取的子串,需要判断这个子串是否合法,如果合法就在字符串后面加上符号`.`表示已经分割。
+在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中已经讲过在循环遍历中如何截取子串。
+
+在`for (int i = startIndex; i < s.size(); i++)`循环中 [startIndex, i]这个区间就是截取的子串,需要判断这个子串是否合法。
+
+如果合法就在字符串后面加上符号`.`表示已经分割。
+
+如果不合法就结束本层循环,如图中剪掉的分支:
+
+
然后就是递归和回溯的过程:
-递归调用时,下一层递归的startIndex要从i+2开始(因为刚刚在字符串中加入了分隔符`.`),同时记录分割符的数量pointNum 要 +1。
+递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入了分隔符`.`),同时记录分割符的数量pointNum 要 +1。
-回溯的时候,就将刚刚加入的分隔符`.` 删掉就可以了,**pointNum其实也要减一,但是 pointNum+1 的逻辑放在递归函数的参数里了,这里相当于隐藏了回溯pointNum的过程**。
+回溯的时候,就将刚刚加入的分隔符`.` 删掉就可以了,pointNum也要-1。
-递归和回溯代码如下:
+代码如下:
```
-// 插入逗点之后下一个子串的起始位置为i+2
-backtracking(s, i + 2, pointNum + 1);
-s.erase(s.begin() + i + 1); // 回溯时删掉逗点
+for (int i = startIndex; i < s.size(); i++) {
+ if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的子串是否合法
+ s.insert(s.begin() + i + 1 , '.'); // 在i的后面插入一个逗点
+ pointNum++;
+ backtracking(s, i + 2, pointNum); // 插入逗点之后下一个子串的起始位置为i+2
+ pointNum--; // 回溯
+ s.erase(s.begin() + i + 1); // 回溯删掉逗点
+ } else break; // 不合法,直接结束本层循环
+}
```
+## 判断子串是否合法
+
最后就是在写一个判断段位是否是有效段位了。
主要考虑到如下三点:
@@ -111,9 +155,27 @@ bool isValid(const string& s, int start, int end) {
}
```
-关键代码已经讲完,整体代码如下:
+## C++代码
-## C++代码
+
+根据[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)给出的回溯算法模板:
+
+```
+void backtracking(参数) {
+ if (终止条件) {
+ 存放结果;
+ return;
+ }
+
+ for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
+ 处理节点;
+ backtracking(路径,选择列表); // 递归
+ 回溯,撤销处理结果
+ }
+}
+```
+
+可以写出如下回溯算法C++代码:
```
class Solution {
@@ -128,16 +190,14 @@ private:
}
return;
}
- // 从起始位置开始构造字段字符串串
for (int i = startIndex; i < s.size(); i++) {
- // 判断 [startIndex,i] 这个区间的子串是否合法
- if (isValid(s, startIndex, i)) {
- // 合法,在i的后面插入一个逗点
- s.insert(s.begin() + i + 1 , '.');
- // 插入逗点之后下一个子串的起始位置为i+2
- backtracking(s, i + 2, pointNum + 1);
- s.erase(s.begin() + i + 1); // 回溯时删掉逗点
- } else break;
+ if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的子串是否合法
+ s.insert(s.begin() + i + 1 , '.'); // 在i的后面插入一个逗点
+ pointNum++;
+ backtracking(s, i + 2, pointNum); // 插入逗点之后下一个子串的起始位置为i+2
+ pointNum--; // 回溯
+ s.erase(s.begin() + i + 1); // 回溯删掉逗点
+ } else break; // 不合法,直接结束本层循环
}
}
// 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法
@@ -167,6 +227,27 @@ public:
return result;
}
};
+
```
-> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。
+# 总结
+
+在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中我列举的分割字符串的难点,本题都覆盖了。
+
+而且本题还需要操作字符串添加逗号作为分隔符,并验证区间的合法性。
+
+可以说是[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)的加强版。
+
+在本文的树形结构图中,我已经把详细的分析思路都画了出来,相信大家看了之后一定会思路清晰不少!
+
+**就酱,「代码随想录」值得推荐给你的朋友们!**
+
+
+一些录友表示跟不上现在的节奏,想从头开始打卡学习起来,可以在在公众号左下方,「算法汇总」可以找到历史文章,都是按系列排好顺序的,挨个看就可以了,别忘了打卡。
+
+**很多录友都在从头开始打卡学习,看看前面文章的留言区就知道了,你并不孤单!**
+
+
+
+> 我是[程序员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),期待你的关注!
+
diff --git a/problems/0127.单词接龙.md b/problems/0127.单词接龙.md
new file mode 100644
index 00000000..575fc4c0
--- /dev/null
+++ b/problems/0127.单词接龙.md
@@ -0,0 +1,73 @@
+
+## 题目链接
+
+https://leetcode-cn.com/problems/word-ladder/
+
+## 思路
+
+以示例1为例,从这个图中可以看出 hit 到 cog的路线,不止一条,有三条,两条是最短的长度为5,一条长度为6。
+
+
+
+本题只需要求出最短长度就可以了,不用找出路径。
+
+所以这道题要解决两个问题:
+
+* 图中的线是如何连在一起的
+* 起点和终点的最短路径长度
+
+
+首先题目中并没有给出点与点之间的连线,而是要我们自己去连,条件是字符只能差一个,所以判断点与点之间的关系,要自己判断是不是差一个字符,如果差一个字符,那就是有链接。
+
+然后就是求起点和终点的最短路径长度,**这里无向图求最短路,广搜最为合适,广搜只要搜到了终点,那么一定是最短的路径**。因为广搜就是以起点中心向四周扩散的搜索。
+
+本题如果用深搜,会非常麻烦。
+
+另外需要有一个注意点:
+
+* 本题是一个无向图,需要用标记位,标记着节点是否走过,否则就会死循环!
+* 本题给出集合是数组型的,可以转成set结构,查找更快一些
+
+C++代码如下:(详细注释)
+
+```
+class Solution {
+public:
+ int ladderLength(string beginWord, string endWord, vector& wordList) {
+ // 将vector转成unordered_set,提高查询速度
+ unordered_set wordSet(wordList.begin(), wordList.end());
+ // 如果endWord没有在wordSet出现,直接返回0
+ if (wordSet.find(endWord) == wordSet.end()) return 0;
+ // 记录word是否访问过
+ unordered_map visitMap; //
+ // 初始化队列
+ queue que;
+ que.push(beginWord);
+ // 初始化visitMap
+ visitMap.insert(pair(beginWord, 1));
+
+ while(!que.empty()) {
+ string word = que.front();
+ que.pop();
+ int path = visitMap[word]; // 这个word的路径长度
+ for (int i = 0; i < word.size(); i++) {
+ string newWord = word; // 用一个新单词替换word,因为每次置换一个字母
+ for (int j = 0 ; j < 26; j++) {
+ newWord[i] = j + 'a';
+ if (newWord == endWord) return path + 1; // 找到了end,返回path+1
+ // wordSet出现了newWord,并且newWord没有被访问过
+ if (wordSet.find(newWord) != wordSet.end()
+ && visitMap.find(newWord) == visitMap.end()) {
+ // 添加访问信息
+ visitMap.insert(pair(newWord, path + 1));
+ que.push(newWord);
+ }
+ }
+ }
+ }
+ return 0;
+ }
+};
+```
+> 我是[程序员Carl](https://github.com/youngyangyang04),组队刷题可以找我,本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](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),期待你的关注!
+
diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md
new file mode 100644
index 00000000..b1d831f7
--- /dev/null
+++ b/problems/0455.分发饼干.md
@@ -0,0 +1,42 @@
+
+## 链接
+
+https://leetcode-cn.com/problems/assign-cookies/
+
+## 思路
+
+这道题目呢,其实可以用较大大的饼干优先满足可以满足的胃口大的小孩。
+
+注意我这里用的是 可以满足的胃口大的小孩。这样就不会造成大饼干的浪费。
+
+所以使用贪心策略,讲饼干数组和小孩数组排序。
+
+然后从后向前遍历小孩数组,用大饼干优先满足胃口大的,并统计满足小孩数量的大小就可以了。
+
+如图:
+
+
+
+
+C++代码整体如下:
+
+```
+class Solution {
+public:
+ int findContentChildren(vector& g, vector& s) {
+ sort(g.begin(), g.end());
+ sort(s.begin(), s.end());
+ int index = s.size() - 1; // 饼干数组的下表
+ int result = 0;
+ for (int i = g.size() - 1; i >= 0; i--) {
+ if (index >= 0 && s[index] >= g[i]) {
+ result++;
+ index--;
+ }
+ }
+ return result;
+ }
+};
+```
+> 我是[程序员Carl](https://github.com/youngyangyang04),组队刷题可以找我,本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](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),期待你的关注!
+