mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-06 23:28:29 +08:00
Update
This commit is contained in:
30
README.md
30
README.md
@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
**这里每一篇题解,都是精品,值得仔细琢磨**。
|
**这里每一篇题解,都是精品,值得仔细琢磨**。
|
||||||
|
|
||||||
我在题目讲解中统一用C++语言,但你会发现下面几乎每篇题解都配有其他语言版本,Java、Python、Go、JavaScript等等,这正是热心小伙们的贡献的代码,当然我也会严格把控代码质量。
|
我在题目讲解中统一使用C++,但你会发现下面几乎每篇题解都配有其他语言版本,Java、Python、Go、JavaScript等等,正是这些[热心小伙们](https://github.com/youngyangyang04/leetcode-master/graphs/contributors)的贡献的代码,当然我也会严格把控代码质量。
|
||||||
|
|
||||||
**所以也欢迎大家参与进来,完善题解的各个语言版本,拥抱开源,让更多小伙伴们收益**。
|
**所以也欢迎大家参与进来,完善题解的各个语言版本,拥抱开源,让更多小伙伴们收益**。
|
||||||
|
|
||||||
@ -133,6 +133,13 @@
|
|||||||
9. [秋招和提前批都越来越提前了....](https://mp.weixin.qq.com/s/SNFiRDx8CKyjhTPlys6ywQ)
|
9. [秋招和提前批都越来越提前了....](https://mp.weixin.qq.com/s/SNFiRDx8CKyjhTPlys6ywQ)
|
||||||
10. [你的简历里「专业技能」写的够专业么?](https://mp.weixin.qq.com/s/bp6y-e5FVN28H9qc8J9zrg)
|
10. [你的简历里「专业技能」写的够专业么?](https://mp.weixin.qq.com/s/bp6y-e5FVN28H9qc8J9zrg)
|
||||||
11. [对于秋招,实习生也有烦恼....](https://mp.weixin.qq.com/s/ka07IPryFnfmIjByFFcXDg)
|
11. [对于秋招,实习生也有烦恼....](https://mp.weixin.qq.com/s/ka07IPryFnfmIjByFFcXDg)
|
||||||
|
12. [华为提前批已经开始了.....](https://mp.weixin.qq.com/s/OC35QDG8pn5OwLpCxieStw)
|
||||||
|
13. [大厂新人培养体系应该是什么样的?](https://mp.weixin.qq.com/s/WBaPCosOljB5NEkFL2GhOQ)
|
||||||
|
|
||||||
|
## 杂谈
|
||||||
|
|
||||||
|
[大半年过去了......](https://mp.weixin.qq.com/s/lubfeistPxBLSQIe5XYg5g)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 数组
|
## 数组
|
||||||
@ -161,14 +168,15 @@
|
|||||||
|
|
||||||
1. [关于哈希表,你该了解这些!](./problems/哈希表理论基础.md)
|
1. [关于哈希表,你该了解这些!](./problems/哈希表理论基础.md)
|
||||||
2. [哈希表:可以拿数组当哈希表来用,但哈希值不要太大](./problems/0242.有效的字母异位词.md)
|
2. [哈希表:可以拿数组当哈希表来用,但哈希值不要太大](./problems/0242.有效的字母异位词.md)
|
||||||
3. [哈希表:哈希值太大了,还是得用set](./problems/0349.两个数组的交集.md)
|
3. [哈希表:查找常用字符](./problems/1002.查找常用字符.md)
|
||||||
4. [哈希表:用set来判断快乐数](./problems/0202.快乐数.md)
|
4. [哈希表:哈希值太大了,还是得用set](./problems/0349.两个数组的交集.md)
|
||||||
5. [哈希表:map等候多时了](./problems/0001.两数之和.md)
|
5. [哈希表:用set来判断快乐数](./problems/0202.快乐数.md)
|
||||||
6. [哈希表:其实需要哈希的地方都能找到map的身影](./problems/0454.四数相加II.md)
|
6. [哈希表:map等候多时了](./problems/0001.两数之和.md)
|
||||||
7. [哈希表:这道题目我做过?](./problems/0383.赎金信.md)
|
7. [哈希表:其实需要哈希的地方都能找到map的身影](./problems/0454.四数相加II.md)
|
||||||
8. [哈希表:解决了两数之和,那么能解决三数之和么?](./problems/0015.三数之和.md)
|
8. [哈希表:这道题目我做过?](./problems/0383.赎金信.md)
|
||||||
9. [双指针法:一样的道理,能解决四数之和](./problems/0018.四数之和.md)
|
9. [哈希表:解决了两数之和,那么能解决三数之和么?](./problems/0015.三数之和.md)
|
||||||
10. [哈希表:总结篇!(每逢总结必经典)](./problems/哈希表总结.md)
|
10. [双指针法:一样的道理,能解决四数之和](./problems/0018.四数之和.md)
|
||||||
|
11. [哈希表:总结篇!(每逢总结必经典)](./problems/哈希表总结.md)
|
||||||
|
|
||||||
|
|
||||||
## 字符串
|
## 字符串
|
||||||
@ -444,7 +452,7 @@
|
|||||||
|
|
||||||
# 贡献者
|
# 贡献者
|
||||||
|
|
||||||
你可以[点此链接](https://github.com/youngyangyang04/leetcode-master/graphs/contributors)查看LeetCode-Master的所有贡献者。感谢你们补充了LeetCode-Master的其他语言版本,让更多的读者收益于此项目。
|
[点此这里](https://github.com/youngyangyang04/leetcode-master/graphs/contributors)查看LeetCode-Master的所有贡献者。感谢他们补充了LeetCode-Master的其他语言版本,让更多的读者收益于此项目。
|
||||||
|
|
||||||
# 关于作者
|
# 关于作者
|
||||||
|
|
||||||
@ -459,7 +467,7 @@
|
|||||||
|
|
||||||
# 公众号
|
# 公众号
|
||||||
|
|
||||||
更多精彩文章持续更新,微信搜索:「代码随想录」第一时间围观,关注后回复:「666」可以获得所有算法专题原创PDF。
|
更多精彩文章持续更新,微信搜索:「代码随想录」第一时间围观,关注后回复:666,可以获得我的所有算法专题原创PDF。
|
||||||
|
|
||||||
**「代码随想录」每天准时为你推送一篇经典面试题目,帮你梳理算法知识体系,轻松学习算法!**,并且公众号里有大量学习资源,也有我自己的学习心得和方法总结,更有上万录友们在这里打卡学习。
|
**「代码随想录」每天准时为你推送一篇经典面试题目,帮你梳理算法知识体系,轻松学习算法!**,并且公众号里有大量学习资源,也有我自己的学习心得和方法总结,更有上万录友们在这里打卡学习。
|
||||||
|
|
||||||
|
@ -651,7 +651,7 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python3:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
// 方法一
|
// 方法一
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
|
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||||
|
</p>
|
||||||
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
> 这个图就是大厂面试经典题目,接雨水! 最常青藤的一道题,面试官百出不厌!
|
||||||
|
|
||||||
# 42. 接雨水
|
# 42. 接雨水
|
||||||
|
|
||||||
@ -355,3 +364,9 @@ public:
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
||||||
|
@ -148,8 +148,6 @@ class Solution {
|
|||||||
|
|
||||||
// 定义中间位置
|
// 定义中间位置
|
||||||
int mid = n / 2;
|
int mid = n / 2;
|
||||||
|
|
||||||
|
|
||||||
while (loop > 0) {
|
while (loop > 0) {
|
||||||
int i = startX;
|
int i = startX;
|
||||||
int j = startY;
|
int j = startY;
|
||||||
@ -182,7 +180,6 @@ class Solution {
|
|||||||
offset += 2;
|
offset += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (n % 2 == 1) {
|
if (n % 2 == 1) {
|
||||||
res[mid][mid] = count;
|
res[mid][mid] = count;
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,10 @@
|
|||||||
|
|
||||||
我们之前讲过了三篇关于二叉树的深度优先遍历的文章:
|
我们之前讲过了三篇关于二叉树的深度优先遍历的文章:
|
||||||
|
|
||||||
* [二叉树:前中后序递归法](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)
|
* [二叉树:前中后序递归法](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)
|
||||||
* [二叉树:前中后序迭代法](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)
|
* [二叉树:前中后序迭代法](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)
|
||||||
* [二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)
|
* [二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)
|
||||||
|
|
||||||
|
|
||||||
接下来我们再来介绍二叉树的另一种遍历方式:层序遍历。
|
接下来我们再来介绍二叉树的另一种遍历方式:层序遍历。
|
||||||
|
|
||||||
|
179
problems/0129.求根到叶子节点数字之和.md
Normal file
179
problems/0129.求根到叶子节点数字之和.md
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
|
||||||
|
## 链接
|
||||||
|
https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/
|
||||||
|
|
||||||
|
## 思路
|
||||||
|
|
||||||
|
本题和[113.路径总和II](https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0113.%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8CII.md)是类似的思路,做完这道题,可以顺便把[113.路径总和II](https://github.com/youngyangyang04/leetcode-master/blob/master/problems/0113.%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8CII.md) 和 [112.路径总和](https://github.com/youngyangyang04/leetcode/blob/master/problems/0112.路径总和.md) 做了。
|
||||||
|
|
||||||
|
结合112.路径总和 和 113.路径总和II,我在讲了[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg),如果大家对二叉树递归函数什么时候需要返回值很迷茫,可以看一下。
|
||||||
|
|
||||||
|
接下来在看本题,就简单多了,本题其实需要使用回溯,但一些同学可能都不知道自己用了回溯,在[二叉树:以为使用了递归,其实还隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA)中,我详细讲解了二叉树的递归中,如何使用了回溯。
|
||||||
|
|
||||||
|
接下来我们来看题:
|
||||||
|
|
||||||
|
首先思路很明确,就是要遍历整个树把更节点到叶子节点组成的数字相加。
|
||||||
|
|
||||||
|
那么先按递归三部曲来分析:
|
||||||
|
|
||||||
|
### 递归三部曲
|
||||||
|
|
||||||
|
如果对递归三部曲不了解的话,可以看这里:[二叉树:前中后递归详解](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)
|
||||||
|
|
||||||
|
* 确定递归函数返回值及其参数
|
||||||
|
|
||||||
|
这里我们要遍历整个二叉树,且需要要返回值做逻辑处理,所有返回值为void,在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中,详细讲解了返回值问题。
|
||||||
|
|
||||||
|
参数只需要把根节点传入,此时还需要定义两个全局遍历,一个是result,记录最终结果,一个是vector<int> path。
|
||||||
|
|
||||||
|
**为什么用vector类型(就是数组)呢? 因为用vector方便我们做回溯!**
|
||||||
|
|
||||||
|
所以代码如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
int result;
|
||||||
|
vector<int> path;
|
||||||
|
void traversal(TreeNode* cur)
|
||||||
|
```
|
||||||
|
|
||||||
|
* 确定终止条件
|
||||||
|
|
||||||
|
递归什么时候终止呢?
|
||||||
|
|
||||||
|
当然是遇到叶子节点,此时要收集结果了,通知返回本层递归,因为单条路径的结果使用vector,我们需要一个函数vectorToInt把vector转成int。
|
||||||
|
|
||||||
|
终止条件代码如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
if (!cur->left && !cur->right) { // 遇到了叶子节点
|
||||||
|
result += vectorToInt(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这里vectorToInt函数就是把数组转成int,代码如下:
|
||||||
|
|
||||||
|
```C++
|
||||||
|
int vectorToInt(const vector<int>& vec) {
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < vec.size(); i++) {
|
||||||
|
sum = sum * 10 + vec[i];
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
* 确定递归单层逻辑
|
||||||
|
|
||||||
|
本题其实采用前中后序都不无所谓, 因为也没有中间几点的处理逻辑。
|
||||||
|
|
||||||
|
这里主要是当左节点不为空,path收集路径,并递归左孩子,右节点同理。
|
||||||
|
|
||||||
|
**但别忘了回溯**。
|
||||||
|
|
||||||
|
如图:
|
||||||
|
|
||||||
|
|
||||||
|
<img src='https://code-thinking.cdn.bcebos.com/pics/129.求根到叶子节点数字之和.png' width=600> </img></div>
|
||||||
|
|
||||||
|
代码如下:
|
||||||
|
|
||||||
|
```C++
|
||||||
|
// 中
|
||||||
|
if (cur->left) { // 左 (空节点不遍历)
|
||||||
|
path.push_back(cur->left->val);
|
||||||
|
traversal(cur->left); // 递归
|
||||||
|
path.pop_back(); // 回溯
|
||||||
|
}
|
||||||
|
if (cur->right) { // 右 (空节点不遍历)
|
||||||
|
path.push_back(cur->right->val);
|
||||||
|
traversal(cur->right); // 递归
|
||||||
|
path.pop_back(); // 回溯
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这里要注意回溯和递归要永远在一起,一个递归,对应一个回溯,是一对一的关系,有的同学写成如下代码:
|
||||||
|
|
||||||
|
```C++
|
||||||
|
if (cur->left) { // 左 (空节点不遍历)
|
||||||
|
path.push_back(cur->left->val);
|
||||||
|
traversal(cur->left); // 递归
|
||||||
|
}
|
||||||
|
if (cur->right) { // 右 (空节点不遍历)
|
||||||
|
path.push_back(cur->right->val);
|
||||||
|
traversal(cur->right); // 递归
|
||||||
|
}
|
||||||
|
path.pop_back(); // 回溯
|
||||||
|
```
|
||||||
|
**把回溯放在花括号外面了,世界上最遥远的距离,是你在花括号里,而我在花括号外!** 这就不对了。
|
||||||
|
|
||||||
|
### 整体C++代码
|
||||||
|
|
||||||
|
关键逻辑分析完了,整体C++代码如下:
|
||||||
|
|
||||||
|
```C++
|
||||||
|
class Solution {
|
||||||
|
private:
|
||||||
|
int result;
|
||||||
|
vector<int> path;
|
||||||
|
// 把vector转化为int
|
||||||
|
int vectorToInt(const vector<int>& vec) {
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < vec.size(); i++) {
|
||||||
|
sum = sum * 10 + vec[i];
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
void traversal(TreeNode* cur) {
|
||||||
|
if (!cur->left && !cur->right) { // 遇到了叶子节点
|
||||||
|
result += vectorToInt(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur->left) { // 左 (空节点不遍历)
|
||||||
|
path.push_back(cur->left->val); // 处理节点
|
||||||
|
traversal(cur->left); // 递归
|
||||||
|
path.pop_back(); // 回溯,撤销
|
||||||
|
}
|
||||||
|
if (cur->right) { // 右 (空节点不遍历)
|
||||||
|
path.push_back(cur->right->val); // 处理节点
|
||||||
|
traversal(cur->right); // 递归
|
||||||
|
path.pop_back(); // 回溯,撤销
|
||||||
|
}
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
int sumNumbers(TreeNode* root) {
|
||||||
|
path.clear();
|
||||||
|
if (root == nullptr) return 0;
|
||||||
|
path.push_back(root->val);
|
||||||
|
traversal(root);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
过于简洁的代码,很容易让初学者忽视了本题中回溯的精髓,甚至作者本身都没有想清楚自己用了回溯。
|
||||||
|
|
||||||
|
**我这里提供的代码把整个回溯过程充分体现出来,希望可以帮助大家看的明明白白!**
|
||||||
|
|
||||||
|
## 其他语言版本
|
||||||
|
|
||||||
|
Java:
|
||||||
|
|
||||||
|
Python:
|
||||||
|
|
||||||
|
Go:
|
||||||
|
|
||||||
|
JavaScript:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
@ -300,8 +300,9 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
python:
|
||||||
|
|
||||||
```Python3
|
```Python
|
||||||
class Solution:
|
class Solution:
|
||||||
#1.去除多余的空格
|
#1.去除多余的空格
|
||||||
def trim_spaces(self,s):
|
def trim_spaces(self,s):
|
||||||
@ -349,7 +350,7 @@ class Solution:
|
|||||||
return ''.join(l) #输出:blue is sky the
|
return ''.join(l) #输出:blue is sky the
|
||||||
|
|
||||||
|
|
||||||
'''
|
```
|
||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
@ -200,14 +200,6 @@ class MyStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Your MyQueue object will be instantiated and called as such:
|
|
||||||
* MyQueue obj = new MyQueue();
|
|
||||||
* obj.push(x);
|
|
||||||
* int param_2 = obj.pop();
|
|
||||||
* int param_3 = obj.peek();
|
|
||||||
* boolean param_4 = obj.empty();
|
|
||||||
*/
|
|
||||||
```
|
```
|
||||||
使用两个 Deque 实现
|
使用两个 Deque 实现
|
||||||
```java
|
```java
|
||||||
@ -350,12 +342,6 @@ class MyStack:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
# Your MyStack object will be instantiated and called as such:
|
|
||||||
# obj = MyStack()
|
|
||||||
# obj.push(x)
|
|
||||||
# param_2 = obj.pop()
|
|
||||||
# param_3 = obj.top()
|
|
||||||
# param_4 = obj.empty()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
## 226.翻转二叉树
|
# 226.翻转二叉树
|
||||||
|
|
||||||
题目地址:https://leetcode-cn.com/problems/invert-binary-tree/
|
题目地址:https://leetcode-cn.com/problems/invert-binary-tree/
|
||||||
|
|
||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树,最后被Google拒绝了。(真假不做判断,权当一个乐子哈)
|
这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树,最后被Google拒绝了。(真假不做判断,权当一个乐子哈)
|
||||||
|
|
||||||
## 题外话
|
# 题外话
|
||||||
|
|
||||||
这道题目是非常经典的题目,也是比较简单的题目(至少一看就会)。
|
这道题目是非常经典的题目,也是比较简单的题目(至少一看就会)。
|
||||||
|
|
||||||
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
如果做过这道题的同学也建议认真看完,相信一定有所收获!
|
如果做过这道题的同学也建议认真看完,相信一定有所收获!
|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
我们之前介绍的都是各种方式遍历二叉树,这次要翻转了,感觉还是有点懵逼。
|
我们之前介绍的都是各种方式遍历二叉树,这次要翻转了,感觉还是有点懵逼。
|
||||||
|
|
||||||
@ -49,7 +49,9 @@
|
|||||||
|
|
||||||
## 递归法
|
## 递归法
|
||||||
|
|
||||||
对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)详细讲解了。
|
|
||||||
|
|
||||||
|
对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)详细讲解了。
|
||||||
|
|
||||||
我们下文以前序遍历为例,通过动画来看一下翻转的过程:
|
我们下文以前序遍历为例,通过动画来看一下翻转的过程:
|
||||||
|
|
||||||
@ -104,7 +106,8 @@ public:
|
|||||||
|
|
||||||
### 深度优先遍历
|
### 深度优先遍历
|
||||||
|
|
||||||
[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)中给出了前中后序迭代方式的写法,所以本地可以很轻松的切出如下迭代法的代码:
|
|
||||||
|
[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)中给出了前中后序迭代方式的写法,所以本地可以很轻松的切出如下迭代法的代码:
|
||||||
|
|
||||||
C++代码迭代法(前序遍历)
|
C++代码迭代法(前序遍历)
|
||||||
|
|
||||||
@ -126,10 +129,10 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
如果这个代码看不懂的话可以在回顾一下[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)。
|
如果这个代码看不懂的话可以在回顾一下[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)。
|
||||||
|
|
||||||
|
|
||||||
我们在[二叉树:前中后序迭代方式的统一写法](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)中介绍了统一的写法,所以,本题也只需将文中的代码少做修改便可。
|
我们在[二叉树:前中后序迭代方式的统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)中介绍了统一的写法,所以,本题也只需将文中的代码少做修改便可。
|
||||||
|
|
||||||
C++代码如下迭代法(前序遍历)
|
C++代码如下迭代法(前序遍历)
|
||||||
|
|
||||||
@ -159,7 +162,7 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
如果上面这个代码看不懂,回顾一下文章[二叉树:前中后序迭代方式的统一写法](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)。
|
如果上面这个代码看不懂,回顾一下文章[二叉树:前中后序迭代方式的统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)。
|
||||||
|
|
||||||
### 广度优先遍历
|
### 广度优先遍历
|
||||||
|
|
||||||
@ -185,7 +188,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
如果对以上代码不理解,或者不清楚二叉树的层序遍历,可以看这篇[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)
|
如果对以上代码不理解,或者不清楚二叉树的层序遍历,可以看这篇[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
@ -202,7 +205,7 @@ public:
|
|||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
### Java:
|
||||||
|
|
||||||
```Java
|
```Java
|
||||||
//DFS递归
|
//DFS递归
|
||||||
@ -254,9 +257,9 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
### Python
|
||||||
|
|
||||||
> 递归法:前序遍历
|
递归法:前序遍历:
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def invertTree(self, root: TreeNode) -> TreeNode:
|
def invertTree(self, root: TreeNode) -> TreeNode:
|
||||||
@ -268,7 +271,7 @@ class Solution:
|
|||||||
return root
|
return root
|
||||||
```
|
```
|
||||||
|
|
||||||
> 迭代法:深度优先遍历(前序遍历)
|
迭代法:深度优先遍历(前序遍历):
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def invertTree(self, root: TreeNode) -> TreeNode:
|
def invertTree(self, root: TreeNode) -> TreeNode:
|
||||||
@ -286,7 +289,7 @@ class Solution:
|
|||||||
return root
|
return root
|
||||||
```
|
```
|
||||||
|
|
||||||
> 迭代法:广度优先遍历(层序遍历)
|
迭代法:广度优先遍历(层序遍历):
|
||||||
```python
|
```python
|
||||||
import collections
|
import collections
|
||||||
class Solution:
|
class Solution:
|
||||||
@ -306,7 +309,8 @@ class Solution:
|
|||||||
return root
|
return root
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
### Go
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
func invertTree(root *TreeNode) *TreeNode {
|
func invertTree(root *TreeNode) *TreeNode {
|
||||||
if root ==nil{
|
if root ==nil{
|
||||||
@ -323,7 +327,7 @@ func invertTree(root *TreeNode) *TreeNode {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
JavaScript:
|
### JavaScript
|
||||||
|
|
||||||
使用递归版本的前序遍历
|
使用递归版本的前序遍历
|
||||||
```javascript
|
```javascript
|
||||||
|
@ -385,15 +385,6 @@ func (this *MyQueue) Empty() bool {
|
|||||||
return len(this.stack) == 0 && len(this.back) == 0
|
return len(this.stack) == 0 && len(this.back) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Your MyQueue object will be instantiated and called as such:
|
|
||||||
* obj := Constructor();
|
|
||||||
* obj.Push(x);
|
|
||||||
* param_2 := obj.Pop();
|
|
||||||
* param_3 := obj.Peek();
|
|
||||||
* param_4 := obj.Empty();
|
|
||||||
*/
|
|
||||||
```
|
|
||||||
|
|
||||||
javaScript:
|
javaScript:
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ https://leetcode-cn.com/problems/repeated-substring-pattern/
|
|||||||
|
|
||||||
如果KMP还不够了解,可以看我的B站:
|
如果KMP还不够了解,可以看我的B站:
|
||||||
|
|
||||||
* [帮你把KMP算法学个通透!B站(理论篇)](https://www.bilibili.com/video/BV1PD4y1o7nd/)
|
* [帮你把KMP算法学个通透!(理论篇)](https://www.bilibili.com/video/BV1PD4y1o7nd/)
|
||||||
* [帮你把KMP算法学个通透!(求next数组代码篇)](https://www.bilibili.com/video/BV1M5411j7Xx)
|
* [帮你把KMP算法学个通透!(求next数组代码篇)](https://www.bilibili.com/video/BV1M5411j7Xx)
|
||||||
|
|
||||||
|
|
||||||
|
98
problems/0463.岛屿的周长.md
Normal file
98
problems/0463.岛屿的周长.md
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
|
||||||
|
## 题目链接
|
||||||
|
https://leetcode-cn.com/problems/island-perimeter/
|
||||||
|
|
||||||
|
## 思路
|
||||||
|
|
||||||
|
岛屿问题最容易让人想到BFS或者DFS,但是这道题还真的没有必要,别把简单问题搞复杂了。
|
||||||
|
|
||||||
|
### 解法一:
|
||||||
|
|
||||||
|
遍历每一个空格,遇到岛屿,计算其上下左右的情况,遇到水域或者出界的情况,就可以计算边了。
|
||||||
|
|
||||||
|
如图:
|
||||||
|
|
||||||
|
<img src='https://code-thinking.cdn.bcebos.com/pics/463.岛屿的周长.png' width=600> </img></div>
|
||||||
|
|
||||||
|
C++代码如下:(详细注释)
|
||||||
|
|
||||||
|
```C++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int direction[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
|
||||||
|
int islandPerimeter(vector<vector<int>>& grid) {
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; i < grid.size(); i++) {
|
||||||
|
for (int j = 0; j < grid[0].size(); j++) {
|
||||||
|
if (grid[i][j] == 1) {
|
||||||
|
for (int k = 0; k < 4; k++) { // 上下左右四个方向
|
||||||
|
int x = i + direction[k][0];
|
||||||
|
int y = j + direction[k][1]; // 计算周边坐标x,y
|
||||||
|
if (x < 0 // i在边界上
|
||||||
|
|| x >= grid.size() // i在边界上
|
||||||
|
|| y < 0 // j在边界上
|
||||||
|
|| y >= grid[0].size() // j在边界上
|
||||||
|
|| grid[x][y] == 0) { // x,y位置是水域
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 解法二:
|
||||||
|
|
||||||
|
计算出总的岛屿数量,因为有一对相邻两个陆地,边的总数就减2,那么在计算出相邻岛屿的数量就可以了。
|
||||||
|
|
||||||
|
result = 岛屿数量 * 4 - cover * 2;
|
||||||
|
|
||||||
|
如图:
|
||||||
|
|
||||||
|
<img src='https://code-thinking.cdn.bcebos.com/pics/463.岛屿的周长1.png' width=600> </img></div>
|
||||||
|
|
||||||
|
C++代码如下:(详细注释)
|
||||||
|
|
||||||
|
```C++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int islandPerimeter(vector<vector<int>>& grid) {
|
||||||
|
int sum = 0; // 陆地数量
|
||||||
|
int cover = 0; // 相邻数量
|
||||||
|
for (int i = 0; i < grid.size(); i++) {
|
||||||
|
for (int j = 0; j < grid[0].size(); j++) {
|
||||||
|
if (grid[i][j] == 1) {
|
||||||
|
sum++;
|
||||||
|
// 统计上边相邻陆地
|
||||||
|
if(i - 1 >= 0 && grid[i - 1][j] == 1) cover++;
|
||||||
|
// 统计左边相邻陆地
|
||||||
|
if(j - 1 >= 0 && grid[i][j - 1] == 1) cover++;
|
||||||
|
// 为什么没统计下边和右边? 因为避免重复计算
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum * 4 - cover * 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 其他语言版本
|
||||||
|
|
||||||
|
Java:
|
||||||
|
|
||||||
|
Python:
|
||||||
|
|
||||||
|
Go:
|
||||||
|
|
||||||
|
JavaScript:
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
@ -139,7 +139,7 @@ public:
|
|||||||
|
|
||||||
## 相关题目推荐
|
## 相关题目推荐
|
||||||
|
|
||||||
* [35.搜索插入位置](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)
|
* [35.搜索插入位置](./0035.搜索插入位置.md)
|
||||||
* 34.在排序数组中查找元素的第一个和最后一个位置
|
* 34.在排序数组中查找元素的第一个和最后一个位置
|
||||||
* 69.x 的平方根
|
* 69.x 的平方根
|
||||||
* 367.有效的完全平方数
|
* 367.有效的完全平方数
|
||||||
|
@ -28,9 +28,9 @@ https://leetcode-cn.com/problems/design-linked-list/
|
|||||||
|
|
||||||
# 思路
|
# 思路
|
||||||
|
|
||||||
如果对链表的基础知识还不太懂,可以看这篇文章:[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/ntlZbEdKgnFQKZkSUAOSpQ)
|
如果对链表的基础知识还不太懂,可以看这篇文章:[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw)
|
||||||
|
|
||||||
如果对链表的虚拟头结点不清楚,可以看这篇文章:[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/slM1CH5Ew9XzK93YOQYSjA)
|
如果对链表的虚拟头结点不清楚,可以看这篇文章:[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)
|
||||||
|
|
||||||
删除链表节点:
|
删除链表节点:
|
||||||

|

|
||||||
|
43
problems/0941.有效的山脉数组.md
Normal file
43
problems/0941.有效的山脉数组.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
## 题目链接
|
||||||
|
|
||||||
|
https://leetcode-cn.com/problems/valid-mountain-array/
|
||||||
|
|
||||||
|
## 思路
|
||||||
|
|
||||||
|
判断是山峰,主要就是要严格的保存左边到中间,和右边到中间是递增的。
|
||||||
|
|
||||||
|
这样可以使用两个指针,left和right,让其按照如下规则移动,如图:
|
||||||
|
|
||||||
|
<img src='https://code-thinking.cdn.bcebos.com/pics/941.有效的山脉数组.png' width=600> </img></div>
|
||||||
|
|
||||||
|
**注意这里还是有一些细节,例如如下两点:**
|
||||||
|
|
||||||
|
* 因为left和right是数组下表,移动的过程中注意不要数组越界
|
||||||
|
* 如果left或者right没有移动,说明是一个单调递增或者递减的数组,依然不是山峰
|
||||||
|
|
||||||
|
C++代码如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
bool validMountainArray(vector<int>& A) {
|
||||||
|
if (A.size() < 3) return false;
|
||||||
|
int left = 0;
|
||||||
|
int right = A.size() - 1;
|
||||||
|
|
||||||
|
// 注意防止越界
|
||||||
|
while (left < A.size() - 1 && A[left] < A[left + 1]) left++;
|
||||||
|
|
||||||
|
// 注意防止越界
|
||||||
|
while (right > 0 && A[right] < A[right - 1]) right--;
|
||||||
|
|
||||||
|
// 如果left或者right都在起始位置,说明不是山峰
|
||||||
|
if (left == right && left != 0 && right != A.size() - 1) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
如果想系统学一学双指针的话, 可以看一下这篇[双指针法:总结篇!](https://mp.weixin.qq.com/s/_p7grwjISfMh0U65uOyCjA)
|
||||||
|
|
||||||
|
|
177
problems/1002.查找常用字符.md
Normal file
177
problems/1002.查找常用字符.md
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
|
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||||
|
</p>
|
||||||
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
|
# 1002. 查找常用字符
|
||||||
|
|
||||||
|
https://leetcode-cn.com/problems/find-common-characters/
|
||||||
|
|
||||||
|
给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。
|
||||||
|
|
||||||
|
你可以按任意顺序返回答案。
|
||||||
|
|
||||||
|
【示例一】
|
||||||
|
输入:["bella","label","roller"]
|
||||||
|
输出:["e","l","l"]
|
||||||
|
|
||||||
|
【示例二】
|
||||||
|
输入:["cool","lock","cook"]
|
||||||
|
输出:["c","o"]
|
||||||
|
|
||||||
|
|
||||||
|
# 思路
|
||||||
|
|
||||||
|
这道题意一起就有点绕,不是那么容易懂,其实就是26个小写字符中有字符 在所有字符串里都出现的话,就输出,重复的也算。
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
输入:["ll","ll","ll"]
|
||||||
|
输出:["l","l"]
|
||||||
|
|
||||||
|
这道题目一眼看上去,就是用哈希法,**“小写字符”,“出现频率”, 这些关键字都是为哈希法量身定做的啊**
|
||||||
|
|
||||||
|
首先可以想到的是暴力解法,一个字符串一个字符串去搜,时间复杂度是O(n^m),n是字符串长度,m是有几个字符串。
|
||||||
|
|
||||||
|
可以看出这是指数级别的时间复杂度,非常高,而且代码实现也不容易,因为要统计 重复的字符,还要适当的替换或者去重。
|
||||||
|
|
||||||
|
那我们还是哈希法吧。如果对哈希法不了解,可以看这篇:[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)。
|
||||||
|
|
||||||
|
如果对用数组来做哈希法不了解的话,可以看这篇:[把数组当做哈希表来用,很巧妙!](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)。
|
||||||
|
|
||||||
|
了解了哈希法,理解了数组在哈希法中的应用之后,可以来看解题思路了。
|
||||||
|
|
||||||
|
整体思路就是统计出搜索字符串里26个字符的出现的频率,然后取每个字符频率最小值,最后转成输出格式就可以了。
|
||||||
|
|
||||||
|
如图:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
先统计第一个字符串所有字符出现的次数,代码如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
int hash[26] = {0}; // 用来统计所有字符串里字符出现的最小频率
|
||||||
|
for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
|
||||||
|
hash[A[0][i] - 'a']++;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
接下来,把其他字符串里字符的出现次数也统计出来一次放在hashOtherStr中。
|
||||||
|
|
||||||
|
然后hash 和 hashOtherStr 取最小值,这是本题关键所在,此时取最小值,就是 一个字符在所有字符串里出现的最小次数了。
|
||||||
|
|
||||||
|
代码如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
int hashOtherStr[26] = {0}; // 统计除第一个字符串外字符的出现频率
|
||||||
|
for (int i = 1; i < A.size(); i++) {
|
||||||
|
memset(hashOtherStr, 0, 26 * sizeof(int));
|
||||||
|
for (int j = 0; j < A[i].size(); j++) {
|
||||||
|
hashOtherStr[A[i][j] - 'a']++;
|
||||||
|
}
|
||||||
|
// 这是关键所在
|
||||||
|
for (int k = 0; k < 26; k++) { // 更新hash,保证hash里统计26个字符在所有字符串里出现的最小次数
|
||||||
|
hash[k] = min(hash[k], hashOtherStr[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
此时hash里统计着字符在所有字符串里出现的最小次数,那么把hash转正题目要求的输出格式就可以了。
|
||||||
|
|
||||||
|
代码如下:
|
||||||
|
|
||||||
|
```
|
||||||
|
// 将hash统计的字符次数,转成输出形式
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
while (hash[i] != 0) { // 注意这里是while,多个重复的字符
|
||||||
|
string s(1, i + 'a'); // char -> string
|
||||||
|
result.push_back(s);
|
||||||
|
hash[i]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
整体C++代码如下:
|
||||||
|
|
||||||
|
```C++
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
vector<string> commonChars(vector<string>& A) {
|
||||||
|
vector<string> result;
|
||||||
|
if (A.size() == 0) return result;
|
||||||
|
int hash[26] = {0}; // 用来统计所有字符串里字符出现的最小频率
|
||||||
|
for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
|
||||||
|
hash[A[0][i] - 'a']++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hashOtherStr[26] = {0}; // 统计除第一个字符串外字符的出现频率
|
||||||
|
for (int i = 1; i < A.size(); i++) {
|
||||||
|
memset(hashOtherStr, 0, 26 * sizeof(int));
|
||||||
|
for (int j = 0; j < A[i].size(); j++) {
|
||||||
|
hashOtherStr[A[i][j] - 'a']++;
|
||||||
|
}
|
||||||
|
// 更新hash,保证hash里统计26个字符在所有字符串里出现的最小次数
|
||||||
|
for (int k = 0; k < 26; k++) {
|
||||||
|
hash[k] = min(hash[k], hashOtherStr[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 将hash统计的字符次数,转成输出形式
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
while (hash[i] != 0) { // 注意这里是while,多个重复的字符
|
||||||
|
string s(1, i + 'a'); // char -> string
|
||||||
|
result.push_back(s);
|
||||||
|
hash[i]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 其他语言版本
|
||||||
|
|
||||||
|
Java:
|
||||||
|
|
||||||
|
```Java
|
||||||
|
class Solution {
|
||||||
|
public List<String> commonChars(String[] A) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (A.length == 0) return result;
|
||||||
|
int[] hash= new int[26]; // 用来统计所有字符串里字符出现的最小频率
|
||||||
|
for (int i = 0; i < A[0].length(); i++) { // 用第一个字符串给hash初始化
|
||||||
|
hash[A[0].charAt(i)- 'a']++;
|
||||||
|
}
|
||||||
|
// 统计除第一个字符串外字符的出现频率
|
||||||
|
for (int i = 1; i < A.length; i++) {
|
||||||
|
int[] hashOtherStr= new int[26];
|
||||||
|
for (int j = 0; j < A[i].length(); j++) {
|
||||||
|
hashOtherStr[A[i].charAt(j)- 'a']++;
|
||||||
|
}
|
||||||
|
// 更新hash,保证hash里统计26个字符在所有字符串里出现的最小次数
|
||||||
|
for (int k = 0; k < 26; k++) {
|
||||||
|
hash[k] = Math.min(hash[k], hashOtherStr[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 将hash统计的字符次数,转成输出形式
|
||||||
|
for (int i = 0; i < 26; i++) {
|
||||||
|
while (hash[i] != 0) { // 注意这里是while,多个重复的字符
|
||||||
|
char c= (char) (i+'a');
|
||||||
|
result.add(String.valueOf(c));
|
||||||
|
hash[i]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
89
problems/1356.根据数字二进制下1的数目排序.md
Normal file
89
problems/1356.根据数字二进制下1的数目排序.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
|
||||||
|
## 题目链接
|
||||||
|
https://leetcode-cn.com/problems/sort-integers-by-the-number-of-1-bits/
|
||||||
|
|
||||||
|
## 思路
|
||||||
|
|
||||||
|
这道题其实是考察如何计算一个数的二进制中1的数量。
|
||||||
|
|
||||||
|
我提供两种方法:
|
||||||
|
|
||||||
|
* 方法一:
|
||||||
|
|
||||||
|
朴实无华挨个计算1的数量,最多就是循环n的二进制位数,32位。
|
||||||
|
|
||||||
|
```C++
|
||||||
|
int bitCount(int n) {
|
||||||
|
int count = 0; // 计数器
|
||||||
|
while (n > 0) {
|
||||||
|
if((n & 1) == 1) count++; // 当前位是1,count++
|
||||||
|
n >>= 1 ; // n向右移位
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* 方法二
|
||||||
|
|
||||||
|
这种方法,只循环n的二进制中1的个数次,比方法一高效的多
|
||||||
|
|
||||||
|
```C++
|
||||||
|
int bitCount(int n) {
|
||||||
|
int count = 0;
|
||||||
|
while (n) {
|
||||||
|
n &= (n - 1); // 清除最低位的1
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
以计算12的二进制1的数量为例,如图所示:
|
||||||
|
|
||||||
|
<img src='https://code-thinking.cdn.bcebos.com/pics/1356.根据数字二进制下1的数目排序.png' width=600> </img></div>
|
||||||
|
|
||||||
|
下面我就使用方法二,来做这道题目:
|
||||||
|
|
||||||
|
## C++代码
|
||||||
|
|
||||||
|
```C++
|
||||||
|
class Solution {
|
||||||
|
private:
|
||||||
|
static int bitCount(int n) { // 计算n的二进制中1的数量
|
||||||
|
int count = 0;
|
||||||
|
while(n) {
|
||||||
|
n &= (n -1); // 清除最低位的1
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
static bool cmp(int a, int b) {
|
||||||
|
int bitA = bitCount(a);
|
||||||
|
int bitB = bitCount(b);
|
||||||
|
if (bitA == bitB) return a < b; // 如果bit中1数量相同,比较数值大小
|
||||||
|
return bitA < bitB; // 否则比较bit中1数量大小
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
vector<int> sortByBits(vector<int>& arr) {
|
||||||
|
sort(arr.begin(), arr.end(), cmp);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 其他语言版本
|
||||||
|
|
||||||
|
Java:
|
||||||
|
|
||||||
|
Python:
|
||||||
|
|
||||||
|
Go:
|
||||||
|
|
||||||
|
JavaScript:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
> 统一写法是一种什么感觉
|
> 统一写法是一种什么感觉
|
||||||
|
|
||||||
此时我们在[二叉树:一入递归深似海,从此offer是路人](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)中用递归的方式,实现了二叉树前中后序的遍历。
|
此时我们在[二叉树:一入递归深似海,从此offer是路人](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)中用递归的方式,实现了二叉树前中后序的遍历。
|
||||||
|
|
||||||
在[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)中用栈实现了二叉树前后中序的迭代遍历(非递归)。
|
在[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)中用栈实现了二叉树前后中序的迭代遍历(非递归)。
|
||||||
|
|
||||||
之后我们发现**迭代法实现的先中后序,其实风格也不是那么统一,除了先序和后序,有关联,中序完全就是另一个风格了,一会用栈遍历,一会又用指针来遍历。**
|
之后我们发现**迭代法实现的先中后序,其实风格也不是那么统一,除了先序和后序,有关联,中序完全就是另一个风格了,一会用栈遍历,一会又用指针来遍历。**
|
||||||
|
|
||||||
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
**重头戏来了,接下来介绍一下统一写法。**
|
**重头戏来了,接下来介绍一下统一写法。**
|
||||||
|
|
||||||
我们以中序遍历为例,在[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)中提到说使用栈的话,**无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况**。
|
我们以中序遍历为例,在[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)中提到说使用栈的话,**无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况**。
|
||||||
|
|
||||||
**那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。**
|
**那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。**
|
||||||
|
|
||||||
@ -149,14 +149,13 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
迭代法前序遍历代码如下:
|
迭代法前序遍历代码如下:
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
|
|
||||||
public List<Integer> preorderTraversal(TreeNode root) {
|
public List<Integer> preorderTraversal(TreeNode root) {
|
||||||
List<Integer> result = new LinkedList<>();
|
List<Integer> result = new LinkedList<>();
|
||||||
Stack<TreeNode> st = new Stack<>();
|
Stack<TreeNode> st = new Stack<>();
|
||||||
@ -180,39 +179,39 @@ Java:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```
|
迭代法中序遍历代码如下:
|
||||||
迭代法中序遍历代码如下:
|
```java
|
||||||
```java
|
class Solution {
|
||||||
class Solution {
|
public List<Integer> inorderTraversal(TreeNode root) {
|
||||||
public List<Integer> inorderTraversal(TreeNode root) {
|
List<Integer> result = new LinkedList<>();
|
||||||
List<Integer> result = new LinkedList<>();
|
Stack<TreeNode> st = new Stack<>();
|
||||||
Stack<TreeNode> st = new Stack<>();
|
if (root != null) st.push(root);
|
||||||
if (root != null) st.push(root);
|
while (!st.empty()) {
|
||||||
while (!st.empty()) {
|
TreeNode node = st.peek();
|
||||||
TreeNode node = st.peek();
|
if (node != null) {
|
||||||
if (node != null) {
|
st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
|
||||||
st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
|
if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈)
|
||||||
if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈)
|
st.push(node); // 添加中节点
|
||||||
st.push(node); // 添加中节点
|
st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
|
||||||
st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
|
|
||||||
|
|
||||||
if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈)
|
if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈)
|
||||||
} else { // 只有遇到空节点的时候,才将下一个节点放进结果集
|
} else { // 只有遇到空节点的时候,才将下一个节点放进结果集
|
||||||
st.pop(); // 将空节点弹出
|
st.pop(); // 将空节点弹出
|
||||||
node = st.peek(); // 重新取出栈中元素
|
node = st.peek(); // 重新取出栈中元素
|
||||||
st.pop();
|
st.pop();
|
||||||
result.add(node.val); // 加入到结果集
|
result.add(node.val); // 加入到结果集
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
```
|
}
|
||||||
迭代法后序遍历代码如下:
|
```
|
||||||
```java
|
|
||||||
class Solution {
|
|
||||||
|
|
||||||
|
迭代法后序遍历代码如下:
|
||||||
|
```java
|
||||||
|
class Solution {
|
||||||
public List<Integer> postorderTraversal(TreeNode root) {
|
public List<Integer> postorderTraversal(TreeNode root) {
|
||||||
List<Integer> result = new LinkedList<>();
|
List<Integer> result = new LinkedList<>();
|
||||||
Stack<TreeNode> st = new Stack<>();
|
Stack<TreeNode> st = new Stack<>();
|
||||||
@ -236,11 +235,11 @@ Java:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```
|
|
||||||
Python:
|
Python:
|
||||||
> 迭代法前序遍历
|
|
||||||
|
|
||||||
|
迭代法前序遍历:
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def preorderTraversal(self, root: TreeNode) -> List[int]:
|
def preorderTraversal(self, root: TreeNode) -> List[int]:
|
||||||
@ -263,7 +262,7 @@ class Solution:
|
|||||||
return result
|
return result
|
||||||
```
|
```
|
||||||
|
|
||||||
> 迭代法中序遍历
|
迭代法中序遍历:
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def inorderTraversal(self, root: TreeNode) -> List[int]:
|
def inorderTraversal(self, root: TreeNode) -> List[int]:
|
||||||
@ -288,7 +287,7 @@ class Solution:
|
|||||||
return result
|
return result
|
||||||
```
|
```
|
||||||
|
|
||||||
> 迭代法后序遍历
|
迭代法后序遍历:
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def postorderTraversal(self, root: TreeNode) -> List[int]:
|
def postorderTraversal(self, root: TreeNode) -> List[int]:
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
为什么可以用迭代法(非递归的方式)来实现二叉树的前后中序遍历呢?
|
为什么可以用迭代法(非递归的方式)来实现二叉树的前后中序遍历呢?
|
||||||
|
|
||||||
我们在[栈与队列:匹配问题都是栈的强项](https://mp.weixin.qq.com/s/eynAEbUbZoAWrk0ZlEugqg)中提到了,**递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中**,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
|
我们在[栈与队列:匹配问题都是栈的强项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)中提到了,**递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中**,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
|
||||||
|
|
||||||
此时大家应该知道我们用栈也可以是实现二叉树的前后中序遍历了。
|
此时大家应该知道我们用栈也可以是实现二叉树的前后中序遍历了。
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ public:
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 总结
|
# 总结
|
||||||
|
|
||||||
此时我们用迭代法写出了二叉树的前后中序遍历,大家可以看出前序和中序是完全两种代码风格,并不想递归写法那样代码稍做调整,就可以实现前后中序。
|
此时我们用迭代法写出了二叉树的前后中序遍历,大家可以看出前序和中序是完全两种代码风格,并不想递归写法那样代码稍做调整,就可以实现前后中序。
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
|
|
||||||
@ -233,7 +233,8 @@ class Solution {
|
|||||||
|
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python3
|
|
||||||
|
```python
|
||||||
# 前序遍历-迭代-LC144_二叉树的前序遍历
|
# 前序遍历-迭代-LC144_二叉树的前序遍历
|
||||||
class Solution:
|
class Solution:
|
||||||
def preorderTraversal(self, root: TreeNode) -> List[int]:
|
def preorderTraversal(self, root: TreeNode) -> List[int]:
|
||||||
|
@ -7,12 +7,19 @@
|
|||||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
|
相信每一位录友都接触过时间复杂度,但又对时间复杂度的认识处于一种朦胧的状态,所以是时候对时间复杂度来一个深度的剖析了。
|
||||||
|
|
||||||
Carl大胆断言:这可能是你见过对时间复杂度分析最通透的一篇文章了。
|
本篇从如下六点进行分析:
|
||||||
|
|
||||||
相信每一位录友都接触过时间复杂度,「代码随想录」已经也讲了一百多道经典题目了,是时候对时间复杂度来一个深度的剖析了,很早之前就写过一篇,当时文章还没有人看,Carl感觉有价值的东西值得让更多的人看到,哈哈。
|
* 究竟什么是时间复杂度
|
||||||
|
* 什么是大O
|
||||||
|
* 不同数据规模的差异
|
||||||
|
* 复杂表达式的化简
|
||||||
|
* O(logn)中的log是以什么为底?
|
||||||
|
* 举一个例子
|
||||||
|
|
||||||
所以重新整理的时间复杂度文章,正式和大家见面啦!
|
|
||||||
|
这可能是你见过对时间复杂度分析最通透的一篇文章。
|
||||||
|
|
||||||
## 究竟什么是时间复杂度
|
## 究竟什么是时间复杂度
|
||||||
|
|
||||||
@ -151,7 +158,7 @@ O(2 * n^2 + 10 * n + 1000) < O(3 * n^2),所以说最后省略掉常数项系
|
|||||||
|
|
||||||
**当然这不是这道题目的最优解,我仅仅是用这道题目来讲解一下时间复杂度**。
|
**当然这不是这道题目的最优解,我仅仅是用这道题目来讲解一下时间复杂度**。
|
||||||
|
|
||||||
# 总结
|
## 总结
|
||||||
|
|
||||||
本篇讲解了什么是时间复杂度,复杂度是用来干什么,以及数据规模对时间复杂度的影响。
|
本篇讲解了什么是时间复杂度,复杂度是用来干什么,以及数据规模对时间复杂度的影响。
|
||||||
|
|
||||||
@ -161,12 +168,6 @@ O(2 * n^2 + 10 * n + 1000) < O(3 * n^2),所以说最后省略掉常数项系
|
|||||||
|
|
||||||
相信看完本篇,大家对时间复杂度的认识会深刻很多!
|
相信看完本篇,大家对时间复杂度的认识会深刻很多!
|
||||||
|
|
||||||
如果感觉「代码随想录」很不错,赶快推荐给身边的朋友同学们吧,他们发现和「代码随想录」相见恨晚!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -118,6 +118,8 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
python:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# 方法一:可以使用切片方法
|
# 方法一:可以使用切片方法
|
||||||
class Solution:
|
class Solution:
|
||||||
|
Reference in New Issue
Block a user