mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-06 15:09:40 +08:00
Update
This commit is contained in:
@ -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
BIN
pics/127.单词接龙.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
BIN
pics/455.分发饼干.png
Normal file
BIN
pics/455.分发饼干.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
@ -1,4 +1,8 @@
|
||||
|
||||
# 链接
|
||||
https://leetcode-cn.com/problems/insert-interval/
|
||||
|
||||
# 思路
|
||||
这道题目合并的情况有很多种,想想都让人头疼。
|
||||
|
||||
我把这道题目化为三步:
|
||||
|
@ -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),期待你的关注!
|
||||
|
||||
|
73
problems/0127.单词接龙.md
Normal file
73
problems/0127.单词接龙.md
Normal 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),期待你的关注!
|
||||
|
42
problems/0455.分发饼干.md
Normal file
42
problems/0455.分发饼干.md
Normal 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),期待你的关注!
|
||||
|
Reference in New Issue
Block a user