This commit is contained in:
youngyangyang04
2020-11-05 15:18:39 +08:00
parent 1c4ab0195a
commit 141cccbc33
7 changed files with 233 additions and 30 deletions

View File

@ -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) |深度优先搜索 |中等|**深度优先搜索/回溯算法**|

BIN
pics/127.单词接龙.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
pics/455.分发饼干.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -1,4 +1,8 @@
# 链接
https://leetcode-cn.com/problems/insert-interval/
# 思路
这道题目合并的情况有很多种,想想都让人头疼。
我把这道题目化为三步:

View File

@ -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)就十分类似了。
切割问题可以抽象为树型结构,如图:
<img src='../pics/93.复原IP地址.png' width=600> </img></div>
终止条件: 和[0131.分割回文串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0131.分割回文串.md) 不同本题明确要求只会分成4段所以不能用切割线切到最后作为终止条件而是分割的段数作为终止条件。
## 回溯三部曲
* 递归参数
在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中我们就提到切割问题类似组合问题。
startIndex一定是需要的因为不能重复分割记录下一层递归分割的起始位置。
本题我们还需要一个变量pointNum记录添加逗点的数量。
所以代码如下:
```
vector<string> 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]这个区间就是截取的子串,需要判断这个子串是否合法。
如果合法就在字符串后面加上符号`.`表示已经分割。
如果不合法就结束本层循环,如图中剪掉的分支:
<img src='../pics/93.复原IP地址.png' width=600> </img></div>
然后就是递归和回溯的过程:
递归调用时下一层递归的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),期待你的关注!

View File

@ -0,0 +1,73 @@
## 题目链接
https://leetcode-cn.com/problems/word-ladder/
## 思路
以示例1为例从这个图中可以看出 hit 到 cog的路线不止一条有三条两条是最短的长度为5一条长度为6。
<img src='../pics/127.单词接龙.png' width=600> </img></div>
本题只需要求出最短长度就可以了,不用找出路径。
所以这道题要解决两个问题:
* 图中的线是如何连在一起的
* 起点和终点的最短路径长度
首先题目中并没有给出点与点之间的连线,而是要我们自己去连,条件是字符只能差一个,所以判断点与点之间的关系,要自己判断是不是差一个字符,如果差一个字符,那就是有链接。
然后就是求起点和终点的最短路径长度,**这里无向图求最短路,广搜最为合适,广搜只要搜到了终点,那么一定是最短的路径**。因为广搜就是以起点中心向四周扩散的搜索。
本题如果用深搜,会非常麻烦。
另外需要有一个注意点:
* 本题是一个无向图,需要用标记位,标记着节点是否走过,否则就会死循环!
* 本题给出集合是数组型的可以转成set结构查找更快一些
C++代码如下:(详细注释)
```
class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
// 将vector转成unordered_set提高查询速度
unordered_set<string> wordSet(wordList.begin(), wordList.end());
// 如果endWord没有在wordSet出现直接返回0
if (wordSet.find(endWord) == wordSet.end()) return 0;
// 记录word是否访问过
unordered_map<string, int> visitMap; // <word, 查询到这个word路径长度>
// 初始化队列
queue<string> que;
que.push(beginWord);
// 初始化visitMap
visitMap.insert(pair<string, int>(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<string, int>(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),期待你的关注!

View File

@ -0,0 +1,42 @@
## 链接
https://leetcode-cn.com/problems/assign-cookies/
## 思路
这道题目呢,其实可以用较大大的饼干优先满足可以满足的胃口大的小孩。
注意我这里用的是 可以满足的胃口大的小孩。这样就不会造成大饼干的浪费。
所以使用贪心策略,讲饼干数组和小孩数组排序。
然后从后向前遍历小孩数组,用大饼干优先满足胃口大的,并统计满足小孩数量的大小就可以了。
如图:
<img src='../pics/455.分发饼干.png' width=600> </img></div>
C++代码整体如下:
```
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& 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),期待你的关注!