Merge branch 'master' of github.com:Hanmengnan/leetcode-master
This commit is contained in:
commit
34b4ffa24c
61
README.md
61
README.md
|
|
@ -1,14 +1,14 @@
|
||||||
|
|
||||||
|
|
||||||
👉 推荐 [在线阅读](http://programmercarl.com/) (Github在国内访问经常不稳定)
|
👉 推荐 [在线阅读](http://programmercarl.com/) (Github在国内访问经常不稳定)
|
||||||
👉 推荐 [Gitee同步](https://gitee.com/programmercarl/leetcode-master)
|
👉 推荐 [Gitee同步](https://gitee.com/programmercarl/leetcode-master)
|
||||||
|
|
||||||
> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者)
|
> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者)
|
||||||
> 2. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://programmercarl.com/other/algo_pdf.html) 。
|
> 2. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://programmercarl.com/other/algo_pdf.html) 。
|
||||||
> 3. **刷题顺序** : README已经将刷题顺序排好了,按照顺序一道一道刷就可以。
|
> 3. **最强八股文:**:[代码随想录知识星球精华PDF](https://www.programmercarl.com/other/kstar_baguwen.html)
|
||||||
> 4. **学习社区** : 一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」知识星球](https://programmercarl.com/other/kstar.html) 。
|
> 4. **刷题顺序** : README已经将刷题顺序排好了,按照顺序一道一道刷就可以。
|
||||||
> 5. **提交代码**:本项目统一使用C++语言进行讲解,但已经有Java、Python、Go、JavaScript等等多语言版本,感谢[这里的每一位贡献者](https://github.com/youngyangyang04/leetcode-master/graphs/contributors),如果你也想贡献代码点亮你的头像,[点击这里](https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A)了解提交代码的方式。
|
> 5. **学习社区** : 一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」知识星球](https://programmercarl.com/other/kstar.html) 。
|
||||||
> 6. **转载须知** :以下所有文章皆为我([程序员Carl](https://github.com/youngyangyang04))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!
|
> 6. **提交代码**:本项目统一使用C++语言进行讲解,但已经有Java、Python、Go、JavaScript等等多语言版本,感谢[这里的每一位贡献者](https://github.com/youngyangyang04/leetcode-master/graphs/contributors),如果你也想贡献代码点亮你的头像,[点击这里](https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A)了解提交代码的方式。
|
||||||
|
> 7. **转载须知** :以下所有文章皆为我([程序员Carl](https://github.com/youngyangyang04))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="programmercarl.com" target="_blank">
|
<a href="programmercarl.com" target="_blank">
|
||||||
|
|
@ -88,8 +88,7 @@
|
||||||
|
|
||||||
## 前序
|
## 前序
|
||||||
|
|
||||||
* [「代码随想录」后序安排](https://mp.weixin.qq.com/s/4eeGJREy6E-v6D7cR_5A4g)
|
* [「代码随想录」学习社区](https://programmercarl.com/other/kstar.html)
|
||||||
* [「代码随想录」学习社区](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
|
||||||
|
|
||||||
|
|
||||||
* 编程语言
|
* 编程语言
|
||||||
|
|
@ -103,6 +102,7 @@
|
||||||
* [看了这么多代码,谈一谈代码风格!](./problems/前序/代码风格.md)
|
* [看了这么多代码,谈一谈代码风格!](./problems/前序/代码风格.md)
|
||||||
* [力扣上的代码想在本地编译运行?](./problems/前序/力扣上的代码想在本地编译运行?.md)
|
* [力扣上的代码想在本地编译运行?](./problems/前序/力扣上的代码想在本地编译运行?.md)
|
||||||
* [什么是核心代码模式,什么又是ACM模式?](./problems/前序/什么是核心代码模式,什么又是ACM模式?.md)
|
* [什么是核心代码模式,什么又是ACM模式?](./problems/前序/什么是核心代码模式,什么又是ACM模式?.md)
|
||||||
|
* [刷题要不要用库函数](./problems/前序/刷力扣用不用库函数.md)
|
||||||
* [ACM模式如何构造二叉树](./problems/前序/ACM模式如何构建二叉树.md)
|
* [ACM模式如何构造二叉树](./problems/前序/ACM模式如何构建二叉树.md)
|
||||||
* [解密互联网大厂研发流程](./problems/前序/互联网大厂研发流程.md)
|
* [解密互联网大厂研发流程](./problems/前序/互联网大厂研发流程.md)
|
||||||
|
|
||||||
|
|
@ -123,52 +123,13 @@
|
||||||
|
|
||||||
* 算法性能分析
|
* 算法性能分析
|
||||||
* [关于时间复杂度,你不知道的都在这里!](./problems/前序/关于时间复杂度,你不知道的都在这里!.md)
|
* [关于时间复杂度,你不知道的都在这里!](./problems/前序/关于时间复杂度,你不知道的都在这里!.md)
|
||||||
* [$O(n)$的算法居然超时了,此时的n究竟是多大?](./problems/前序/On的算法居然超时了,此时的n究竟是多大?.md)
|
* [O(n)的算法居然超时了,此时的n究竟是多大?](./problems/前序/On的算法居然超时了,此时的n究竟是多大?.md)
|
||||||
* [通过一道面试题目,讲一讲递归算法的时间复杂度!](./problems/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.md)
|
* [通过一道面试题目,讲一讲递归算法的时间复杂度!](./problems/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.md)
|
||||||
* [本周小结!(算法性能分析系列一)](./problems/周总结/20201210复杂度分析周末总结.md)
|
* [本周小结!(算法性能分析系列一)](./problems/周总结/20201210复杂度分析周末总结.md)
|
||||||
* [关于空间复杂度,可能有几个疑问?](./problems/前序/关于空间复杂度,可能有几个疑问?.md)
|
* [关于空间复杂度,可能有几个疑问?](./problems/前序/关于空间复杂度,可能有几个疑问?.md)
|
||||||
* [递归算法的时间与空间复杂度分析!](./problems/前序/递归算法的时间与空间复杂度分析.md)
|
* [递归算法的时间与空间复杂度分析!](./problems/前序/递归算法的时间与空间复杂度分析.md)
|
||||||
* [刷了这么多题,你了解自己代码的内存消耗么?](./problems/前序/刷了这么多题,你了解自己代码的内存消耗么?.md)
|
* [刷了这么多题,你了解自己代码的内存消耗么?](./problems/前序/刷了这么多题,你了解自己代码的内存消耗么?.md)
|
||||||
|
|
||||||
## 知识星球精选
|
|
||||||
|
|
||||||
* [秋招面试,心态很重要!](./problems/知识星球精选/秋招总结3.md)
|
|
||||||
* [秋招倒霉透顶,触底反弹!](./problems/知识星球精选/秋招总结2.md)
|
|
||||||
* [无竞赛,无实习,如何秋招?](./problems/知识星球精选/秋招总结1.md)
|
|
||||||
* [offer总决赛,何去何从!](./problems/知识星球精选/offer总决赛,何去何从.md)
|
|
||||||
* [入职后担心代码能力跟不上!](./problems/知识星球精选/入职后担心代码能力跟不上.md)
|
|
||||||
* [秋招进入offer决赛圈!](./problems/知识星球精选/offer对比-决赛圈.md)
|
|
||||||
* [非科班的困扰](./problems/知识星球精选/非科班的困扰.md)
|
|
||||||
* [offer的选择-开奖](./problems/知识星球精选/秋招开奖.md)
|
|
||||||
* [看到代码就抵触!怎么办?](./problems/知识星球精选/不喜欢写代码怎么办.md)
|
|
||||||
* [遭遇逼签,怎么办?](./problems/知识星球精选/逼签.md)
|
|
||||||
* [HR特意刁难非科班!](./problems/知识星球精选/HR特意刁难非科班.md)
|
|
||||||
* [offer的选择](./problems/知识星球精选/offer的选择.md)
|
|
||||||
* [天下乌鸦一般黑,哪家没有PUA?](./problems/知识星球精选/天下乌鸦一般黑.md)
|
|
||||||
* [初入大三,考研VS工作](./problems/知识星球精选/初入大三选择考研VS工作.md)
|
|
||||||
* [非科班2021秋招总结](./problems/知识星球精选/非科班2021秋招总结.md)
|
|
||||||
* [秋招下半场依然没offer,怎么办?](./problems/知识星球精选/秋招下半场依然没offer.md)
|
|
||||||
* [合适自己的就是最好的](./problems/知识星球精选/合适自己的就是最好的.md)
|
|
||||||
* [为什么都说客户端会消失](./problems/知识星球精选/客三消.md)
|
|
||||||
* [博士转计算机如何找工作](./problems/知识星球精选/博士转行计算机.md)
|
|
||||||
* [不一样的七夕](./problems/知识星球精选/不一样的七夕.md)
|
|
||||||
* [HR面注意事项](./problems/知识星球精选/HR面注意事项.md)
|
|
||||||
* [刷题攻略要刷两遍!](./problems/知识星球精选/刷题攻略要刷两遍.md)
|
|
||||||
* [秋招进行中的迷茫与焦虑......](./problems/知识星球精选/秋招进行中的迷茫与焦虑.md)
|
|
||||||
* [大厂新人培养体系应该是什么样的?](./problems/知识星球精选/大厂新人培养体系.md)
|
|
||||||
* [你的简历里「专业技能」写的够专业么?](./problems/知识星球精选/专业技能可以这么写.md)
|
|
||||||
* [Carl看了上百份简历,总结了这些!](./problems/知识星球精选/写简历的一些问题.md)
|
|
||||||
* [备战2022届秋招](./problems/知识星球精选/备战2022届秋招.md)
|
|
||||||
* [技术不太好,如果选择方向](./problems/知识星球精选/技术不好如何选择技术方向.md)
|
|
||||||
* [刷题要不要使用库函数](./problems/知识星球精选/刷力扣用不用库函数.md)
|
|
||||||
* [关于实习的几点问题](./problems/知识星球精选/关于实习大家的疑问.md)
|
|
||||||
* [面试中遇到了发散性问题,怎么办?](./problems/知识星球精选/面试中发散性问题.md)
|
|
||||||
* [英语到底重不重要!](./problems/知识星球精选/英语到底重不重要.md)
|
|
||||||
* [计算机专业要不要读研!](./problems/知识星球精选/要不要考研.md)
|
|
||||||
* [关于提前批的一些建议](./problems/知识星球精选/关于提前批的一些建议.md)
|
|
||||||
* [已经在实习的录友要如何准备秋招](./problems/知识星球精选/如何权衡实习与秋招复习.md)
|
|
||||||
* [华为提前批已经开始了](./problems/知识星球精选/提前批已经开始了.md)
|
|
||||||
|
|
||||||
## 杂谈
|
## 杂谈
|
||||||
|
|
||||||
* [「代码随想录」刷题网站上线](https://mp.weixin.qq.com/s/-6rd_g7LrVD1fuKBYk2tXQ)。
|
* [「代码随想录」刷题网站上线](https://mp.weixin.qq.com/s/-6rd_g7LrVD1fuKBYk2tXQ)。
|
||||||
|
|
@ -263,7 +224,7 @@
|
||||||
3. [二叉树:听说递归能做的,栈也能做!](./problems/二叉树的迭代遍历.md)
|
3. [二叉树:听说递归能做的,栈也能做!](./problems/二叉树的迭代遍历.md)
|
||||||
4. [二叉树:前中后序迭代方式的写法就不能统一一下么?](./problems/二叉树的统一迭代法.md)
|
4. [二叉树:前中后序迭代方式的写法就不能统一一下么?](./problems/二叉树的统一迭代法.md)
|
||||||
5. [二叉树:层序遍历登场!](./problems/0102.二叉树的层序遍历.md)
|
5. [二叉树:层序遍历登场!](./problems/0102.二叉树的层序遍历.md)
|
||||||
6. [二叉树:你真的会翻转二叉树么?](./problems/0226.翻转二叉树.md)
|
6. [二叉树:你真的会翻转二叉树么?](./problems/0226.翻转二叉树.md)
|
||||||
7. [本周小结!(二叉树)](./problems/周总结/20200927二叉树周末总结.md)
|
7. [本周小结!(二叉树)](./problems/周总结/20200927二叉树周末总结.md)
|
||||||
8. [二叉树:我对称么?](./problems/0101.对称二叉树.md)
|
8. [二叉树:我对称么?](./problems/0101.对称二叉树.md)
|
||||||
9. [二叉树:看看这些树的最大深度](./problems/0104.二叉树的最大深度.md)
|
9. [二叉树:看看这些树的最大深度](./problems/0104.二叉树的最大深度.md)
|
||||||
|
|
@ -570,7 +531,8 @@
|
||||||
|
|
||||||
如果是已工作,备注:姓名-城市-岗位-组队刷题。如果学生,备注:姓名-学校-年级-组队刷题。**备注没有自我介绍不通过哦**
|
如果是已工作,备注:姓名-城市-岗位-组队刷题。如果学生,备注:姓名-学校-年级-组队刷题。**备注没有自我介绍不通过哦**
|
||||||
|
|
||||||
<div align="center"><img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20220102204804.png" data-img="1" width="200" height="200"></img></div>
|
|
||||||
|
<div align="center"><img src="https://code-thinking-1253855093.file.myqcloud.com/pics/第二企业刷题活码.png" data-img="1" width="200" height="200"></img></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -582,6 +544,7 @@
|
||||||
|
|
||||||
**来看看就知道了,你会发现相见恨晚!**
|
**来看看就知道了,你会发现相见恨晚!**
|
||||||
|
|
||||||
|
|
||||||
<a name="公众号"></a>
|
<a name="公众号"></a>
|
||||||
<div align="center"><img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20211026122841.png" data-img="1" width="650" height="500"></img></div>
|
<div align="center"><img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20211026122841.png" data-img="1" width="650" height="500"></img></div>
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -118,6 +118,18 @@ class Solution:
|
||||||
return [records[target - val], idx] # 如果存在就返回字典记录索引和当前索引
|
return [records[target - val], idx] # 如果存在就返回字典记录索引和当前索引
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Python (v2):
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def twoSum(self, nums: List[int], target: int) -> List[int]:
|
||||||
|
rec = {}
|
||||||
|
for i in range(len(nums)):
|
||||||
|
rest = target - nums[i]
|
||||||
|
# Use get to get the index of the data, making use of one of the dictionary properties.
|
||||||
|
if rec.get(rest, None) is not None: return [rec[rest], i]
|
||||||
|
rec[nums[i]] = i
|
||||||
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
|
@ -186,6 +198,24 @@ var twoSum = function (nums, target) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function twoSum(nums: number[], target: number): number[] {
|
||||||
|
let helperMap: Map<number, number> = new Map();
|
||||||
|
let index: number | undefined;
|
||||||
|
let resArr: number[] = [];
|
||||||
|
for (let i = 0, length = nums.length; i < length; i++) {
|
||||||
|
index = helperMap.get(target - nums[i]);
|
||||||
|
if (index !== undefined) {
|
||||||
|
resArr = [i, index];
|
||||||
|
}
|
||||||
|
helperMap.set(nums[i], i);
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
php
|
php
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
两层for循环,遍历区间起始位置和终止位置,然后判断这个区间是不是回文。
|
两层for循环,遍历区间起始位置和终止位置,然后判断这个区间是不是回文。
|
||||||
|
|
||||||
时间复杂度:$O(n^3)$
|
时间复杂度:O(n^3)
|
||||||
|
|
||||||
## 动态规划
|
## 动态规划
|
||||||
|
|
||||||
|
|
@ -205,8 +205,8 @@ public:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n^2)$
|
* 时间复杂度:O(n^2)
|
||||||
* 空间复杂度:$O(n^2)$
|
* 空间复杂度:O(n^2)
|
||||||
|
|
||||||
## 双指针
|
## 双指针
|
||||||
|
|
||||||
|
|
@ -253,14 +253,33 @@ public:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n^2)$
|
* 时间复杂度:O(n^2)
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
## Java
|
Java:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] twoSum(int[] nums, int target) {
|
||||||
|
int[] res = new int[2];
|
||||||
|
if(nums == null || nums.length == 0){
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
Map<Integer, Integer> map = new HashMap<>();
|
||||||
|
for(int i = 0; i < nums.length; i++){
|
||||||
|
int temp = target - nums[i];
|
||||||
|
if(map.containsKey(temp)){
|
||||||
|
res[1] = i;
|
||||||
|
res[0] = map.get(temp);
|
||||||
|
}
|
||||||
|
map.put(nums[i], i);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// 双指针 中心扩散法
|
// 双指针 中心扩散法
|
||||||
|
|
@ -291,7 +310,7 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Python
|
Python:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
|
|
@ -312,7 +331,8 @@ class Solution:
|
||||||
return s[left:right + 1]
|
return s[left:right + 1]
|
||||||
|
|
||||||
```
|
```
|
||||||
> 双指针法:
|
双指针:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def longestPalindrome(self, s: str) -> str:
|
def longestPalindrome(self, s: str) -> str:
|
||||||
|
|
@ -340,13 +360,13 @@ class Solution:
|
||||||
return s[start:end]
|
return s[start:end]
|
||||||
|
|
||||||
```
|
```
|
||||||
## Go
|
Go:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## JavaScript
|
JavaScript:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//动态规划解法
|
//动态规划解法
|
||||||
|
|
@ -462,7 +482,93 @@ var longestPalindrome = function(s) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C:
|
||||||
|
|
||||||
|
动态规划:
|
||||||
|
```c
|
||||||
|
//初始化dp数组,全部初始为false
|
||||||
|
bool **initDP(int strLen) {
|
||||||
|
bool **dp = (bool **)malloc(sizeof(bool *) * strLen);
|
||||||
|
int i, j;
|
||||||
|
for(i = 0; i < strLen; ++i) {
|
||||||
|
dp[i] = (bool *)malloc(sizeof(bool) * strLen);
|
||||||
|
for(j = 0; j < strLen; ++j)
|
||||||
|
dp[i][j] = false;
|
||||||
|
}
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * longestPalindrome(char * s){
|
||||||
|
//求出字符串长度
|
||||||
|
int strLen = strlen(s);
|
||||||
|
//初始化dp数组,元素初始化为false
|
||||||
|
bool **dp = initDP(strLen);
|
||||||
|
int maxLength = 0, left = 0, right = 0;
|
||||||
|
|
||||||
|
//从下到上,从左到右遍历
|
||||||
|
int i, j;
|
||||||
|
for(i = strLen - 1; i >= 0; --i) {
|
||||||
|
for(j = i; j < strLen; ++j) {
|
||||||
|
//若当前i与j所指字符一样
|
||||||
|
if(s[i] == s[j]) {
|
||||||
|
//若i、j指向相邻字符或同一字符,则为回文字符串
|
||||||
|
if(j - i <= 1)
|
||||||
|
dp[i][j] = true;
|
||||||
|
//若i+1与j-1所指字符串为回文字符串,则i、j所指字符串为回文字符串
|
||||||
|
else if(dp[i + 1][j - 1])
|
||||||
|
dp[i][j] = true;
|
||||||
|
}
|
||||||
|
//若新的字符串的长度大于之前的最大长度,进行更新
|
||||||
|
if(dp[i][j] && j - i + 1 > maxLength) {
|
||||||
|
maxLength = j - i + 1;
|
||||||
|
left = i;
|
||||||
|
right = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//复制回文字符串,并返回
|
||||||
|
char *ret = (char*)malloc(sizeof(char) * (maxLength + 1));
|
||||||
|
memcpy(ret, s + left, maxLength);
|
||||||
|
ret[maxLength] = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
双指针:
|
||||||
|
```c
|
||||||
|
int left, maxLength;
|
||||||
|
void extend(char *str, int i, int j, int size) {
|
||||||
|
while(i >= 0 && j < size && str[i] == str[j]) {
|
||||||
|
//若当前子字符串长度大于最长的字符串长度,进行更新
|
||||||
|
if(j - i + 1 > maxLength) {
|
||||||
|
maxLength = j - i + 1;
|
||||||
|
left = i;
|
||||||
|
}
|
||||||
|
//左指针左移,右指针右移。扩大搜索范围
|
||||||
|
++j, --i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char * longestPalindrome(char * s){
|
||||||
|
left = right = maxLength = 0;
|
||||||
|
int size = strlen(s);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < size; ++i) {
|
||||||
|
//长度为单数的子字符串
|
||||||
|
extend(s, i, i, size);
|
||||||
|
//长度为双数的子字符串
|
||||||
|
extend(s, i, i + 1, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//复制子字符串
|
||||||
|
char *subStr = (char *)malloc(sizeof(char) * (maxLength + 1));
|
||||||
|
memcpy(subStr, s + left, maxLength);
|
||||||
|
subStr[maxLength] = 0;
|
||||||
|
|
||||||
|
return subStr;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -138,8 +138,12 @@ public:
|
||||||
*/
|
*/
|
||||||
if (nums[i] + nums[left] + nums[right] > 0) {
|
if (nums[i] + nums[left] + nums[right] > 0) {
|
||||||
right--;
|
right--;
|
||||||
|
// 当前元素不合适了,可以去重
|
||||||
|
while (left < right && nums[right] == nums[right + 1]) right--;
|
||||||
} else if (nums[i] + nums[left] + nums[right] < 0) {
|
} else if (nums[i] + nums[left] + nums[right] < 0) {
|
||||||
left++;
|
left++;
|
||||||
|
// 不合适,去重
|
||||||
|
while (left < right && nums[left] == nums[left - 1]) left++;
|
||||||
} else {
|
} else {
|
||||||
result.push_back(vector<int>{nums[i], nums[left], nums[right]});
|
result.push_back(vector<int>{nums[i], nums[left], nums[right]});
|
||||||
// 去重逻辑应该放在找到一个三元组之后
|
// 去重逻辑应该放在找到一个三元组之后
|
||||||
|
|
@ -243,7 +247,34 @@ class Solution:
|
||||||
right -= 1
|
right -= 1
|
||||||
return ans
|
return ans
|
||||||
```
|
```
|
||||||
|
Python (v2):
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def threeSum(self, nums: List[int]) -> List[List[int]]:
|
||||||
|
if len(nums) < 3: return []
|
||||||
|
nums, res = sorted(nums), []
|
||||||
|
for i in range(len(nums) - 2):
|
||||||
|
cur, l, r = nums[i], i + 1, len(nums) - 1
|
||||||
|
if res != [] and res[-1][0] == cur: continue # Drop duplicates for the first time.
|
||||||
|
|
||||||
|
while l < r:
|
||||||
|
if cur + nums[l] + nums[r] == 0:
|
||||||
|
res.append([cur, nums[l], nums[r]])
|
||||||
|
# Drop duplicates for the second time in interation of l & r. Only used when target situation occurs, because that is the reason for dropping duplicates.
|
||||||
|
while l < r - 1 and nums[l] == nums[l + 1]:
|
||||||
|
l += 1
|
||||||
|
while r > l + 1 and nums[r] == nums[r - 1]:
|
||||||
|
r -= 1
|
||||||
|
if cur + nums[l] + nums[r] > 0:
|
||||||
|
r -= 1
|
||||||
|
else:
|
||||||
|
l += 1
|
||||||
|
return res
|
||||||
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
func threeSum(nums []int)[][]int{
|
func threeSum(nums []int)[][]int{
|
||||||
sort.Ints(nums)
|
sort.Ints(nums)
|
||||||
|
|
@ -282,57 +313,75 @@ func threeSum(nums []int)[][]int{
|
||||||
javaScript:
|
javaScript:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
/**
|
|
||||||
* @param {number[]} nums
|
|
||||||
* @return {number[][]}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 循环内不考虑去重
|
|
||||||
var threeSum = function(nums) {
|
var threeSum = function(nums) {
|
||||||
const len = nums.length;
|
const res = [], len = nums.length
|
||||||
if(len < 3) return [];
|
// 将数组排序
|
||||||
nums.sort((a, b) => a - b);
|
nums.sort((a, b) => a - b)
|
||||||
const resSet = new Set();
|
for (let i = 0; i < len; i++) {
|
||||||
for(let i = 0; i < len - 2; i++) {
|
let l = i + 1, r = len - 1, iNum = nums[i]
|
||||||
if(nums[i] > 0) break;
|
// 数组排过序,如果第一个数大于0直接返回res
|
||||||
let l = i + 1, r = len - 1;
|
if (iNum > 0) return res
|
||||||
|
// 去重
|
||||||
|
if (iNum == nums[i - 1]) continue
|
||||||
while(l < r) {
|
while(l < r) {
|
||||||
const sum = nums[i] + nums[l] + nums[r];
|
let lNum = nums[l], rNum = nums[r], threeSum = iNum + lNum + rNum
|
||||||
if(sum < 0) { l++; continue };
|
// 三数之和小于0,则左指针向右移动
|
||||||
if(sum > 0) { r--; continue };
|
if (threeSum < 0) l++
|
||||||
resSet.add(`${nums[i]},${nums[l]},${nums[r]}`);
|
else if (threeSum > 0) r--
|
||||||
l++;
|
else {
|
||||||
r--;
|
res.push([iNum, lNum, rNum])
|
||||||
|
// 去重
|
||||||
|
while(l < r && nums[l] == nums[l + 1]){
|
||||||
|
l++
|
||||||
|
}
|
||||||
|
while(l < r && nums[r] == nums[r - 1]) {
|
||||||
|
r--
|
||||||
|
}
|
||||||
|
l++
|
||||||
|
r--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Array.from(resSet).map(i => i.split(","));
|
return res
|
||||||
};
|
|
||||||
|
|
||||||
// 去重优化
|
|
||||||
var threeSum = function(nums) {
|
|
||||||
const len = nums.length;
|
|
||||||
if(len < 3) return [];
|
|
||||||
nums.sort((a, b) => a - b);
|
|
||||||
const res = [];
|
|
||||||
for(let i = 0; i < len - 2; i++) {
|
|
||||||
if(nums[i] > 0) break;
|
|
||||||
// a去重
|
|
||||||
if(i > 0 && nums[i] === nums[i - 1]) continue;
|
|
||||||
let l = i + 1, r = len - 1;
|
|
||||||
while(l < r) {
|
|
||||||
const sum = nums[i] + nums[l] + nums[r];
|
|
||||||
if(sum < 0) { l++; continue };
|
|
||||||
if(sum > 0) { r--; continue };
|
|
||||||
res.push([nums[i], nums[l], nums[r]])
|
|
||||||
// b c 去重
|
|
||||||
while(l < r && nums[l] === nums[++l]);
|
|
||||||
while(l < r && nums[r] === nums[--r]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function threeSum(nums: number[]): number[][] {
|
||||||
|
nums.sort((a, b) => a - b);
|
||||||
|
let length = nums.length;
|
||||||
|
let left: number = 0,
|
||||||
|
right: number = length - 1;
|
||||||
|
let resArr: number[][] = [];
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
if (i > 0 && nums[i] === nums[i - 1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
left = i + 1;
|
||||||
|
right = length - 1;
|
||||||
|
while (left < right) {
|
||||||
|
let total: number = nums[i] + nums[left] + nums[right];
|
||||||
|
if (total === 0) {
|
||||||
|
resArr.push([nums[i], nums[left], nums[right]]);
|
||||||
|
left++;
|
||||||
|
right--;
|
||||||
|
while (nums[right] === nums[right + 1]) {
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
while (nums[left] === nums[left - 1]) {
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
} else if (total < 0) {
|
||||||
|
left++;
|
||||||
|
} else {
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
ruby:
|
ruby:
|
||||||
```ruby
|
```ruby
|
||||||
|
|
@ -509,5 +558,64 @@ int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C#:
|
||||||
|
```csharp
|
||||||
|
public class Solution
|
||||||
|
{
|
||||||
|
public IList<IList<int>> ThreeSum(int[] nums)
|
||||||
|
{
|
||||||
|
var result = new List<IList<int>>();
|
||||||
|
|
||||||
|
Array.Sort(nums);
|
||||||
|
|
||||||
|
for (int i = 0; i < nums.Length - 2; i++)
|
||||||
|
{
|
||||||
|
int n1 = nums[i];
|
||||||
|
|
||||||
|
if (n1 > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i > 0 && n1 == nums[i - 1])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int left = i + 1;
|
||||||
|
int right = nums.Length - 1;
|
||||||
|
|
||||||
|
while (left < right)
|
||||||
|
{
|
||||||
|
int n2 = nums[left];
|
||||||
|
int n3 = nums[right];
|
||||||
|
int sum = n1 + n2 + n3;
|
||||||
|
|
||||||
|
if (sum > 0)
|
||||||
|
{
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
else if (sum < 0)
|
||||||
|
{
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Add(new List<int> { n1, n2, n3 });
|
||||||
|
|
||||||
|
while (left < right && nums[left] == n2)
|
||||||
|
{
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (left < right && nums[right] == n3)
|
||||||
|
{
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -420,6 +420,40 @@ var letterCombinations = function(digits) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function letterCombinations(digits: string): string[] {
|
||||||
|
if (digits === '') return [];
|
||||||
|
const strMap: { [index: string]: string[] } = {
|
||||||
|
1: [],
|
||||||
|
2: ['a', 'b', 'c'],
|
||||||
|
3: ['d', 'e', 'f'],
|
||||||
|
4: ['g', 'h', 'i'],
|
||||||
|
5: ['j', 'k', 'l'],
|
||||||
|
6: ['m', 'n', 'o'],
|
||||||
|
7: ['p', 'q', 'r', 's'],
|
||||||
|
8: ['t', 'u', 'v'],
|
||||||
|
9: ['w', 'x', 'y', 'z'],
|
||||||
|
}
|
||||||
|
const resArr: string[] = [];
|
||||||
|
function backTracking(digits: string, curIndex: number, route: string[]): void {
|
||||||
|
if (curIndex === digits.length) {
|
||||||
|
resArr.push(route.join(''));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let tempArr: string[] = strMap[digits[curIndex]];
|
||||||
|
for (let i = 0, length = tempArr.length; i < length; i++) {
|
||||||
|
route.push(tempArr[i]);
|
||||||
|
backTracking(digits, curIndex + 1, route);
|
||||||
|
route.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backTracking(digits, 0, []);
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
四数之和,和[15.三数之和](https://programmercarl.com/0015.三数之和.html)是一个思路,都是使用双指针法, 基本解法就是在[15.三数之和](https://programmercarl.com/0015.三数之和.html) 的基础上再套一层for循环。
|
四数之和,和[15.三数之和](https://programmercarl.com/0015.三数之和.html)是一个思路,都是使用双指针法, 基本解法就是在[15.三数之和](https://programmercarl.com/0015.三数之和.html) 的基础上再套一层for循环。
|
||||||
|
|
||||||
但是有一些细节需要注意,例如: 不要判断`nums[k] > target` 就返回了,三数之和 可以通过 `nums[i] > 0` 就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。(大家亲自写代码就能感受出来)
|
但是有一些细节需要注意,例如: 不要判断`nums[k] > target` 就返回了,三数之和 可以通过 `nums[i] > 0` 就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。比如:数组是`[-4, -3, -2, -1]`,`target`是`-10`,不能因为`-4 > -10`而跳过。但是我们依旧可以去做剪枝,逻辑变成`nums[i] > target && (nums[i] >=0 || target >= 0)`就可以了。
|
||||||
|
|
||||||
[15.三数之和](https://programmercarl.com/0015.三数之和.html)的双指针解法是一层for循环num[i]为确定值,然后循环内有left和right下标作为双指针,找到nums[i] + nums[left] + nums[right] == 0。
|
[15.三数之和](https://programmercarl.com/0015.三数之和.html)的双指针解法是一层for循环num[i]为确定值,然后循环内有left和right下标作为双指针,找到nums[i] + nums[left] + nums[right] == 0。
|
||||||
|
|
||||||
|
|
@ -72,15 +72,20 @@ public:
|
||||||
vector<vector<int>> result;
|
vector<vector<int>> result;
|
||||||
sort(nums.begin(), nums.end());
|
sort(nums.begin(), nums.end());
|
||||||
for (int k = 0; k < nums.size(); k++) {
|
for (int k = 0; k < nums.size(); k++) {
|
||||||
// 这种剪枝是错误的,这道题目target 是任意值
|
// 剪枝处理
|
||||||
// if (nums[k] > target) {
|
if (nums[k] > target && (nums[k] >= 0 || target >= 0)) {
|
||||||
// return result;
|
break; // 这里使用break,统一通过最后的return返回
|
||||||
// }
|
}
|
||||||
// 去重
|
// 去重
|
||||||
if (k > 0 && nums[k] == nums[k - 1]) {
|
if (k > 0 && nums[k] == nums[k - 1]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int i = k + 1; i < nums.size(); i++) {
|
for (int i = k + 1; i < nums.size(); i++) {
|
||||||
|
// 2级剪枝处理
|
||||||
|
if (nums[k] + nums[i] > target && (nums[k] + nums[i] >= 0 || target >= 0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// 正确去重方法
|
// 正确去重方法
|
||||||
if (i > k + 1 && nums[i] == nums[i - 1]) {
|
if (i > k + 1 && nums[i] == nums[i - 1]) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -91,9 +96,13 @@ public:
|
||||||
// nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
|
// nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
|
||||||
if (nums[k] + nums[i] > target - (nums[left] + nums[right])) {
|
if (nums[k] + nums[i] > target - (nums[left] + nums[right])) {
|
||||||
right--;
|
right--;
|
||||||
|
// 当前元素不合适了,可以去重
|
||||||
|
while (left < right && nums[right] == nums[right + 1]) right--;
|
||||||
// nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
|
// nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
|
||||||
} else if (nums[k] + nums[i] < target - (nums[left] + nums[right])) {
|
} else if (nums[k] + nums[i] < target - (nums[left] + nums[right])) {
|
||||||
left++;
|
left++;
|
||||||
|
// 不合适,去重
|
||||||
|
while (left < right && nums[left] == nums[left - 1]) left++;
|
||||||
} else {
|
} else {
|
||||||
result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
|
result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
|
||||||
// 去重逻辑应该放在找到一个四元组之后
|
// 去重逻辑应该放在找到一个四元组之后
|
||||||
|
|
@ -212,6 +221,7 @@ class Solution(object):
|
||||||
|
|
||||||
# good thing about using python is you can use set to drop duplicates.
|
# good thing about using python is you can use set to drop duplicates.
|
||||||
ans = set()
|
ans = set()
|
||||||
|
# ans = [] # save results by list()
|
||||||
for i in range(len(nums)):
|
for i in range(len(nums)):
|
||||||
for j in range(i + 1, len(nums)):
|
for j in range(i + 1, len(nums)):
|
||||||
for k in range(j + 1, len(nums)):
|
for k in range(j + 1, len(nums)):
|
||||||
|
|
@ -220,10 +230,16 @@ class Solution(object):
|
||||||
# make sure no duplicates.
|
# make sure no duplicates.
|
||||||
count = (nums[i] == val) + (nums[j] == val) + (nums[k] == val)
|
count = (nums[i] == val) + (nums[j] == val) + (nums[k] == val)
|
||||||
if hashmap[val] > count:
|
if hashmap[val] > count:
|
||||||
ans.add(tuple(sorted([nums[i], nums[j], nums[k], val])))
|
ans_tmp = tuple(sorted([nums[i], nums[j], nums[k], val]))
|
||||||
else:
|
ans.add(ans_tmp)
|
||||||
continue
|
# Avoiding duplication in list manner but it cause time complexity increases
|
||||||
return ans
|
# if ans_tmp not in ans:
|
||||||
|
# ans.append(ans_tmp)
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
return list(ans)
|
||||||
|
# if used list() to save results, just
|
||||||
|
# return ans
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -311,7 +327,49 @@ var fourSum = function(nums, target) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function fourSum(nums: number[], target: number): number[][] {
|
||||||
|
nums.sort((a, b) => a - b);
|
||||||
|
let first: number = 0,
|
||||||
|
second: number,
|
||||||
|
third: number,
|
||||||
|
fourth: number;
|
||||||
|
let length: number = nums.length;
|
||||||
|
let resArr: number[][] = [];
|
||||||
|
for (; first < length; first++) {
|
||||||
|
if (first > 0 && nums[first] === nums[first - 1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (second = first + 1; second < length; second++) {
|
||||||
|
if ((second - first) > 1 && nums[second] === nums[second - 1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
third = second + 1;
|
||||||
|
fourth = length - 1;
|
||||||
|
while (third < fourth) {
|
||||||
|
let total: number = nums[first] + nums[second] + nums[third] + nums[fourth];
|
||||||
|
if (total === target) {
|
||||||
|
resArr.push([nums[first], nums[second], nums[third], nums[fourth]]);
|
||||||
|
third++;
|
||||||
|
fourth--;
|
||||||
|
while (nums[third] === nums[third - 1]) third++;
|
||||||
|
while (nums[fourth] === nums[fourth + 1]) fourth--;
|
||||||
|
} else if (total < target) {
|
||||||
|
third++;
|
||||||
|
} else {
|
||||||
|
fourth--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
PHP:
|
PHP:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
class Solution {
|
class Solution {
|
||||||
/**
|
/**
|
||||||
|
|
@ -403,5 +461,67 @@ func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C#:
|
||||||
|
```csharp
|
||||||
|
public class Solution
|
||||||
|
{
|
||||||
|
public IList<IList<int>> FourSum(int[] nums, int target)
|
||||||
|
{
|
||||||
|
var result = new List<IList<int>>();
|
||||||
|
|
||||||
|
Array.Sort(nums);
|
||||||
|
|
||||||
|
for (int i = 0; i < nums.Length - 3; i++)
|
||||||
|
{
|
||||||
|
int n1 = nums[i];
|
||||||
|
if (i > 0 && n1 == nums[i - 1])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int j = i + 1; j < nums.Length - 2; j++)
|
||||||
|
{
|
||||||
|
int n2 = nums[j];
|
||||||
|
if (j > i + 1 && n2 == nums[j - 1])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int left = j + 1;
|
||||||
|
int right = nums.Length - 1;
|
||||||
|
|
||||||
|
while (left < right)
|
||||||
|
{
|
||||||
|
int n3 = nums[left];
|
||||||
|
int n4 = nums[right];
|
||||||
|
int sum = n1 + n2 + n3 + n4;
|
||||||
|
|
||||||
|
if (sum > target)
|
||||||
|
{
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
else if (sum < target)
|
||||||
|
{
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Add(new List<int> { n1, n2, n3, n4 });
|
||||||
|
|
||||||
|
while (left < right && nums[left] == n3)
|
||||||
|
{
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (left < right && nums[right] == n4)
|
||||||
|
{
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
技巧性的东西没有固定的学习方法,还是要多看多练,自己总灵活运用了。
|
技巧性的东西没有固定的学习方法,还是要多看多练,自己灵活运用了。
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
@ -159,7 +159,7 @@ class Solution {
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python3
|
```python
|
||||||
# 方法一,仅使用栈,更省空间
|
# 方法一,仅使用栈,更省空间
|
||||||
class Solution:
|
class Solution:
|
||||||
def isValid(self, s: str) -> bool:
|
def isValid(self, s: str) -> bool:
|
||||||
|
|
@ -180,7 +180,7 @@ class Solution:
|
||||||
return True if not stack else False
|
return True if not stack else False
|
||||||
```
|
```
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
# 方法二,使用字典
|
# 方法二,使用字典
|
||||||
class Solution:
|
class Solution:
|
||||||
def isValid(self, s: str) -> bool:
|
def isValid(self, s: str) -> bool:
|
||||||
|
|
@ -283,8 +283,60 @@ var isValid = function(s) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
版本一:普通版
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function isValid(s: string): boolean {
|
||||||
|
let helperStack: string[] = [];
|
||||||
|
for (let i = 0, length = s.length; i < length; i++) {
|
||||||
|
let x: string = s[i];
|
||||||
|
switch (x) {
|
||||||
|
case '(':
|
||||||
|
helperStack.push(')');
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
helperStack.push(']');
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
helperStack.push('}');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (helperStack.pop() !== x) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return helperStack.length === 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
版本二:优化版
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function isValid(s: string): boolean {
|
||||||
|
type BracketMap = {
|
||||||
|
[index: string]: string;
|
||||||
|
}
|
||||||
|
let helperStack: string[] = [];
|
||||||
|
let bracketMap: BracketMap = {
|
||||||
|
'(': ')',
|
||||||
|
'[': ']',
|
||||||
|
'{': '}'
|
||||||
|
}
|
||||||
|
for (let i of s) {
|
||||||
|
if (bracketMap.hasOwnProperty(i)) {
|
||||||
|
helperStack.push(bracketMap[i]);
|
||||||
|
} else if (i !== helperStack.pop()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return helperStack.length === 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
Swift
|
Swift
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func isValid(_ s: String) -> Bool {
|
func isValid(_ s: String) -> Bool {
|
||||||
var stack = [String.Element]()
|
var stack = [String.Element]()
|
||||||
|
|
|
||||||
|
|
@ -254,32 +254,20 @@ TypeScript:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
function swapPairs(head: ListNode | null): ListNode | null {
|
function swapPairs(head: ListNode | null): ListNode | null {
|
||||||
/**
|
const dummyHead: ListNode = new ListNode(0, head);
|
||||||
* 初始状态:
|
let cur: ListNode = dummyHead;
|
||||||
* curNode -> node1 -> node2 -> tmepNode
|
while(cur.next !== null && cur.next.next !== null) {
|
||||||
* 转换过程:
|
const tem: ListNode = cur.next;
|
||||||
* curNode -> node2
|
const tem1: ListNode = cur.next.next.next;
|
||||||
* curNode -> node2 -> node1
|
|
||||||
* curNode -> node2 -> node1 -> tempNode
|
cur.next = cur.next.next; // step 1
|
||||||
* curNode = node1
|
cur.next.next = tem; // step 2
|
||||||
*/
|
cur.next.next.next = tem1; // step 3
|
||||||
let retNode: ListNode | null = new ListNode(0, head),
|
|
||||||
curNode: ListNode | null = retNode,
|
cur = cur.next.next;
|
||||||
node1: ListNode | null = null,
|
}
|
||||||
node2: ListNode | null = null,
|
return dummyHead.next;
|
||||||
tempNode: ListNode | null = null;
|
}
|
||||||
|
|
||||||
while (curNode && curNode.next && curNode.next.next) {
|
|
||||||
node1 = curNode.next;
|
|
||||||
node2 = curNode.next.next;
|
|
||||||
tempNode = node2.next;
|
|
||||||
curNode.next = node2;
|
|
||||||
node2.next = node1;
|
|
||||||
node1.next = tempNode;
|
|
||||||
curNode = node1;
|
|
||||||
}
|
|
||||||
return retNode.next;
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Kotlin:
|
Kotlin:
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
|
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
|
||||||
|
|
||||||
不要使用额外的数组空间,你必须仅使用 $O(1)$ 额外空间并**原地**修改输入数组。
|
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并**原地**修改输入数组。
|
||||||
|
|
||||||
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
|
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
|
||||||
|
|
||||||
|
|
@ -68,8 +68,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n^2)$
|
* 时间复杂度:O(n^2)
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
### 双指针法
|
### 双指针法
|
||||||
|
|
||||||
|
|
@ -101,11 +101,42 @@ public:
|
||||||
```
|
```
|
||||||
注意这些实现方法并没有改变元素的相对位置!
|
注意这些实现方法并没有改变元素的相对位置!
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
旧文链接:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)
|
旧文链接:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)
|
||||||
|
|
||||||
|
```CPP
|
||||||
|
/**
|
||||||
|
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
|
||||||
|
* 时间复杂度:O(n)
|
||||||
|
* 空间复杂度:O(1)
|
||||||
|
*/
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int removeElement(vector<int>& nums, int val) {
|
||||||
|
int leftIndex = 0;
|
||||||
|
int rightIndex = nums.size() - 1;
|
||||||
|
while (leftIndex <= rightIndex) {
|
||||||
|
// 找左边等于val的元素
|
||||||
|
while (leftIndex <= rightIndex && nums[leftIndex] != val){
|
||||||
|
++leftIndex;
|
||||||
|
}
|
||||||
|
// 找右边不等于val的元素
|
||||||
|
while (leftIndex <= rightIndex && nums[rightIndex] == val) {
|
||||||
|
-- rightIndex;
|
||||||
|
}
|
||||||
|
// 将右边不等于val的元素覆盖左边等于val的元素
|
||||||
|
if (leftIndex < rightIndex) {
|
||||||
|
nums[leftIndex++] = nums[rightIndex--];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return leftIndex; // leftIndex一定指向了最终数组末尾的下一个元素
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 相关题目推荐
|
## 相关题目推荐
|
||||||
|
|
||||||
* 26.删除排序数组中的重复项
|
* 26.删除排序数组中的重复项
|
||||||
|
|
@ -142,7 +173,7 @@ class Solution {
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
"""双指针法
|
"""双指针法
|
||||||
时间复杂度:O(n)
|
时间复杂度:O(n)
|
||||||
|
|
@ -250,10 +281,8 @@ func removeElement(_ nums: inout [Int], _ val: Int) -> Int {
|
||||||
|
|
||||||
for fastIndex in 0..<nums.count {
|
for fastIndex in 0..<nums.count {
|
||||||
if val != nums[fastIndex] {
|
if val != nums[fastIndex] {
|
||||||
if slowIndex != fastIndex {
|
|
||||||
nums[slowIndex] = nums[fastIndex]
|
nums[slowIndex] = nums[fastIndex]
|
||||||
}
|
slowIndex += 1
|
||||||
slowIndex += 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return slowIndex
|
return slowIndex
|
||||||
|
|
|
||||||
|
|
@ -229,9 +229,9 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减
|
||||||
|
|
||||||
# 时间复杂度分析
|
# 时间复杂度分析
|
||||||
|
|
||||||
其中n为文本串长度,m为模式串长度,因为在匹配的过程中,根据前缀表不断调整匹配的位置,可以看出匹配的过程是$O(n)$,之前还要单独生成next数组,时间复杂度是$O(m)$。所以整个KMP算法的时间复杂度是$O(n+m)$的。
|
其中n为文本串长度,m为模式串长度,因为在匹配的过程中,根据前缀表不断调整匹配的位置,可以看出匹配的过程是O(n),之前还要单独生成next数组,时间复杂度是O(m)。所以整个KMP算法的时间复杂度是O(n+m)的。
|
||||||
|
|
||||||
暴力的解法显而易见是$O(n × m)$,所以**KMP在字符串匹配中极大的提高的搜索的效率。**
|
暴力的解法显而易见是O(n × m),所以**KMP在字符串匹配中极大的提高的搜索的效率。**
|
||||||
|
|
||||||
为了和力扣题目28.实现strStr保持一致,方便大家理解,以下文章统称haystack为文本串, needle为模式串。
|
为了和力扣题目28.实现strStr保持一致,方便大家理解,以下文章统称haystack为文本串, needle为模式串。
|
||||||
|
|
||||||
|
|
@ -255,11 +255,11 @@ void getNext(int* next, const string& s)
|
||||||
|
|
||||||
1. 初始化:
|
1. 初始化:
|
||||||
|
|
||||||
定义两个指针i和j,j指向前缀起始位置,i指向后缀起始位置。
|
定义两个指针i和j,j指向前缀末尾位置,i指向后缀末尾位置。
|
||||||
|
|
||||||
然后还要对next数组进行初始化赋值,如下:
|
然后还要对next数组进行初始化赋值,如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
int j = -1;
|
int j = -1;
|
||||||
next[0] = j;
|
next[0] = j;
|
||||||
```
|
```
|
||||||
|
|
@ -278,8 +278,8 @@ next[i] 表示 i(包括i)之前最长相等的前后缀长度(其实就是
|
||||||
|
|
||||||
所以遍历模式串s的循环下标i 要从 1开始,代码如下:
|
所以遍历模式串s的循环下标i 要从 1开始,代码如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
for(int i = 1; i < s.size(); i++) {
|
for (int i = 1; i < s.size(); i++) {
|
||||||
```
|
```
|
||||||
|
|
||||||
如果 s[i] 与 s[j+1]不相同,也就是遇到 前后缀末尾不相同的情况,就要向前回退。
|
如果 s[i] 与 s[j+1]不相同,也就是遇到 前后缀末尾不相同的情况,就要向前回退。
|
||||||
|
|
@ -292,7 +292,7 @@ next[j]就是记录着j(包括j)之前的子串的相同前后缀的长度
|
||||||
|
|
||||||
所以,处理前后缀不相同的情况代码如下:
|
所以,处理前后缀不相同的情况代码如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
|
while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
|
||||||
j = next[j]; // 向前回退
|
j = next[j]; // 向前回退
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +300,7 @@ while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
|
||||||
|
|
||||||
3. 处理前后缀相同的情况
|
3. 处理前后缀相同的情况
|
||||||
|
|
||||||
如果s[i] 与 s[j + 1] 相同,那么就同时向后移动i 和j 说明找到了相同的前后缀,同时还要将j(前缀的长度)赋给next[i], 因为next[i]要记录相同前后缀的长度。
|
如果 s[i] 与 s[j + 1] 相同,那么就同时向后移动i 和j 说明找到了相同的前后缀,同时还要将j(前缀的长度)赋给next[i], 因为next[i]要记录相同前后缀的长度。
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
|
|
@ -346,7 +346,7 @@ void getNext(int* next, const string& s){
|
||||||
|
|
||||||
i就从0开始,遍历文本串,代码如下:
|
i就从0开始,遍历文本串,代码如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
for (int i = 0; i < s.size(); i++)
|
for (int i = 0; i < s.size(); i++)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -356,7 +356,7 @@ for (int i = 0; i < s.size(); i++)
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
while(j >= 0 && s[i] != t[j + 1]) {
|
while(j >= 0 && s[i] != t[j + 1]) {
|
||||||
j = next[j];
|
j = next[j];
|
||||||
}
|
}
|
||||||
|
|
@ -364,7 +364,7 @@ while(j >= 0 && s[i] != t[j + 1]) {
|
||||||
|
|
||||||
如果 s[i] 与 t[j + 1] 相同,那么i 和 j 同时向后移动, 代码如下:
|
如果 s[i] 与 t[j + 1] 相同,那么i 和 j 同时向后移动, 代码如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
if (s[i] == t[j + 1]) {
|
if (s[i] == t[j + 1]) {
|
||||||
j++; // i的增加在for循环里
|
j++; // i的增加在for循环里
|
||||||
}
|
}
|
||||||
|
|
@ -376,7 +376,7 @@ if (s[i] == t[j + 1]) {
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
if (j == (t.size() - 1) ) {
|
if (j == (t.size() - 1) ) {
|
||||||
return (i - t.size() + 1);
|
return (i - t.size() + 1);
|
||||||
}
|
}
|
||||||
|
|
@ -929,6 +929,83 @@ var strStr = function (haystack, needle) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript版本:
|
||||||
|
|
||||||
|
> 前缀表统一减一
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function strStr(haystack: string, needle: string): number {
|
||||||
|
function getNext(str: string): number[] {
|
||||||
|
let next: number[] = [];
|
||||||
|
let j: number = -1;
|
||||||
|
next[0] = j;
|
||||||
|
for (let i = 1, length = str.length; i < length; i++) {
|
||||||
|
while (j >= 0 && str[i] !== str[j + 1]) {
|
||||||
|
j = next[j];
|
||||||
|
}
|
||||||
|
if (str[i] === str[j + 1]) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
next[i] = j;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
if (needle.length === 0) return 0;
|
||||||
|
let next: number[] = getNext(needle);
|
||||||
|
let j: number = -1;
|
||||||
|
for (let i = 0, length = haystack.length; i < length; i++) {
|
||||||
|
while (j >= 0 && haystack[i] !== needle[j + 1]) {
|
||||||
|
j = next[j];
|
||||||
|
}
|
||||||
|
if (haystack[i] === needle[j + 1]) {
|
||||||
|
if (j === needle.length - 2) {
|
||||||
|
return i - j - 1;
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 前缀表不减一
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 不减一版本
|
||||||
|
function strStr(haystack: string, needle: string): number {
|
||||||
|
function getNext(str: string): number[] {
|
||||||
|
let next: number[] = [];
|
||||||
|
let j: number = 0;
|
||||||
|
next[0] = j;
|
||||||
|
for (let i = 1, length = str.length; i < length; i++) {
|
||||||
|
while (j > 0 && str[i] !== str[j]) {
|
||||||
|
j = next[j - 1];
|
||||||
|
}
|
||||||
|
if (str[i] === str[j]) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
next[i] = j;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
if (needle.length === 0) return 0;
|
||||||
|
let next: number[] = getNext(needle);
|
||||||
|
let j: number = 0;
|
||||||
|
for (let i = 0, length = haystack.length; i < length; i++) {
|
||||||
|
while (j > 0 && haystack[i] !== needle[j]) {
|
||||||
|
j = next[j - 1];
|
||||||
|
}
|
||||||
|
if (haystack[i] === needle[j]) {
|
||||||
|
if (j === needle.length - 1) {
|
||||||
|
return i - j;
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Swift 版本
|
Swift 版本
|
||||||
|
|
||||||
> 前缀表统一减一
|
> 前缀表统一减一
|
||||||
|
|
@ -982,5 +1059,112 @@ func getNext(_ next: inout [Int], needle: [Character]) {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 前缀表右移
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func strStr(_ haystack: String, _ needle: String) -> Int {
|
||||||
|
|
||||||
|
let s = Array(haystack), p = Array(needle)
|
||||||
|
guard p.count != 0 else { return 0 }
|
||||||
|
|
||||||
|
var j = 0
|
||||||
|
var next = [Int].init(repeating: 0, count: p.count)
|
||||||
|
getNext(&next, p)
|
||||||
|
|
||||||
|
for i in 0 ..< s.count {
|
||||||
|
|
||||||
|
while j > 0 && s[i] != p[j] {
|
||||||
|
j = next[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
if s[i] == p[j] {
|
||||||
|
j += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if j == p.count {
|
||||||
|
return i - p.count + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 前缀表后移一位,首位用 -1 填充
|
||||||
|
func getNext(_ next: inout [Int], _ needle: [Character]) {
|
||||||
|
|
||||||
|
guard needle.count > 1 else { return }
|
||||||
|
|
||||||
|
var j = 0
|
||||||
|
next[0] = j
|
||||||
|
|
||||||
|
for i in 1 ..< needle.count-1 {
|
||||||
|
|
||||||
|
while j > 0 && needle[i] != needle[j] {
|
||||||
|
j = next[j-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if needle[i] == needle[j] {
|
||||||
|
j += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
next[i] = j
|
||||||
|
}
|
||||||
|
next.removeLast()
|
||||||
|
next.insert(-1, at: 0)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 前缀表统一不减一
|
||||||
|
```swift
|
||||||
|
|
||||||
|
func strStr(_ haystack: String, _ needle: String) -> Int {
|
||||||
|
|
||||||
|
let s = Array(haystack), p = Array(needle)
|
||||||
|
guard p.count != 0 else { return 0 }
|
||||||
|
|
||||||
|
var j = 0
|
||||||
|
var next = [Int](repeating: 0, count: needle.count)
|
||||||
|
// KMP
|
||||||
|
getNext(&next, needle: p)
|
||||||
|
|
||||||
|
for i in 0 ..< s.count {
|
||||||
|
while j > 0 && s[i] != p[j] {
|
||||||
|
j = next[j-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if s[i] == p[j] {
|
||||||
|
j += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if j == p.count {
|
||||||
|
return i - p.count + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
//前缀表
|
||||||
|
func getNext(_ next: inout [Int], needle: [Character]) {
|
||||||
|
|
||||||
|
var j = 0
|
||||||
|
next[0] = j
|
||||||
|
|
||||||
|
for i in 1 ..< needle.count {
|
||||||
|
|
||||||
|
while j>0 && needle[i] != needle[j] {
|
||||||
|
j = next[j-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if needle[i] == needle[j] {
|
||||||
|
j += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
next[i] = j
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ public:
|
||||||
for (int j = nums.size() - 1; j > i; j--) {
|
for (int j = nums.size() - 1; j > i; j--) {
|
||||||
if (nums[j] > nums[i]) {
|
if (nums[j] > nums[i]) {
|
||||||
swap(nums[j], nums[i]);
|
swap(nums[j], nums[i]);
|
||||||
sort(nums.begin() + i + 1, nums.end());
|
reverse(nums.begin() + i + 1, nums.end());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ func searchInsert(nums []int, target int) int {
|
||||||
```
|
```
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def searchInsert(self, nums: List[int], target: int) -> int:
|
def searchInsert(self, nums: List[int], target: int) -> int:
|
||||||
left, right = 0, len(nums) - 1
|
left, right = 0, len(nums) - 1
|
||||||
|
|
@ -318,6 +318,31 @@ func searchInsert(_ nums: [Int], _ target: Int) -> Int {
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### PHP
|
||||||
|
|
||||||
|
```php
|
||||||
|
// 二分法(1):[左闭右闭]
|
||||||
|
function searchInsert($nums, $target)
|
||||||
|
{
|
||||||
|
$n = count($nums);
|
||||||
|
$l = 0;
|
||||||
|
$r = $n - 1;
|
||||||
|
while ($l <= $r) {
|
||||||
|
$mid = floor(($l + $r) / 2);
|
||||||
|
if ($nums[$mid] > $target) {
|
||||||
|
// 下次搜索在左区间:[$l,$mid-1]
|
||||||
|
$r = $mid - 1;
|
||||||
|
} else if ($nums[$mid] < $target) {
|
||||||
|
// 下次搜索在右区间:[$mid+1,$r]
|
||||||
|
$l = $mid + 1;
|
||||||
|
} else {
|
||||||
|
// 命中返回
|
||||||
|
return $mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $r + 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
||||||
|
|
@ -439,6 +439,55 @@ var solveSudoku = function(board) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
Do not return anything, modify board in-place instead.
|
||||||
|
*/
|
||||||
|
function isValid(col: number, row: number, val: string, board: string[][]): boolean {
|
||||||
|
let n: number = board.length;
|
||||||
|
// 列向检查
|
||||||
|
for (let rowIndex = 0; rowIndex < n; rowIndex++) {
|
||||||
|
if (board[rowIndex][col] === val) return false;
|
||||||
|
}
|
||||||
|
// 横向检查
|
||||||
|
for (let colIndex = 0; colIndex < n; colIndex++) {
|
||||||
|
if (board[row][colIndex] === val) return false;
|
||||||
|
}
|
||||||
|
// 九宫格检查
|
||||||
|
const startX = Math.floor(col / 3) * 3;
|
||||||
|
const startY = Math.floor(row / 3) * 3;
|
||||||
|
for (let rowIndex = startY; rowIndex < startY + 3; rowIndex++) {
|
||||||
|
for (let colIndex = startX; colIndex < startX + 3; colIndex++) {
|
||||||
|
if (board[rowIndex][colIndex] === val) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function solveSudoku(board: string[][]): void {
|
||||||
|
let n: number = 9;
|
||||||
|
backTracking(n, board);
|
||||||
|
function backTracking(n: number, board: string[][]): boolean {
|
||||||
|
for (let row = 0; row < n; row++) {
|
||||||
|
for (let col = 0; col < n; col++) {
|
||||||
|
if (board[row][col] === '.') {
|
||||||
|
for (let i = 1; i <= n; i++) {
|
||||||
|
if (isValid(col, row, String(i), board)) {
|
||||||
|
board[row][col] = String(i);
|
||||||
|
if (backTracking(n, board) === true) return true;
|
||||||
|
board[row][col] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### C
|
### C
|
||||||
|
|
||||||
```C
|
```C
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ class Solution {
|
||||||
|
|
||||||
## Python
|
## Python
|
||||||
**回溯**
|
**回溯**
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.path = []
|
self.path = []
|
||||||
|
|
@ -296,7 +296,7 @@ class Solution:
|
||||||
self.path.pop() # 回溯
|
self.path.pop() # 回溯
|
||||||
```
|
```
|
||||||
**剪枝回溯**
|
**剪枝回溯**
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.path = []
|
self.path = []
|
||||||
|
|
@ -370,18 +370,17 @@ func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int)
|
||||||
```js
|
```js
|
||||||
var combinationSum = function(candidates, target) {
|
var combinationSum = function(candidates, target) {
|
||||||
const res = [], path = [];
|
const res = [], path = [];
|
||||||
candidates.sort(); // 排序
|
candidates.sort((a,b)=>a-b); // 排序
|
||||||
backtracking(0, 0);
|
backtracking(0, 0);
|
||||||
return res;
|
return res;
|
||||||
function backtracking(j, sum) {
|
function backtracking(j, sum) {
|
||||||
if (sum > target) return;
|
|
||||||
if (sum === target) {
|
if (sum === target) {
|
||||||
res.push(Array.from(path));
|
res.push(Array.from(path));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(let i = j; i < candidates.length; i++ ) {
|
for(let i = j; i < candidates.length; i++ ) {
|
||||||
const n = candidates[i];
|
const n = candidates[i];
|
||||||
if(n > target - sum) continue;
|
if(n > target - sum) break;
|
||||||
path.push(n);
|
path.push(n);
|
||||||
sum += n;
|
sum += n;
|
||||||
backtracking(i, sum);
|
backtracking(i, sum);
|
||||||
|
|
@ -392,7 +391,34 @@ var combinationSum = function(candidates, target) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function combinationSum(candidates: number[], target: number): number[][] {
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
function backTracking(
|
||||||
|
candidates: number[], target: number,
|
||||||
|
startIndex: number, route: number[], curSum: number
|
||||||
|
): void {
|
||||||
|
if (curSum > target) return;
|
||||||
|
if (curSum === target) {
|
||||||
|
resArr.push(route.slice());
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (let i = startIndex, length = candidates.length; i < length; i++) {
|
||||||
|
let tempVal: number = candidates[i];
|
||||||
|
route.push(tempVal);
|
||||||
|
backTracking(candidates, target, i, route, curSum + tempVal);
|
||||||
|
route.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backTracking(candidates, target, 0, [], 0);
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int* path;
|
int* path;
|
||||||
int pathTop;
|
int pathTop;
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,7 @@ class Solution {
|
||||||
|
|
||||||
## Python
|
## Python
|
||||||
**回溯+巧妙去重(省去使用used**
|
**回溯+巧妙去重(省去使用used**
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.paths = []
|
self.paths = []
|
||||||
|
|
@ -374,7 +374,7 @@ class Solution:
|
||||||
sum_ -= candidates[i] # 回溯,为了下一轮for loop
|
sum_ -= candidates[i] # 回溯,为了下一轮for loop
|
||||||
```
|
```
|
||||||
**回溯+去重(使用used)**
|
**回溯+去重(使用used)**
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.paths = []
|
self.paths = []
|
||||||
|
|
@ -508,22 +508,27 @@ func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int)
|
||||||
*/
|
*/
|
||||||
var combinationSum2 = function(candidates, target) {
|
var combinationSum2 = function(candidates, target) {
|
||||||
const res = []; path = [], len = candidates.length;
|
const res = []; path = [], len = candidates.length;
|
||||||
candidates.sort();
|
candidates.sort((a,b)=>a-b);
|
||||||
backtracking(0, 0);
|
backtracking(0, 0);
|
||||||
return res;
|
return res;
|
||||||
function backtracking(sum, i) {
|
function backtracking(sum, i) {
|
||||||
if (sum > target) return;
|
|
||||||
if (sum === target) {
|
if (sum === target) {
|
||||||
res.push(Array.from(path));
|
res.push(Array.from(path));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let f = -1;
|
|
||||||
for(let j = i; j < len; j++) {
|
for(let j = i; j < len; j++) {
|
||||||
const n = candidates[j];
|
const n = candidates[j];
|
||||||
if(n > target - sum || n === f) continue;
|
if(j > i && candidates[j] === candidates[j-1]){
|
||||||
|
//若当前元素和前一个元素相等
|
||||||
|
//则本次循环结束,防止出现重复组合
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//如果当前元素值大于目标值-总和的值
|
||||||
|
//由于数组已排序,那么该元素之后的元素必定不满足条件
|
||||||
|
//直接终止当前层的递归
|
||||||
|
if(n > target - sum) break;
|
||||||
path.push(n);
|
path.push(n);
|
||||||
sum += n;
|
sum += n;
|
||||||
f = n;
|
|
||||||
backtracking(sum, j + 1);
|
backtracking(sum, j + 1);
|
||||||
path.pop();
|
path.pop();
|
||||||
sum -= n;
|
sum -= n;
|
||||||
|
|
@ -532,6 +537,7 @@ var combinationSum2 = function(candidates, target) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
**使用used去重**
|
**使用used去重**
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var combinationSum2 = function(candidates, target) {
|
var combinationSum2 = function(candidates, target) {
|
||||||
let res = [];
|
let res = [];
|
||||||
|
|
@ -562,6 +568,37 @@ var combinationSum2 = function(candidates, target) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function combinationSum2(candidates: number[], target: number): number[][] {
|
||||||
|
candidates.sort((a, b) => a - b);
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
function backTracking(
|
||||||
|
candidates: number[], target: number,
|
||||||
|
curSum: number, startIndex: number, route: number[]
|
||||||
|
) {
|
||||||
|
if (curSum > target) return;
|
||||||
|
if (curSum === target) {
|
||||||
|
resArr.push(route.slice());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = startIndex, length = candidates.length; i < length; i++) {
|
||||||
|
if (i > startIndex && candidates[i] === candidates[i - 1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let tempVal: number = candidates[i];
|
||||||
|
route.push(tempVal);
|
||||||
|
backTracking(candidates, target, curSum + tempVal, i + 1, route);
|
||||||
|
route.pop();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backTracking(candidates, target, 0, 0, []);
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
|
||||||
|
|
@ -129,8 +129,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
因为每次遍历列的时候,还要向两边寻找最高的列,所以时间复杂度为$O(n^2)$。
|
因为每次遍历列的时候,还要向两边寻找最高的列,所以时间复杂度为O(n^2)。
|
||||||
空间复杂度为$O(1)$。
|
空间复杂度为O(1)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -365,7 +365,7 @@ public:
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
Java:
|
### Java:
|
||||||
|
|
||||||
双指针法
|
双指针法
|
||||||
```java
|
```java
|
||||||
|
|
@ -468,7 +468,7 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
### Python:
|
||||||
|
|
||||||
双指针法
|
双指针法
|
||||||
```python3
|
```python3
|
||||||
|
|
@ -491,7 +491,7 @@ class Solution:
|
||||||
return res
|
return res
|
||||||
```
|
```
|
||||||
动态规划
|
动态规划
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def trap(self, height: List[int]) -> int:
|
def trap(self, height: List[int]) -> int:
|
||||||
leftheight, rightheight = [0]*len(height), [0]*len(height)
|
leftheight, rightheight = [0]*len(height), [0]*len(height)
|
||||||
|
|
@ -575,7 +575,7 @@ class Solution:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
### Go
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func trap(height []int) int {
|
func trap(height []int) int {
|
||||||
|
|
@ -642,7 +642,7 @@ func min(a,b int)int{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
JavaScript:
|
### JavaScript:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
//双指针
|
//双指针
|
||||||
|
|
@ -744,7 +744,7 @@ var trap = function(height) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
C:
|
### C:
|
||||||
|
|
||||||
一种更简便的双指针方法:
|
一种更简便的双指针方法:
|
||||||
|
|
||||||
|
|
@ -779,8 +779,8 @@ int trap(int* height, int heightSize) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度 $O(n)$
|
* 时间复杂度 O(n)
|
||||||
* 空间复杂度 $O(1)$
|
* 空间复杂度 O(1)
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ public:
|
||||||
|
|
||||||
### Java
|
### Java
|
||||||
```Java
|
```Java
|
||||||
|
// 版本一
|
||||||
class Solution {
|
class Solution {
|
||||||
public int jump(int[] nums) {
|
public int jump(int[] nums) {
|
||||||
if (nums == null || nums.length == 0 || nums.length == 1) {
|
if (nums == null || nums.length == 0 || nums.length == 1) {
|
||||||
|
|
@ -172,7 +173,30 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 版本二
|
||||||
|
class Solution {
|
||||||
|
public int jump(int[] nums) {
|
||||||
|
int result = 0;
|
||||||
|
// 当前覆盖的最远距离下标
|
||||||
|
int end = 0;
|
||||||
|
// 下一步覆盖的最远距离下标
|
||||||
|
int temp = 0;
|
||||||
|
for (int i = 0; i <= end && end < nums.length - 1; ++i) {
|
||||||
|
temp = Math.max(temp, i + nums[i]);
|
||||||
|
// 可达位置的改变次数就是跳跃次数
|
||||||
|
if (i == end) {
|
||||||
|
end = temp;
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def jump(self, nums: List[int]) -> int:
|
def jump(self, nums: List[int]) -> int:
|
||||||
|
|
@ -226,6 +250,27 @@ var jump = function(nums) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function jump(nums: number[]): number {
|
||||||
|
const length: number = nums.length;
|
||||||
|
let curFarthestIndex: number = 0,
|
||||||
|
nextFarthestIndex: number = 0;
|
||||||
|
let curIndex: number = 0;
|
||||||
|
let stepNum: number = 0;
|
||||||
|
while (curIndex < length - 1) {
|
||||||
|
nextFarthestIndex = Math.max(nextFarthestIndex, curIndex + nums[curIndex]);
|
||||||
|
if (curIndex === curFarthestIndex) {
|
||||||
|
curFarthestIndex = nextFarthestIndex;
|
||||||
|
stepNum++;
|
||||||
|
}
|
||||||
|
curIndex++;
|
||||||
|
}
|
||||||
|
return stepNum;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ class Solution:
|
||||||
usage_list[i] = False
|
usage_list[i] = False
|
||||||
```
|
```
|
||||||
**回溯+丢掉usage_list**
|
**回溯+丢掉usage_list**
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.path = []
|
self.path = []
|
||||||
|
|
@ -331,6 +331,34 @@ var permute = function(nums) {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function permute(nums: number[]): number[][] {
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
const helperSet: Set<number> = new Set();
|
||||||
|
backTracking(nums, []);
|
||||||
|
return resArr;
|
||||||
|
function backTracking(nums: number[], route: number[]): void {
|
||||||
|
if (route.length === nums.length) {
|
||||||
|
resArr.push(route.slice());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let tempVal: number;
|
||||||
|
for (let i = 0, length = nums.length; i < length; i++) {
|
||||||
|
tempVal = nums[i];
|
||||||
|
if (!helperSet.has(tempVal)) {
|
||||||
|
route.push(tempVal);
|
||||||
|
helperSet.add(tempVal);
|
||||||
|
backTracking(nums, route);
|
||||||
|
route.pop();
|
||||||
|
helperSet.delete(tempVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### C
|
### C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,34 @@ var permuteUnique = function (nums) {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function permuteUnique(nums: number[]): number[][] {
|
||||||
|
nums.sort((a, b) => a - b);
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
const usedArr: boolean[] = new Array(nums.length).fill(false);
|
||||||
|
backTracking(nums, []);
|
||||||
|
return resArr;
|
||||||
|
function backTracking(nums: number[], route: number[]): void {
|
||||||
|
if (route.length === nums.length) {
|
||||||
|
resArr.push(route.slice());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0, length = nums.length; i < length; i++) {
|
||||||
|
if (i > 0 && nums[i] === nums[i - 1] && usedArr[i - 1] === false) continue;
|
||||||
|
if (usedArr[i] === false) {
|
||||||
|
route.push(nums[i]);
|
||||||
|
usedArr[i] = true;
|
||||||
|
backTracking(nums, route);
|
||||||
|
usedArr[i] = false;
|
||||||
|
route.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### Swift
|
### Swift
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,6 @@ for (int col = 0; col < n; col++) {
|
||||||
|
|
||||||
```CPP
|
```CPP
|
||||||
bool isValid(int row, int col, vector<string>& chessboard, int n) {
|
bool isValid(int row, int col, vector<string>& chessboard, int n) {
|
||||||
int count = 0;
|
|
||||||
// 检查列
|
// 检查列
|
||||||
for (int i = 0; i < row; i++) { // 这是一个剪枝
|
for (int i = 0; i < row; i++) { // 这是一个剪枝
|
||||||
if (chessboard[i][col] == 'Q') {
|
if (chessboard[i][col] == 'Q') {
|
||||||
|
|
@ -178,7 +177,6 @@ void backtracking(int n, int row, vector<string>& chessboard) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool isValid(int row, int col, vector<string>& chessboard, int n) {
|
bool isValid(int row, int col, vector<string>& chessboard, int n) {
|
||||||
int count = 0;
|
|
||||||
// 检查列
|
// 检查列
|
||||||
for (int i = 0; i < row; i++) { // 这是一个剪枝
|
for (int i = 0; i < row; i++) { // 这是一个剪枝
|
||||||
if (chessboard[i][col] == 'Q') {
|
if (chessboard[i][col] == 'Q') {
|
||||||
|
|
@ -346,69 +344,56 @@ class Solution {
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
```Go
|
```Go
|
||||||
import "strings"
|
|
||||||
var res [][]string
|
|
||||||
|
|
||||||
func isValid(board [][]string, row, col int) (res bool){
|
|
||||||
n := len(board)
|
|
||||||
for i:=0; i < row; i++ {
|
|
||||||
if board[i][col] == "Q" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := 0; i < n; i++{
|
|
||||||
if board[row][i] == "Q" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i ,j := row, col; i >= 0 && j >=0 ; i, j = i - 1, j- 1{
|
|
||||||
if board[i][j] == "Q"{
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i, j := row, col; i >=0 && j < n; i,j = i-1, j+1 {
|
|
||||||
if board[i][j] == "Q" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func backtrack(board [][]string, row int) {
|
|
||||||
size := len(board)
|
|
||||||
if row == size{
|
|
||||||
temp := make([]string, size)
|
|
||||||
for i := 0; i<size;i++{
|
|
||||||
temp[i] = strings.Join(board[i],"")
|
|
||||||
}
|
|
||||||
res =append(res,temp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for col := 0; col < size; col++ {
|
|
||||||
if !isValid(board, row, col){
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
board[row][col] = "Q"
|
|
||||||
backtrack(board, row+1)
|
|
||||||
board[row][col] = "."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func solveNQueens(n int) [][]string {
|
func solveNQueens(n int) [][]string {
|
||||||
res = [][]string{}
|
var res [][]string
|
||||||
board := make([][]string, n)
|
chessboard := make([][]string, n)
|
||||||
for i := 0; i < n; i++{
|
for i := 0; i < n; i++ {
|
||||||
board[i] = make([]string, n)
|
chessboard[i] = make([]string, n)
|
||||||
}
|
}
|
||||||
for i := 0; i < n; i++{
|
for i := 0; i < n; i++ {
|
||||||
for j := 0; j<n;j++{
|
for j := 0; j < n; j++ {
|
||||||
board[i][j] = "."
|
chessboard[i][j] = "."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
backtrack(board, 0)
|
var backtrack func(int)
|
||||||
|
backtrack = func(row int) {
|
||||||
|
if row == n {
|
||||||
|
temp := make([]string, n)
|
||||||
|
for i, rowStr := range chessboard {
|
||||||
|
temp[i] = strings.Join(rowStr, "")
|
||||||
|
}
|
||||||
|
res = append(res, temp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
if isValid(n, row, i, chessboard) {
|
||||||
|
chessboard[row][i] = "Q"
|
||||||
|
backtrack(row + 1)
|
||||||
|
chessboard[row][i] = "."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backtrack(0)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
return res
|
func isValid(n, row, col int, chessboard [][]string) bool {
|
||||||
|
for i := 0; i < row; i++ {
|
||||||
|
if chessboard[i][col] == "Q" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, j := row-1, col-1; i >= 0 && j >= 0; i, j = i-1, j-1 {
|
||||||
|
if chessboard[i][j] == "Q" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, j := row-1, col+1; i >= 0 && j < n; i, j = i-1, j+1 {
|
||||||
|
if chessboard[i][j] == "Q" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
### Javascript
|
### Javascript
|
||||||
|
|
@ -470,6 +455,58 @@ var solveNQueens = function(n) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function solveNQueens(n: number): string[][] {
|
||||||
|
const board: string[][] = new Array(n).fill(0).map(_ => new Array(n).fill('.'));
|
||||||
|
const resArr: string[][] = [];
|
||||||
|
backTracking(n, 0, board);
|
||||||
|
return resArr;
|
||||||
|
function backTracking(n: number, rowNum: number, board: string[][]): void {
|
||||||
|
if (rowNum === n) {
|
||||||
|
resArr.push(transformBoard(board));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
if (isValid(i, rowNum, board) === true) {
|
||||||
|
board[rowNum][i] = 'Q';
|
||||||
|
backTracking(n, rowNum + 1, board);
|
||||||
|
board[rowNum][i] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
function isValid(col: number, row: number, board: string[][]): boolean {
|
||||||
|
const n: number = board.length;
|
||||||
|
if (col < 0 || col >= n || row < 0 || row >= n) return false;
|
||||||
|
// 检查列
|
||||||
|
for (let row of board) {
|
||||||
|
if (row[col] === 'Q') return false;
|
||||||
|
}
|
||||||
|
// 检查45度方向
|
||||||
|
let x: number = col,
|
||||||
|
y: number = row;
|
||||||
|
while (y >= 0 && x < n) {
|
||||||
|
if (board[y--][x++] === 'Q') return false;
|
||||||
|
}
|
||||||
|
// 检查135度方向
|
||||||
|
x = col;
|
||||||
|
y = row;
|
||||||
|
while (x >= 0 && y >= 0) {
|
||||||
|
if (board[y--][x--] === 'Q') return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function transformBoard(board: string[][]): string[] {
|
||||||
|
const resArr = [];
|
||||||
|
for (let row of board) {
|
||||||
|
resArr.push(row.join(''));
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Swift
|
### Swift
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
|
|
|
||||||
|
|
@ -143,5 +143,65 @@ var totalNQueens = function(n) {
|
||||||
return count;
|
return count;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C
|
||||||
|
```c
|
||||||
|
//path[i]为在i行,path[i]列上存在皇后
|
||||||
|
int *path;
|
||||||
|
int pathTop;
|
||||||
|
int answer;
|
||||||
|
//检查当前level行index列放置皇后是否合法
|
||||||
|
int isValid(int index, int level) {
|
||||||
|
int i;
|
||||||
|
//updater为若斜角存在皇后,其所应在的列
|
||||||
|
//用来检查左上45度是否存在皇后
|
||||||
|
int lCornerUpdater = index - level;
|
||||||
|
//用来检查右上135度是否存在皇后
|
||||||
|
int rCornerUpdater = index + level;
|
||||||
|
for(i = 0; i < pathTop; ++i) {
|
||||||
|
//path[i] == index检查index列是否存在皇后
|
||||||
|
//检查斜角皇后:只要path[i] == updater,就说明当前位置不可放置皇后。
|
||||||
|
//path[i] == lCornerUpdater检查左上角45度是否有皇后
|
||||||
|
//path[i] == rCornerUpdater检查右上角135度是否有皇后
|
||||||
|
if(path[i] == index || path[i] == lCornerUpdater || path[i] == rCornerUpdater)
|
||||||
|
return 0;
|
||||||
|
//更新updater指向下一行对应的位置
|
||||||
|
++lCornerUpdater;
|
||||||
|
--rCornerUpdater;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//回溯算法:level为当前皇后行数
|
||||||
|
void backTracking(int n, int level) {
|
||||||
|
//若path中元素个数已经为n,则证明有一种解法。answer+1
|
||||||
|
if(pathTop == n) {
|
||||||
|
++answer;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < n; ++i) {
|
||||||
|
//若当前level行,i列是合法的放置位置。就将i放入path中
|
||||||
|
if(isValid(i, level)) {
|
||||||
|
path[pathTop++] = i;
|
||||||
|
backTracking(n, level + 1);
|
||||||
|
//回溯
|
||||||
|
--pathTop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalNQueens(int n){
|
||||||
|
answer = 0;
|
||||||
|
pathTop = 0;
|
||||||
|
path = (int *)malloc(sizeof(int) * n);
|
||||||
|
|
||||||
|
backTracking(n, 0);
|
||||||
|
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
暴力解法的思路,第一层for 就是设置起始位置,第二层for循环遍历数组寻找最大值
|
暴力解法的思路,第一层for 就是设置起始位置,第二层for循环遍历数组寻找最大值
|
||||||
|
|
||||||
* 时间复杂度:$O(n^2)$
|
* 时间复杂度:O(n^2)
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
```CPP
|
```CPP
|
||||||
class Solution {
|
class Solution {
|
||||||
|
|
@ -98,8 +98,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
当然题目没有说如果数组为空,应该返回什么,所以数组为空的话返回啥都可以了。
|
当然题目没有说如果数组为空,应该返回什么,所以数组为空的话返回啥都可以了。
|
||||||
|
|
||||||
|
|
@ -128,8 +128,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
|
|
@ -211,7 +211,7 @@ func maxSubArray(nums []int) int {
|
||||||
return maxSum
|
return maxSum
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Javascript:
|
### Javascript:
|
||||||
```Javascript
|
```Javascript
|
||||||
var maxSubArray = function(nums) {
|
var maxSubArray = function(nums) {
|
||||||
|
|
@ -231,6 +231,96 @@ var maxSubArray = function(nums) {
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### C:
|
||||||
|
贪心:
|
||||||
|
```c
|
||||||
|
int maxSubArray(int* nums, int numsSize){
|
||||||
|
int maxVal = INT_MIN;
|
||||||
|
int subArrSum = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < numsSize; ++i) {
|
||||||
|
subArrSum += nums[i];
|
||||||
|
// 若当前局部和大于之前的最大结果,对结果进行更新
|
||||||
|
maxVal = subArrSum > maxVal ? subArrSum : maxVal;
|
||||||
|
// 若当前局部和为负,对结果无益。则从nums[i+1]开始应重新计算。
|
||||||
|
subArrSum = subArrSum < 0 ? 0 : subArrSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxVal;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
动态规划:
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* 解题思路:动态规划:
|
||||||
|
* 1. dp数组:dp[i]表示从0到i的子序列中最大序列和的值
|
||||||
|
* 2. 递推公式:dp[i] = max(dp[i-1] + nums[i], nums[i])
|
||||||
|
若dp[i-1]<0,对最后结果无益。dp[i]则为nums[i]。
|
||||||
|
* 3. dp数组初始化:dp[0]的最大子数组和为nums[0]
|
||||||
|
* 4. 推导顺序:从前往后遍历
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
int maxSubArray(int* nums, int numsSize){
|
||||||
|
int dp[numsSize];
|
||||||
|
// dp[0]最大子数组和为nums[0]
|
||||||
|
dp[0] = nums[0];
|
||||||
|
// 若numsSize为1,应直接返回nums[0]
|
||||||
|
int subArrSum = nums[0];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 1; i < numsSize; ++i) {
|
||||||
|
dp[i] = max(dp[i - 1] + nums[i], nums[i]);
|
||||||
|
|
||||||
|
// 若dp[i]大于之前记录的最大值,进行更新
|
||||||
|
if(dp[i] > subArrSum)
|
||||||
|
subArrSum = dp[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return subArrSum;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
**贪心**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function maxSubArray(nums: number[]): number {
|
||||||
|
let curSum: number = 0;
|
||||||
|
let resMax: number = -Infinity;
|
||||||
|
for (let i = 0, length = nums.length; i < length; i++) {
|
||||||
|
curSum += nums[i];
|
||||||
|
resMax = Math.max(curSum, resMax);
|
||||||
|
if (curSum < 0) curSum = 0;
|
||||||
|
}
|
||||||
|
return resMax;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**动态规划**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 动态规划
|
||||||
|
function maxSubArray(nums: number[]): number {
|
||||||
|
const length = nums.length;
|
||||||
|
if (length === 0) return 0;
|
||||||
|
const dp: number[] = [];
|
||||||
|
dp[0] = nums[0];
|
||||||
|
let resMax: number = nums[0];
|
||||||
|
for (let i = 1; i < length; i++) {
|
||||||
|
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
|
||||||
|
resMax = Math.max(resMax, dp[i]);
|
||||||
|
}
|
||||||
|
return resMax;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
@ -174,6 +174,7 @@ const maxSubArray = nums => {
|
||||||
// 数组长度,dp初始化
|
// 数组长度,dp初始化
|
||||||
const len = nums.length;
|
const len = nums.length;
|
||||||
let dp = new Array(len).fill(0);
|
let dp = new Array(len).fill(0);
|
||||||
|
dp[0] = nums[0];
|
||||||
// 最大值初始化为dp[0]
|
// 最大值初始化为dp[0]
|
||||||
let max = dp[0];
|
let max = dp[0];
|
||||||
for (let i = 1; i < len; i++) {
|
for (let i = 1; i < len; i++) {
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,46 @@ public:
|
||||||
* [59.螺旋矩阵II](https://leetcode-cn.com/problems/spiral-matrix-ii/)
|
* [59.螺旋矩阵II](https://leetcode-cn.com/problems/spiral-matrix-ii/)
|
||||||
* [剑指Offer 29.顺时针打印矩阵](https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/)
|
* [剑指Offer 29.顺时针打印矩阵](https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/)
|
||||||
|
|
||||||
|
## 其他语言版本
|
||||||
|
Python:
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
|
||||||
|
m, n = len(matrix), len(matrix[0])
|
||||||
|
left, right, up, down = 0, n - 1, 0, m - 1 # 定位四个方向的边界,闭区间
|
||||||
|
res = []
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for i in range(left, right + 1): # 上边,从左到右
|
||||||
|
res.append(matrix[up][i])
|
||||||
|
up += 1 # 上边界下移
|
||||||
|
|
||||||
|
if len(res) >= m * n: # 判断是否已经遍历完
|
||||||
|
break
|
||||||
|
|
||||||
|
for i in range(up, down + 1): # 右边,从上到下
|
||||||
|
res.append(matrix[i][right])
|
||||||
|
right -= 1 # 右边界左移
|
||||||
|
|
||||||
|
if len(res) >= m * n:
|
||||||
|
break
|
||||||
|
|
||||||
|
for i in range(right, left - 1, -1): # 下边,从右到左
|
||||||
|
res.append(matrix[down][i])
|
||||||
|
down -= 1 # 下边界上移
|
||||||
|
|
||||||
|
if len(res) >= m * n:
|
||||||
|
break
|
||||||
|
|
||||||
|
for i in range(down, up - 1, -1): # 左边,从下到上
|
||||||
|
res.append(matrix[i][left])
|
||||||
|
left += 1 # 左边界右移
|
||||||
|
|
||||||
|
if len(res) >= m * n:
|
||||||
|
break
|
||||||
|
|
||||||
|
return res
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -155,5 +155,46 @@ var canJump = function(nums) {
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### C
|
||||||
|
```c
|
||||||
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
bool canJump(int* nums, int numsSize){
|
||||||
|
int cover = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
// 只可能获取cover范围中的步数,所以i<=cover
|
||||||
|
for(i = 0; i <= cover; ++i) {
|
||||||
|
// 更新cover为从i出发能到达的最大值/cover的值中较大值
|
||||||
|
cover = max(i + nums[i], cover);
|
||||||
|
|
||||||
|
// 若更新后cover可以到达最后的元素,返回true
|
||||||
|
if(cover >= numsSize - 1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function canJump(nums: number[]): boolean {
|
||||||
|
let farthestIndex: number = 0;
|
||||||
|
let cur: number = 0;
|
||||||
|
while (cur <= farthestIndex) {
|
||||||
|
farthestIndex = Math.max(farthestIndex, cur + nums[cur]);
|
||||||
|
if (farthestIndex >= nums.length - 1) return true;
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,26 @@ var merge = function(intervals) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function merge(intervals: number[][]): number[][] {
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
intervals.sort((a, b) => a[0] - b[0]);
|
||||||
|
resArr[0] = [...intervals[0]]; // 避免修改原intervals
|
||||||
|
for (let i = 1, length = intervals.length; i < length; i++) {
|
||||||
|
let interval: number[] = intervals[i];
|
||||||
|
let last: number[] = resArr[resArr.length - 1];
|
||||||
|
if (interval[0] <= last[1]) {
|
||||||
|
last[1] = Math.max(interval[1], last[1]);
|
||||||
|
} else {
|
||||||
|
resArr.push([...intervals[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/spiral-matrix-ii/)
|
[力扣题目链接](https://leetcode-cn.com/problems/spiral-matrix-ii/)
|
||||||
|
|
||||||
给定一个正整数 n,生成一个包含 1 到 $n^2$ 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
|
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
相信很多同学刚开始做这种题目的时候,上来就是一波判断猛如虎。
|
相信很多同学刚开始做这种题目的时候,上来就是一波判断猛如虎。
|
||||||
|
|
||||||
结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里哪里有问题,改了那里这里又跑不起来了。
|
结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里那里有问题,改了那里这里又跑不起来了。
|
||||||
|
|
||||||
大家还记得我们在这篇文章[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0704.二分查找.html)中讲解了二分法,提到如果要写出正确的二分法一定要坚持**循环不变量原则**。
|
大家还记得我们在这篇文章[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0704.二分查找.html)中讲解了二分法,提到如果要写出正确的二分法一定要坚持**循环不变量原则**。
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是**一进循环深似海,从此offer是路人**。
|
可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是**一进循环深似海,从此offer是路人**。
|
||||||
|
|
||||||
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开又闭的原则,这样这一圈才能按照统一的规则画下来。
|
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
|
||||||
|
|
||||||
那么我按照左闭右开的原则,来画一圈,大家看一下:
|
那么我按照左闭右开的原则,来画一圈,大家看一下:
|
||||||
|
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
一些同学做这道题目之所以一直写不好,代码越写越乱。
|
一些同学做这道题目之所以一直写不好,代码越写越乱。
|
||||||
|
|
||||||
就是因为在画每一条边的时候,一会左开又闭,一会左闭右闭,一会又来左闭右开,岂能不乱。
|
就是因为在画每一条边的时候,一会左开右闭,一会左闭右闭,一会又来左闭右开,岂能不乱。
|
||||||
|
|
||||||
代码如下,已经详细注释了每一步的目的,可以看出while循环里判断的情况是很多的,代码里处理的原则也是统一的左闭右开。
|
代码如下,已经详细注释了每一步的目的,可以看出while循环里判断的情况是很多的,代码里处理的原则也是统一的左闭右开。
|
||||||
|
|
||||||
|
|
@ -188,51 +188,35 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
python:
|
python3:
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
|
|
||||||
def generateMatrix(self, n: int) -> List[List[int]]:
|
def generateMatrix(self, n: int) -> List[List[int]]:
|
||||||
# 初始化要填充的正方形
|
nums = [[0] * n for _ in range(n)]
|
||||||
matrix = [[0] * n for _ in range(n)]
|
startx, starty = 0, 0 # 起始点
|
||||||
|
loop, mid = n // 2, n // 2 # 迭代次数、n为奇数时,矩阵的中心点
|
||||||
|
count = 1 # 计数
|
||||||
|
|
||||||
left, right, up, down = 0, n - 1, 0, n - 1
|
for offset in range(1, loop + 1) : # 每循环一层偏移量加1,偏移量从1开始
|
||||||
number = 1 # 要填充的数字
|
for i in range(starty, n - offset) : # 从左至右,左闭右开
|
||||||
|
nums[startx][i] = count
|
||||||
|
count += 1
|
||||||
|
for i in range(startx, n - offset) : # 从上至下
|
||||||
|
nums[i][n - offset] = count
|
||||||
|
count += 1
|
||||||
|
for i in range(n - offset, starty, -1) : # 从右至左
|
||||||
|
nums[n - offset][i] = count
|
||||||
|
count += 1
|
||||||
|
for i in range(n - offset, startx, -1) : # 从下至上
|
||||||
|
nums[i][starty] = count
|
||||||
|
count += 1
|
||||||
|
startx += 1 # 更新起始点
|
||||||
|
starty += 1
|
||||||
|
|
||||||
while left < right and up < down:
|
if n % 2 != 0 : # n为奇数时,填充中心点
|
||||||
|
nums[mid][mid] = count
|
||||||
# 从左到右填充上边
|
return nums
|
||||||
for x in range(left, right):
|
|
||||||
matrix[up][x] = number
|
|
||||||
number += 1
|
|
||||||
|
|
||||||
# 从上到下填充右边
|
|
||||||
for y in range(up, down):
|
|
||||||
matrix[y][right] = number
|
|
||||||
number += 1
|
|
||||||
|
|
||||||
# 从右到左填充下边
|
|
||||||
for x in range(right, left, -1):
|
|
||||||
matrix[down][x] = number
|
|
||||||
number += 1
|
|
||||||
|
|
||||||
# 从下到上填充左边
|
|
||||||
for y in range(down, up, -1):
|
|
||||||
matrix[y][left] = number
|
|
||||||
number += 1
|
|
||||||
|
|
||||||
# 缩小要填充的范围
|
|
||||||
left += 1
|
|
||||||
right -= 1
|
|
||||||
up += 1
|
|
||||||
down -= 1
|
|
||||||
|
|
||||||
# 如果阶数为奇数,额外填充一次中心
|
|
||||||
if n % 2:
|
|
||||||
matrix[n // 2][n // 2] = number
|
|
||||||
|
|
||||||
return matrix
|
|
||||||
```
|
```
|
||||||
|
|
||||||
javaScript
|
javaScript
|
||||||
|
|
@ -262,11 +246,11 @@ var generateMatrix = function(n) {
|
||||||
res[row][col] = count++;
|
res[row][col] = count++;
|
||||||
}
|
}
|
||||||
// 下行从右到左(左闭右开)
|
// 下行从右到左(左闭右开)
|
||||||
for (; col > startX; col--) {
|
for (; col > startY; col--) {
|
||||||
res[row][col] = count++;
|
res[row][col] = count++;
|
||||||
}
|
}
|
||||||
// 左列做下到上(左闭右开)
|
// 左列做下到上(左闭右开)
|
||||||
for (; row > startY; row--) {
|
for (; row > startX; row--) {
|
||||||
res[row][col] = count++;
|
res[row][col] = count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ public:
|
||||||
|
|
||||||
那二叉树的节点个数就是 2^(m + n - 1) - 1。可以理解深搜的算法就是遍历了整个满二叉树(其实没有遍历整个满二叉树,只是近似而已)
|
那二叉树的节点个数就是 2^(m + n - 1) - 1。可以理解深搜的算法就是遍历了整个满二叉树(其实没有遍历整个满二叉树,只是近似而已)
|
||||||
|
|
||||||
所以上面深搜代码的时间复杂度为$O(2^{m + n - 1} - 1)$,可以看出,这是指数级别的时间复杂度,是非常大的。
|
所以上面深搜代码的时间复杂度为O(2^(m + n - 1) - 1),可以看出,这是指数级别的时间复杂度,是非常大的。
|
||||||
|
|
||||||
### 动态规划
|
### 动态规划
|
||||||
|
|
||||||
|
|
@ -143,8 +143,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(m × n)$
|
* 时间复杂度:O(m × n)
|
||||||
* 空间复杂度:$O(m × n)$
|
* 空间复杂度:O(m × n)
|
||||||
|
|
||||||
其实用一个一维数组(也可以理解是滚动数组)就可以了,但是不利于理解,可以优化点空间,建议先理解了二维,在理解一维,C++代码如下:
|
其实用一个一维数组(也可以理解是滚动数组)就可以了,但是不利于理解,可以优化点空间,建议先理解了二维,在理解一维,C++代码如下:
|
||||||
|
|
||||||
|
|
@ -164,8 +164,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(m × n)$
|
* 时间复杂度:O(m × n)
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
### 数论方法
|
### 数论方法
|
||||||
|
|
||||||
|
|
@ -224,8 +224,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(m)$
|
* 时间复杂度:O(m)
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
**计算组合问题的代码还是有难度的,特别是处理溢出的情况!**
|
**计算组合问题的代码还是有难度的,特别是处理溢出的情况!**
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
</a>
|
</a>
|
||||||
<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>
|
||||||
|
|
||||||
## 63. 不同路径 II
|
# 63. 不同路径 II
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/unique-paths-ii/)
|
[力扣题目链接](https://leetcode-cn.com/problems/unique-paths-ii/)
|
||||||
|
|
||||||
|
|
@ -22,23 +22,22 @@
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
|
* 输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
|
||||||
输出:2
|
* 输出:2
|
||||||
解释:
|
解释:
|
||||||
3x3 网格的正中间有一个障碍物。
|
* 3x3 网格的正中间有一个障碍物。
|
||||||
从左上角到右下角一共有 2 条不同的路径:
|
* 从左上角到右下角一共有 2 条不同的路径:
|
||||||
1. 向右 -> 向右 -> 向下 -> 向下
|
1. 向右 -> 向右 -> 向下 -> 向下
|
||||||
2. 向下 -> 向下 -> 向右 -> 向右
|
2. 向下 -> 向下 -> 向右 -> 向右
|
||||||
|
|
||||||
示例 2:
|
示例 2:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
输入:obstacleGrid = [[0,1],[0,0]]
|
* 输入:obstacleGrid = [[0,1],[0,0]]
|
||||||
输出:1
|
* 输出:1
|
||||||
|
|
||||||
提示:
|
提示:
|
||||||
|
|
||||||
* m == obstacleGrid.length
|
* m == obstacleGrid.length
|
||||||
* n == obstacleGrid[i].length
|
* n == obstacleGrid[i].length
|
||||||
* 1 <= m, n <= 100
|
* 1 <= m, n <= 100
|
||||||
|
|
@ -153,8 +152,41 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n × m)$,n、m 分别为obstacleGrid 长度和宽度
|
* 时间复杂度:O(n × m),n、m 分别为obstacleGrid 长度和宽度
|
||||||
* 空间复杂度:$O(n × m)$
|
* 空间复杂度:O(n × m)
|
||||||
|
|
||||||
|
|
||||||
|
同样我们给出空间优化版本:
|
||||||
|
```CPP
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
|
||||||
|
if (obstacleGrid[0][0] == 1)
|
||||||
|
return 0;
|
||||||
|
vector<int> dp(obstacleGrid[0].size());
|
||||||
|
for (int j = 0; j < dp.size(); ++j)
|
||||||
|
if (obstacleGrid[0][j] == 1)
|
||||||
|
dp[j] = 0;
|
||||||
|
else if (j == 0)
|
||||||
|
dp[j] = 1;
|
||||||
|
else
|
||||||
|
dp[j] = dp[j-1];
|
||||||
|
|
||||||
|
for (int i = 1; i < obstacleGrid.size(); ++i)
|
||||||
|
for (int j = 0; j < dp.size(); ++j){
|
||||||
|
if (obstacleGrid[i][j] == 1)
|
||||||
|
dp[j] = 0;
|
||||||
|
else if (j != 0)
|
||||||
|
dp[j] = dp[j] + dp[j-1];
|
||||||
|
}
|
||||||
|
return dp.back();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
* 时间复杂度:O(n × m),n、m 分别为obstacleGrid 长度和宽度
|
||||||
|
* 空间复杂度:O(m)
|
||||||
|
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
|
|
@ -171,7 +203,7 @@ public:
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
Java:
|
### Java
|
||||||
|
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
|
|
@ -199,7 +231,7 @@ class Solution {
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Python:
|
### Python
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
|
|
@ -262,54 +294,41 @@ class Solution:
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Go:
|
### Go
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func uniquePathsWithObstacles(obstacleGrid [][]int) int {
|
func uniquePathsWithObstacles(obstacleGrid [][]int) int {
|
||||||
m,n:= len(obstacleGrid),len(obstacleGrid[0])
|
m, n := len(obstacleGrid), len(obstacleGrid[0])
|
||||||
// 定义一个dp数组
|
// 定义一个dp数组
|
||||||
dp := make([][]int,m)
|
dp := make([][]int, m)
|
||||||
for i,_ := range dp {
|
for i, _ := range dp {
|
||||||
dp[i] = make([]int,n)
|
dp[i] = make([]int, n)
|
||||||
}
|
}
|
||||||
// 初始化
|
// 初始化, 如果是障碍物, 后面的就都是0, 不用循环了
|
||||||
for i:=0;i<m;i++ {
|
for i := 0; i < m && obstacleGrid[i][0] == 0; i++ {
|
||||||
// 如果是障碍物, 后面的就都是0, 不用循环了
|
dp[i][0] = 1
|
||||||
if obstacleGrid[i][0] == 1 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
dp[i][0]=1
|
|
||||||
}
|
}
|
||||||
for i:=0;i<n;i++ {
|
for i := 0; i < n && obstacleGrid[0][i] == 0; i++ {
|
||||||
if obstacleGrid[0][i] == 1 {
|
dp[0][i] = 1
|
||||||
break
|
|
||||||
}
|
|
||||||
dp[0][i]=1
|
|
||||||
}
|
}
|
||||||
// dp数组推导过程
|
// dp数组推导过程
|
||||||
for i:=1;i<m;i++ {
|
for i := 1; i < m; i++ {
|
||||||
for j:=1;j<n;j++ {
|
for j := 1; j < n; j++ {
|
||||||
// 如果obstacleGrid[i][j]这个点是障碍物, 那么我们的dp[i][j]保持为0
|
// 如果obstacleGrid[i][j]这个点是障碍物, 那么dp[i][j]保持为0
|
||||||
if obstacleGrid[i][j] != 1 {
|
if obstacleGrid[i][j] != 1 {
|
||||||
// 否则我们需要计算当前点可以到达的路径数
|
// 否则我们需要计算当前点可以到达的路径数
|
||||||
dp[i][j] = dp[i-1][j]+dp[i][j-1]
|
dp[i][j] = dp[i-1][j] + dp[i][j-1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// debug遍历dp
|
|
||||||
//for i,_ := range dp {
|
|
||||||
// for j,_ := range dp[i] {
|
|
||||||
// fmt.Printf("%.2v,",dp[i][j])
|
|
||||||
// }
|
|
||||||
// fmt.Println()
|
|
||||||
//}
|
|
||||||
return dp[m-1][n-1]
|
return dp[m-1][n-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Javascript
|
### Javascript
|
||||||
``` Javascript
|
```Javascript
|
||||||
var uniquePathsWithObstacles = function(obstacleGrid) {
|
var uniquePathsWithObstacles = function(obstacleGrid) {
|
||||||
const m = obstacleGrid.length
|
const m = obstacleGrid.length
|
||||||
const n = obstacleGrid[0].length
|
const n = obstacleGrid[0].length
|
||||||
|
|
|
||||||
|
|
@ -256,16 +256,28 @@ public int climbStairs(int n) {
|
||||||
### Python
|
### Python
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# 空间复杂度为O(n)版本
|
||||||
class Solution:
|
class Solution:
|
||||||
def climbStairs(self, n: int) -> int:
|
def climbStairs(self, n: int) -> int:
|
||||||
# dp[i]表示爬到第i级楼梯的种数, (1, 2) (2, 1)是两种不同的类型
|
# dp[i] 为第 i 阶楼梯有多少种方法爬到楼顶
|
||||||
dp = [0] * (n + 1)
|
dp=[0]*(n+1)
|
||||||
dp[0] = 1
|
dp[0]=1
|
||||||
for i in range(n+1):
|
dp[1]=1
|
||||||
for j in range(1, 3):
|
for i in range(2,n+1):
|
||||||
if i>=j:
|
dp[i]=dp[i-1]+dp[i-2]
|
||||||
dp[i] += dp[i-j]
|
return dp[n]
|
||||||
return dp[-1]
|
|
||||||
|
# 空间复杂度为O(1)版本
|
||||||
|
class Solution:
|
||||||
|
def climbStairs(self, n: int) -> int:
|
||||||
|
dp=[0]*(n+1)
|
||||||
|
dp[0]=1
|
||||||
|
dp[1]=1
|
||||||
|
for i in range(2,n+1):
|
||||||
|
tmp=dp[0]+dp[1]
|
||||||
|
dp[0]=dp[1]
|
||||||
|
dp[1]=tmp
|
||||||
|
return dp[1]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
|
|
|
||||||
|
|
@ -143,10 +143,10 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python3:
|
||||||
|
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def climbStairs(self, n: int) -> int:
|
def climbStairs(self, n: int) -> int:
|
||||||
dp = [0]*(n + 1)
|
dp = [0]*(n + 1)
|
||||||
|
|
|
||||||
|
|
@ -423,8 +423,8 @@ class Solution:
|
||||||
if len(path) == k:
|
if len(path) == k:
|
||||||
res.append(path[:])
|
res.append(path[:])
|
||||||
return
|
return
|
||||||
for i in range(startIndex,n - (k - len(path)) + 2): #优化的地方
|
for i in range(startIndex,n-(k-len(path))+2): #优化的地方
|
||||||
path.append(i) #处理节点
|
path.append(i) #处理节点
|
||||||
backtrack(n,k,i+1) #递归
|
backtrack(n,k,i+1) #递归
|
||||||
path.pop() #回溯,撤销处理的节点
|
path.pop() #回溯,撤销处理的节点
|
||||||
backtrack(n,k,1)
|
backtrack(n,k,1)
|
||||||
|
|
@ -456,6 +456,27 @@ const combineHelper = (n, k, startIndex) => {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function combine(n: number, k: number): number[][] {
|
||||||
|
let resArr: number[][] = [];
|
||||||
|
function backTracking(n: number, k: number, startIndex: number, tempArr: number[]): void {
|
||||||
|
if (tempArr.length === k) {
|
||||||
|
resArr.push(tempArr.slice());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = startIndex; i <= n - k + 1 + tempArr.length; i++) {
|
||||||
|
tempArr.push(i);
|
||||||
|
backTracking(n, k, i + 1, tempArr);
|
||||||
|
tempArr.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backTracking(n, k, 1, []);
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Go
|
## Go
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ class Solution {
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def combine(self, n: int, k: int) -> List[List[int]]:
|
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||||
res=[] #存放符合条件结果的集合
|
res=[] #存放符合条件结果的集合
|
||||||
|
|
@ -240,7 +240,29 @@ var combine = function(n, k) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function combine(n: number, k: number): number[][] {
|
||||||
|
let resArr: number[][] = [];
|
||||||
|
function backTracking(n: number, k: number, startIndex: number, tempArr: number[]): void {
|
||||||
|
if (tempArr.length === k) {
|
||||||
|
resArr.push(tempArr.slice());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = startIndex; i <= n - k + 1 + tempArr.length; i++) {
|
||||||
|
tempArr.push(i);
|
||||||
|
backTracking(n, k, i + 1, tempArr);
|
||||||
|
tempArr.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backTracking(n, k, 1, []);
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
C:
|
C:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int* path;
|
int* path;
|
||||||
int pathTop;
|
int pathTop;
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,7 @@ class Solution {
|
||||||
```
|
```
|
||||||
|
|
||||||
## Python
|
## Python
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.path: List[int] = []
|
self.path: List[int] = []
|
||||||
|
|
@ -272,7 +272,28 @@ var subsets = function(nums) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function subsets(nums: number[]): number[][] {
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
backTracking(nums, 0, []);
|
||||||
|
return resArr;
|
||||||
|
function backTracking(nums: number[], startIndex: number, route: number[]): void {
|
||||||
|
resArr.push(route.slice());
|
||||||
|
let length = nums.length;
|
||||||
|
if (startIndex === length) return;
|
||||||
|
for (let i = startIndex; i < length; i++) {
|
||||||
|
route.push(nums[i]);
|
||||||
|
backTracking(nums, i + 1, route);
|
||||||
|
route.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int* path;
|
int* path;
|
||||||
int pathTop;
|
int pathTop;
|
||||||
|
|
|
||||||
|
|
@ -277,9 +277,9 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python3:
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
|
|
||||||
# 双指针;暴力解法(leetcode超时)
|
# 双指针;暴力解法(leetcode超时)
|
||||||
class Solution:
|
class Solution:
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ class Solution {
|
||||||
private:
|
private:
|
||||||
vector<vector<int>> result;
|
vector<vector<int>> result;
|
||||||
vector<int> path;
|
vector<int> path;
|
||||||
void backtracking(vector<int>& nums, int startIndex, vector<bool>& used) {
|
void backtracking(vector<int>& nums, int startIndex) {
|
||||||
result.push_back(path);
|
result.push_back(path);
|
||||||
unordered_set<int> uset;
|
unordered_set<int> uset;
|
||||||
for (int i = startIndex; i < nums.size(); i++) {
|
for (int i = startIndex; i < nums.size(); i++) {
|
||||||
|
|
@ -96,7 +96,7 @@ private:
|
||||||
}
|
}
|
||||||
uset.insert(nums[i]);
|
uset.insert(nums[i]);
|
||||||
path.push_back(nums[i]);
|
path.push_back(nums[i]);
|
||||||
backtracking(nums, i + 1, used);
|
backtracking(nums, i + 1);
|
||||||
path.pop_back();
|
path.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -105,9 +105,8 @@ public:
|
||||||
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
|
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
|
||||||
result.clear();
|
result.clear();
|
||||||
path.clear();
|
path.clear();
|
||||||
vector<bool> used(nums.size(), false);
|
|
||||||
sort(nums.begin(), nums.end()); // 去重需要排序
|
sort(nums.begin(), nums.end()); // 去重需要排序
|
||||||
backtracking(nums, 0, used);
|
backtracking(nums, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -319,6 +318,28 @@ var subsetsWithDup = function(nums) {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function subsetsWithDup(nums: number[]): number[][] {
|
||||||
|
nums.sort((a, b) => a - b);
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
backTraking(nums, 0, []);
|
||||||
|
return resArr;
|
||||||
|
function backTraking(nums: number[], startIndex: number, route: number[]): void {
|
||||||
|
resArr.push(route.slice());
|
||||||
|
let length: number = nums.length;
|
||||||
|
if (startIndex === length) return;
|
||||||
|
for (let i = startIndex; i < length; i++) {
|
||||||
|
if (i > startIndex && nums[i] === nums[i - 1]) continue;
|
||||||
|
route.push(nums[i]);
|
||||||
|
backTraking(nums, i + 1, route);
|
||||||
|
route.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### C
|
### C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
@ -388,7 +409,7 @@ int** subsetsWithDup(int* nums, int numsSize, int* returnSize, int** returnColum
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Swift
|
### Swift
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func subsetsWithDup(_ nums: [Int]) -> [[Int]] {
|
func subsetsWithDup(_ nums: [Int]) -> [[Int]] {
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ private:
|
||||||
public:
|
public:
|
||||||
vector<string> restoreIpAddresses(string s) {
|
vector<string> restoreIpAddresses(string s) {
|
||||||
result.clear();
|
result.clear();
|
||||||
if (s.size() > 12) return result; // 算是剪枝了
|
if (s.size() < 4 || s.size() > 12) return result; // 算是剪枝了
|
||||||
backtracking(s, 0, 0);
|
backtracking(s, 0, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -304,6 +304,48 @@ class Solution {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//方法二:比上面的方法时间复杂度低,更好地剪枝,优化时间复杂度
|
||||||
|
class Solution {
|
||||||
|
List<String> result = new ArrayList<String>();
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
public List<String> restoreIpAddresses(String s) {
|
||||||
|
restoreIpAddressesHandler(s, 0, 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// number表示stringbuilder中ip段的数量
|
||||||
|
public void restoreIpAddressesHandler(String s, int start, int number) {
|
||||||
|
// 如果start等于s的长度并且ip段的数量是4,则加入结果集,并返回
|
||||||
|
if (start == s.length() && number == 4) {
|
||||||
|
result.add(stringBuilder.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 如果start等于s的长度但是ip段的数量不为4,或者ip段的数量为4但是start小于s的长度,则直接返回
|
||||||
|
if (start == s.length() || number == 4) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 剪枝:ip段的长度最大是3,并且ip段处于[0,255]
|
||||||
|
for (int i = start; i < s.length() && i - start < 3 && Integer.parseInt(s.substring(start, i + 1)) >= 0
|
||||||
|
&& Integer.parseInt(s.substring(start, i + 1)) <= 255; i++) {
|
||||||
|
// 如果ip段的长度大于1,并且第一位为0的话,continue
|
||||||
|
if (i + 1 - start > 1 && s.charAt(start) - '0' == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stringBuilder.append(s.substring(start, i + 1));
|
||||||
|
// 当stringBuilder里的网段数量小于3时,才会加点;如果等于3,说明已经有3段了,最后一段不需要再加点
|
||||||
|
if (number < 3) {
|
||||||
|
stringBuilder.append(".");
|
||||||
|
}
|
||||||
|
number++;
|
||||||
|
restoreIpAddressesHandler(s, i + 1, number);
|
||||||
|
number--;
|
||||||
|
// 删除当前stringBuilder最后一个网段,注意考虑点的数量的问题
|
||||||
|
stringBuilder.delete(start + number, i + number + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## python
|
## python
|
||||||
|
|
@ -339,7 +381,7 @@ class Solution(object):
|
||||||
```
|
```
|
||||||
|
|
||||||
python3:
|
python3:
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.result = []
|
self.result = []
|
||||||
|
|
@ -413,6 +455,45 @@ var restoreIpAddresses = function(s) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function isValidIpSegment(str: string): boolean {
|
||||||
|
let resBool: boolean = true;
|
||||||
|
let tempVal: number = Number(str);
|
||||||
|
if (
|
||||||
|
str.length === 0 || isNaN(tempVal) ||
|
||||||
|
tempVal > 255 || tempVal < 0 ||
|
||||||
|
(str.length > 1 && str[0] === '0')
|
||||||
|
) {
|
||||||
|
resBool = false;
|
||||||
|
}
|
||||||
|
return resBool;
|
||||||
|
}
|
||||||
|
function restoreIpAddresses(s: string): string[] {
|
||||||
|
const resArr: string[] = [];
|
||||||
|
backTracking(s, 0, []);
|
||||||
|
return resArr;
|
||||||
|
function backTracking(s: string, startIndex: number, route: string[]): void {
|
||||||
|
let length: number = s.length;
|
||||||
|
if (route.length === 4 && startIndex >= length) {
|
||||||
|
resArr.push(route.join('.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (route.length === 4 || startIndex >= length) return;
|
||||||
|
let tempStr: string = '';
|
||||||
|
for (let i = startIndex + 1; i <= Math.min(length, startIndex + 3); i++) {
|
||||||
|
tempStr = s.slice(startIndex, i);
|
||||||
|
if (isValidIpSegment(tempStr)) {
|
||||||
|
route.push(s.slice(startIndex, i));
|
||||||
|
backTracking(s, i, route);
|
||||||
|
route.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## Go
|
## Go
|
||||||
|
|
||||||
回溯(对于前导 0的IP(特别注意s[startIndex]=='0'的判断,不应该写成s[startIndex]==0,因为s截取出来不是数字))
|
回溯(对于前导 0的IP(特别注意s[startIndex]=='0'的判断,不应该写成s[startIndex]==0,因为s截取出来不是数字))
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
</a>
|
</a>
|
||||||
<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>
|
||||||
|
|
||||||
## 96.不同的二叉搜索树
|
# 96.不同的二叉搜索树
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/unique-binary-search-trees/)
|
[力扣题目链接](https://leetcode-cn.com/problems/unique-binary-search-trees/)
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ public:
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
### Java
|
||||||
```Java
|
```Java
|
||||||
class Solution {
|
class Solution {
|
||||||
public int numTrees(int n) {
|
public int numTrees(int n) {
|
||||||
|
|
@ -184,7 +184,7 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
### Python
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def numTrees(self, n: int) -> int:
|
def numTrees(self, n: int) -> int:
|
||||||
|
|
@ -196,7 +196,7 @@ class Solution:
|
||||||
return dp[-1]
|
return dp[-1]
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
### Go
|
||||||
```Go
|
```Go
|
||||||
func numTrees(n int)int{
|
func numTrees(n int)int{
|
||||||
dp:=make([]int,n+1)
|
dp:=make([]int,n+1)
|
||||||
|
|
@ -210,7 +210,7 @@ func numTrees(n int)int{
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Javascript:
|
### Javascript
|
||||||
```Javascript
|
```Javascript
|
||||||
const numTrees =(n) => {
|
const numTrees =(n) => {
|
||||||
let dp = new Array(n+1).fill(0);
|
let dp = new Array(n+1).fill(0);
|
||||||
|
|
@ -227,7 +227,34 @@ const numTrees =(n) => {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C:
|
||||||
|
```c
|
||||||
|
//开辟dp数组
|
||||||
|
int *initDP(int n) {
|
||||||
|
int *dp = (int *)malloc(sizeof(int) * (n + 1));
|
||||||
|
int i;
|
||||||
|
for(i = 0; i <= n; ++i)
|
||||||
|
dp[i] = 0;
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numTrees(int n){
|
||||||
|
//开辟dp数组
|
||||||
|
int *dp = initDP(n);
|
||||||
|
//将dp[0]设为1
|
||||||
|
dp[0] = 1;
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
for(i = 1; i <= n; ++i) {
|
||||||
|
for(j = 1; j <= i; ++j) {
|
||||||
|
//递推公式:dp[i] = dp[i] + 根为j时左子树种类个数 * 根为j时右子树种类个数
|
||||||
|
dp[i] += dp[j - 1] * dp[i - j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[n];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -408,7 +408,28 @@ class Solution:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
```
|
```
|
||||||
## Go
|
```python
|
||||||
|
# 遵循Carl的写法,只添加了节点判断的部分
|
||||||
|
class Solution:
|
||||||
|
def isValidBST(self, root: TreeNode) -> bool:
|
||||||
|
# method 2
|
||||||
|
que, pre = [], None
|
||||||
|
while root or que:
|
||||||
|
while root:
|
||||||
|
que.append(root)
|
||||||
|
root = root.left
|
||||||
|
root = que.pop()
|
||||||
|
# 对第一个节点只做记录,对后面的节点进行比较
|
||||||
|
if pre is None:
|
||||||
|
pre = root.val
|
||||||
|
else:
|
||||||
|
if pre >= root.val: return False
|
||||||
|
pre = root.val
|
||||||
|
root = root.right
|
||||||
|
return True
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
import "math"
|
import "math"
|
||||||
|
|
@ -526,6 +547,48 @@ var isValidBST = function (root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
> 辅助数组解决:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function isValidBST(root: TreeNode | null): boolean {
|
||||||
|
const traversalArr: number[] = [];
|
||||||
|
function inorderTraverse(root: TreeNode | null): void {
|
||||||
|
if (root === null) return;
|
||||||
|
inorderTraverse(root.left);
|
||||||
|
traversalArr.push(root.val);
|
||||||
|
inorderTraverse(root.right);
|
||||||
|
}
|
||||||
|
inorderTraverse(root);
|
||||||
|
for (let i = 0, length = traversalArr.length; i < length - 1; i++) {
|
||||||
|
if (traversalArr[i] >= traversalArr[i + 1]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 递归中解决:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function isValidBST(root: TreeNode | null): boolean {
|
||||||
|
let maxVal = -Infinity;
|
||||||
|
function inorderTraverse(root: TreeNode | null): boolean {
|
||||||
|
if (root === null) return true;
|
||||||
|
let leftValid: boolean = inorderTraverse(root.left);
|
||||||
|
if (!leftValid) return false;
|
||||||
|
if (maxVal < root.val) {
|
||||||
|
maxVal = root.val
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let rightValid: boolean = inorderTraverse(root.right);
|
||||||
|
return leftValid && rightValid;
|
||||||
|
}
|
||||||
|
return inorderTraverse(root);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
||||||
|
|
@ -574,6 +574,75 @@ var isSymmetric = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript:
|
||||||
|
|
||||||
|
> 递归法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function isSymmetric(root: TreeNode | null): boolean {
|
||||||
|
function recur(node1: TreeNode | null, node2: TreeNode | null): boolean {
|
||||||
|
if (node1 === null && node2 === null) return true;
|
||||||
|
if (node1 === null || node2 === null) return false;
|
||||||
|
if (node1.val !== node2.val) return false
|
||||||
|
let isSym1: boolean = recur(node1.left, node2.right);
|
||||||
|
let isSym2: boolean = recur(node1.right, node2.left);
|
||||||
|
return isSym1 && isSym2
|
||||||
|
}
|
||||||
|
if (root === null) return true;
|
||||||
|
return recur(root.left, root.right);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 迭代法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 迭代法(队列)
|
||||||
|
function isSymmetric(root: TreeNode | null): boolean {
|
||||||
|
let helperQueue: (TreeNode | null)[] = [];
|
||||||
|
let tempNode1: TreeNode | null,
|
||||||
|
tempNode2: TreeNode | null;
|
||||||
|
if (root !== null) {
|
||||||
|
helperQueue.push(root.left);
|
||||||
|
helperQueue.push(root.right);
|
||||||
|
}
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
tempNode1 = helperQueue.shift()!;
|
||||||
|
tempNode2 = helperQueue.shift()!;
|
||||||
|
if (tempNode1 === null && tempNode2 === null) continue;
|
||||||
|
if (tempNode1 === null || tempNode2 === null) return false;
|
||||||
|
if (tempNode1.val !== tempNode2.val) return false;
|
||||||
|
helperQueue.push(tempNode1.left);
|
||||||
|
helperQueue.push(tempNode2.right);
|
||||||
|
helperQueue.push(tempNode1.right);
|
||||||
|
helperQueue.push(tempNode2.left);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 迭代法(栈)
|
||||||
|
function isSymmetric(root: TreeNode | null): boolean {
|
||||||
|
let helperStack: (TreeNode | null)[] = [];
|
||||||
|
let tempNode1: TreeNode | null,
|
||||||
|
tempNode2: TreeNode | null;
|
||||||
|
if (root !== null) {
|
||||||
|
helperStack.push(root.left);
|
||||||
|
helperStack.push(root.right);
|
||||||
|
}
|
||||||
|
while (helperStack.length > 0) {
|
||||||
|
tempNode1 = helperStack.pop()!;
|
||||||
|
tempNode2 = helperStack.pop()!;
|
||||||
|
if (tempNode1 === null && tempNode2 === null) continue;
|
||||||
|
if (tempNode1 === null || tempNode2 === null) return false;
|
||||||
|
if (tempNode1.val !== tempNode2.val) return false;
|
||||||
|
helperStack.push(tempNode1.left);
|
||||||
|
helperStack.push(tempNode2.right);
|
||||||
|
helperStack.push(tempNode1.right);
|
||||||
|
helperStack.push(tempNode2.left);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## Swift:
|
## Swift:
|
||||||
|
|
||||||
> 递归
|
> 递归
|
||||||
|
|
|
||||||
|
|
@ -83,10 +83,10 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
python代码:
|
python3代码:
|
||||||
|
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
|
|
||||||
class Solution:
|
class Solution:
|
||||||
"""二叉树层序遍历迭代解法"""
|
"""二叉树层序遍历迭代解法"""
|
||||||
|
|
@ -246,31 +246,56 @@ var levelOrder = function(root) {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
TypeScript:
|
||||||
```swift
|
|
||||||
func levelOrder(_ root: TreeNode?) -> [[Int]] {
|
```typescript
|
||||||
var res = [[Int]]()
|
function levelOrder(root: TreeNode | null): number[][] {
|
||||||
guard let root = root else {
|
let helperQueue: TreeNode[] = [];
|
||||||
return res
|
let res: number[][] = [];
|
||||||
}
|
let tempArr: number[] = [];
|
||||||
var queue = [TreeNode]()
|
if (root !== null) helperQueue.push(root);
|
||||||
queue.append(root)
|
let curNode: TreeNode;
|
||||||
while !queue.isEmpty {
|
while (helperQueue.length > 0) {
|
||||||
let size = queue.count
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
var sub = [Int]()
|
curNode = helperQueue.shift()!;
|
||||||
for _ in 0 ..< size {
|
tempArr.push(curNode.val);
|
||||||
let node = queue.removeFirst()
|
if (curNode.left !== null) {
|
||||||
sub.append(node.val)
|
helperQueue.push(curNode.left);
|
||||||
if let left = node.left {
|
|
||||||
queue.append(left)
|
|
||||||
}
|
}
|
||||||
if let right = node.right {
|
if (curNode.right !== null) {
|
||||||
queue.append(right)
|
helperQueue.push(curNode.right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.append(sub)
|
res.push(tempArr);
|
||||||
|
tempArr = [];
|
||||||
}
|
}
|
||||||
return res
|
return res;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func levelOrder(_ root: TreeNode?) -> [[Int]] {
|
||||||
|
var result = [[Int]]()
|
||||||
|
guard let root = root else { return result }
|
||||||
|
// 表示一层
|
||||||
|
var queue = [root]
|
||||||
|
while !queue.isEmpty {
|
||||||
|
let count = queue.count
|
||||||
|
var subarray = [Int]()
|
||||||
|
for _ in 0 ..< count {
|
||||||
|
// 当前层
|
||||||
|
let node = queue.removeFirst()
|
||||||
|
subarray.append(node.val)
|
||||||
|
// 下一层
|
||||||
|
if let node = node.left { queue.append(node) }
|
||||||
|
if let node = node.right { queue.append(node) }
|
||||||
|
}
|
||||||
|
result.append(subarray)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -454,29 +479,52 @@ var levelOrderBottom = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function levelOrderBottom(root: TreeNode | null): number[][] {
|
||||||
|
let helperQueue: TreeNode[] = [];
|
||||||
|
let resArr: number[][] = [];
|
||||||
|
let tempArr: number[] = [];
|
||||||
|
let tempNode: TreeNode;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
tempNode = helperQueue.shift()!;
|
||||||
|
tempArr.push(tempNode.val);
|
||||||
|
if (tempNode.left !== null) helperQueue.push(tempNode.left);
|
||||||
|
if (tempNode.right !== null) helperQueue.push(tempNode.right);
|
||||||
|
}
|
||||||
|
resArr.push(tempArr);
|
||||||
|
tempArr = [];
|
||||||
|
}
|
||||||
|
return resArr.reverse();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func levelOrderBottom(_ root: TreeNode?) -> [[Int]] {
|
func levelOrderBottom(_ root: TreeNode?) -> [[Int]] {
|
||||||
var res = [[Int]]()
|
// 表示一层
|
||||||
guard let root = root else {
|
var queue = [TreeNode]()
|
||||||
return res
|
if let node = root { queue.append(node) }
|
||||||
}
|
var result = [[Int]]()
|
||||||
var queue: [TreeNode] = [root]
|
|
||||||
while !queue.isEmpty {
|
while !queue.isEmpty {
|
||||||
var sub = [Int]()
|
let count = queue.count
|
||||||
for _ in 0 ..< queue.count {
|
var subarray = [Int]()
|
||||||
|
for _ in 0 ..< count {
|
||||||
|
// 当前层
|
||||||
let node = queue.removeFirst()
|
let node = queue.removeFirst()
|
||||||
sub.append(node.val)
|
subarray.append(node.val)
|
||||||
if let left = node.left {
|
// 下一层
|
||||||
queue.append(left)
|
if let node = node.left { queue.append(node) }
|
||||||
}
|
if let node = node.right { queue.append(node)}
|
||||||
if let right = node.right {
|
|
||||||
queue.append(right)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res.insert(sub, at: 0)
|
result.append(subarray)
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
|
return result.reversed()
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -657,35 +705,50 @@ var rightSideView = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
TypeScript:
|
||||||
```swift
|
|
||||||
func rightSideView(_ root: TreeNode?) -> [Int] {
|
```typescript
|
||||||
var res = [Int]()
|
function rightSideView(root: TreeNode | null): number[] {
|
||||||
guard let root = root else {
|
let helperQueue: TreeNode[] = [];
|
||||||
return res
|
let resArr: number[] = [];
|
||||||
}
|
let tempNode: TreeNode;
|
||||||
var queue = [TreeNode]()
|
if (root !== null) helperQueue.push(root);
|
||||||
queue.append(root)
|
while (helperQueue.length > 0) {
|
||||||
while !queue.isEmpty {
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
let size = queue.count
|
tempNode = helperQueue.shift()!;
|
||||||
for i in 0 ..< size {
|
if (i === length - 1) resArr.push(tempNode.val);
|
||||||
let node = queue.removeFirst()
|
if (tempNode.left !== null) helperQueue.push(tempNode.left);
|
||||||
if i == size - 1 {
|
if (tempNode.right !== null) helperQueue.push(tempNode.right);
|
||||||
// 保存 每层最后一个元素
|
|
||||||
res.append(node.val)
|
|
||||||
}
|
|
||||||
if let left = node.left {
|
|
||||||
queue.append(left)
|
|
||||||
}
|
|
||||||
if let right = node.right {
|
|
||||||
queue.append(right)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res
|
return resArr;
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func rightSideView(_ root: TreeNode?) -> [Int] {
|
||||||
|
// 表示一层
|
||||||
|
var queue = [TreeNode]()
|
||||||
|
if let node = root { queue.append(node) }
|
||||||
|
var result = [Int]()
|
||||||
|
while !queue.isEmpty {
|
||||||
|
let count = queue.count
|
||||||
|
for i in 0 ..< count {
|
||||||
|
// 当前层
|
||||||
|
let node = queue.removeFirst()
|
||||||
|
if i == count - 1 { result.append(node.val) }
|
||||||
|
|
||||||
|
// 下一层
|
||||||
|
if let node = node.left { queue.append(node) }
|
||||||
|
if let node = node.right { queue.append(node) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# 637.二叉树的层平均值
|
# 637.二叉树的层平均值
|
||||||
|
|
||||||
|
|
@ -868,31 +931,54 @@ var averageOfLevels = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function averageOfLevels(root: TreeNode | null): number[] {
|
||||||
|
let helperQueue: TreeNode[] = [];
|
||||||
|
let resArr: number[] = [];
|
||||||
|
let total: number = 0;
|
||||||
|
let tempNode: TreeNode;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
let length = helperQueue.length;
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
tempNode = helperQueue.shift()!;
|
||||||
|
total += tempNode.val;
|
||||||
|
if (tempNode.left) helperQueue.push(tempNode.left);
|
||||||
|
if (tempNode.right) helperQueue.push(tempNode.right);
|
||||||
|
}
|
||||||
|
resArr.push(total / length);
|
||||||
|
total = 0;
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func averageOfLevels(_ root: TreeNode?) -> [Double] {
|
func averageOfLevels(_ root: TreeNode?) -> [Double] {
|
||||||
var res = [Double]()
|
// 表示一层
|
||||||
guard let root = root else {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
var queue = [TreeNode]()
|
var queue = [TreeNode]()
|
||||||
queue.append(root)
|
if let node = root { queue.append(node) }
|
||||||
|
var result = [Double]()
|
||||||
while !queue.isEmpty {
|
while !queue.isEmpty {
|
||||||
let size = queue.count
|
let count = queue.count
|
||||||
var sum = 0
|
var sum = 0
|
||||||
for _ in 0 ..< size {
|
for _ in 0 ..< count {
|
||||||
|
// 当前层
|
||||||
let node = queue.removeFirst()
|
let node = queue.removeFirst()
|
||||||
sum += node.val
|
sum += node.val
|
||||||
if let left = node.left {
|
|
||||||
queue.append(left)
|
// 下一层
|
||||||
}
|
if let node = node.left { queue.append(node) }
|
||||||
if let right = node.right {
|
if let node = node.right { queue.append(node) }
|
||||||
queue.append(right)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res.append(Double(sum) / Double(size))
|
result.append(Double(sum) / Double(count))
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -1092,28 +1178,50 @@ var levelOrder = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function levelOrder(root: Node | null): number[][] {
|
||||||
|
let helperQueue: Node[] = [];
|
||||||
|
let resArr: number[][] = [];
|
||||||
|
let tempArr: number[] = [];
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
let curNode: Node;
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
curNode = helperQueue.shift()!;
|
||||||
|
tempArr.push(curNode.val);
|
||||||
|
helperQueue.push(...curNode.children);
|
||||||
|
}
|
||||||
|
resArr.push(tempArr);
|
||||||
|
tempArr = [];
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func levelOrder(_ root: Node?) -> [[Int]] {
|
func levelOrder(_ root: Node?) -> [[Int]] {
|
||||||
var res = [[Int]]()
|
// 表示一层
|
||||||
guard let root = root else {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
var queue = [Node]()
|
var queue = [Node]()
|
||||||
queue.append(root)
|
if let node = root { queue.append(node) }
|
||||||
|
var result = [[Int]]()
|
||||||
while !queue.isEmpty {
|
while !queue.isEmpty {
|
||||||
let size = queue.count
|
let count = queue.count
|
||||||
var sub = [Int]()
|
var subarray = [Int]()
|
||||||
for _ in 0 ..< size {
|
for _ in 0 ..< count {
|
||||||
|
// 当前层
|
||||||
let node = queue.removeFirst()
|
let node = queue.removeFirst()
|
||||||
sub.append(node.val)
|
subarray.append(node.val)
|
||||||
for childNode in node.children {
|
// 下一层
|
||||||
queue.append(childNode)
|
for node in node.children { queue.append(node) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res.append(sub)
|
result.append(subarray)
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -1179,23 +1287,23 @@ java代码:
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
public List<Integer> largestValues(TreeNode root) {
|
public List<Integer> largestValues(TreeNode root) {
|
||||||
List<Integer> retVal = new ArrayList<Integer>();
|
if(root == null){
|
||||||
Queue<TreeNode> tmpQueue = new LinkedList<TreeNode>();
|
return Collections.emptyList();
|
||||||
if (root != null) tmpQueue.add(root);
|
}
|
||||||
|
List<Integer> result = new ArrayList();
|
||||||
while (tmpQueue.size() != 0){
|
Queue<TreeNode> queue = new LinkedList();
|
||||||
int size = tmpQueue.size();
|
queue.offer(root);
|
||||||
List<Integer> lvlVals = new ArrayList<Integer>();
|
while(!queue.isEmpty()){
|
||||||
for (int index = 0; index < size; index++){
|
int max = Integer.MIN_VALUE;
|
||||||
TreeNode node = tmpQueue.poll();
|
for(int i = queue.size(); i > 0; i--){
|
||||||
lvlVals.add(node.val);
|
TreeNode node = queue.poll();
|
||||||
if (node.left != null) tmpQueue.add(node.left);
|
max = Math.max(max, node.val);
|
||||||
if (node.right != null) tmpQueue.add(node.right);
|
if(node.left != null) queue.offer(node.left);
|
||||||
}
|
if(node.right != null) queue.offer(node.right);
|
||||||
retVal.add(Collections.max(lvlVals));
|
}
|
||||||
}
|
result.add(max);
|
||||||
|
}
|
||||||
return retVal;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -1272,33 +1380,56 @@ var largestValues = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function largestValues(root: TreeNode | null): number[] {
|
||||||
|
let helperQueue: TreeNode[] = [];
|
||||||
|
let resArr: number[] = [];
|
||||||
|
let tempNode: TreeNode;
|
||||||
|
let max: number = 0;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
tempNode = helperQueue.shift()!;
|
||||||
|
if (i === 0) {
|
||||||
|
max = tempNode.val;
|
||||||
|
} else {
|
||||||
|
max = max > tempNode.val ? max : tempNode.val;
|
||||||
|
}
|
||||||
|
if (tempNode.left) helperQueue.push(tempNode.left);
|
||||||
|
if (tempNode.right) helperQueue.push(tempNode.right);
|
||||||
|
}
|
||||||
|
resArr.push(max);
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func largestValues(_ root: TreeNode?) -> [Int] {
|
func largestValues(_ root: TreeNode?) -> [Int] {
|
||||||
var res = [Int]()
|
// 表示一层
|
||||||
guard let root = root else {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
var queue = [TreeNode]()
|
var queue = [TreeNode]()
|
||||||
queue.append(root)
|
if let node = root { queue.append(node) }
|
||||||
|
var result = [Int]()
|
||||||
while !queue.isEmpty {
|
while !queue.isEmpty {
|
||||||
let size = queue.count
|
let count = queue.count
|
||||||
var max: Int = Int.min
|
var max = queue[0].val
|
||||||
for _ in 0 ..< size {
|
for _ in 0 ..< count {
|
||||||
|
// 当前层
|
||||||
let node = queue.removeFirst()
|
let node = queue.removeFirst()
|
||||||
if node.val > max {
|
if node.val > max { max = node.val }
|
||||||
max = node.val
|
|
||||||
}
|
// 下一层
|
||||||
if let left = node.left {
|
if let node = node.left { queue.append(node) }
|
||||||
queue.append(left)
|
if let node = node.right { queue.append(node) }
|
||||||
}
|
|
||||||
if let right = node.right {
|
|
||||||
queue.append(right)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res.append(max)
|
result.append(max)
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -1308,7 +1439,7 @@ func largestValues(_ root: TreeNode?) -> [Int] {
|
||||||
|
|
||||||
给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
|
给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
struct Node {
|
struct Node {
|
||||||
int val;
|
int val;
|
||||||
Node *left;
|
Node *left;
|
||||||
|
|
@ -1463,6 +1594,31 @@ var connect = function(root) {
|
||||||
};
|
};
|
||||||
|
|
||||||
```
|
```
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function connect(root: Node | null): Node | null {
|
||||||
|
let helperQueue: Node[] = [];
|
||||||
|
let preNode: Node, curNode: Node;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
if (i === 0) {
|
||||||
|
preNode = helperQueue.shift()!;
|
||||||
|
} else {
|
||||||
|
curNode = helperQueue.shift()!;
|
||||||
|
preNode.next = curNode;
|
||||||
|
preNode = curNode;
|
||||||
|
}
|
||||||
|
if (preNode.left) helperQueue.push(preNode.left);
|
||||||
|
if (preNode.right) helperQueue.push(preNode.right);
|
||||||
|
}
|
||||||
|
preNode.next = null;
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
go:
|
go:
|
||||||
|
|
||||||
```GO
|
```GO
|
||||||
|
|
@ -1504,33 +1660,34 @@ func connect(root *Node) *Node {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func connect(_ root: Node?) -> Node? {
|
func connect(_ root: Node?) -> Node? {
|
||||||
guard let root = root else {
|
// 表示一层
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var queue = [Node]()
|
var queue = [Node]()
|
||||||
queue.append(root)
|
if let node = root { queue.append(node) }
|
||||||
while !queue.isEmpty {
|
while !queue.isEmpty {
|
||||||
let size = queue.count
|
let count = queue.count
|
||||||
var preNode: Node?
|
var current, previous: Node!
|
||||||
for i in 0 ..< size {
|
for i in 0 ..< count {
|
||||||
let node = queue.removeFirst()
|
// 当前层
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
preNode = node
|
previous = queue.removeFirst()
|
||||||
|
current = previous
|
||||||
} else {
|
} else {
|
||||||
preNode?.next = node
|
current = queue.removeFirst()
|
||||||
preNode = node
|
previous.next = current
|
||||||
}
|
previous = current
|
||||||
if let left = node.left {
|
|
||||||
queue.append(left)
|
|
||||||
}
|
|
||||||
if let right = node.right {
|
|
||||||
queue.append(right)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 下一层
|
||||||
|
if let node = current.left { queue.append(node) }
|
||||||
|
if let node = current.right { queue.append(node) }
|
||||||
}
|
}
|
||||||
|
previous.next = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -1689,6 +1846,31 @@ var connect = function(root) {
|
||||||
return root;
|
return root;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function connect(root: Node | null): Node | null {
|
||||||
|
let helperQueue: Node[] = [];
|
||||||
|
let preNode: Node, curNode: Node;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
if (i === 0) {
|
||||||
|
preNode = helperQueue.shift()!;
|
||||||
|
} else {
|
||||||
|
curNode = helperQueue.shift()!;
|
||||||
|
preNode.next = curNode;
|
||||||
|
preNode = curNode;
|
||||||
|
}
|
||||||
|
if (preNode.left) helperQueue.push(preNode.left);
|
||||||
|
if (preNode.right) helperQueue.push(preNode.right);
|
||||||
|
}
|
||||||
|
preNode.next = null;
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
go:
|
go:
|
||||||
|
|
||||||
```GO
|
```GO
|
||||||
|
|
@ -1729,34 +1911,34 @@ func connect(root *Node) *Node {
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func connect(_ root: Node?) -> Node? {
|
func connect(_ root: Node?) -> Node? {
|
||||||
guard let root = root else {
|
// 表示一层
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var queue = [Node]()
|
var queue = [Node]()
|
||||||
queue.append(root)
|
if let node = root { queue.append(node) }
|
||||||
while !queue.isEmpty {
|
while !queue.isEmpty {
|
||||||
let size = queue.count
|
let count = queue.count
|
||||||
var preNode: Node?
|
var current, previous: Node!
|
||||||
for i in 0 ..< size {
|
for i in 0 ..< count {
|
||||||
let node = queue.removeFirst()
|
// 当前层
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
preNode = node
|
previous = queue.removeFirst()
|
||||||
|
current = previous
|
||||||
} else {
|
} else {
|
||||||
preNode?.next = node
|
current = queue.removeFirst()
|
||||||
preNode = node
|
previous.next = current
|
||||||
}
|
previous = current
|
||||||
if let left = node.left {
|
|
||||||
queue.append(left)
|
|
||||||
}
|
|
||||||
if let right = node.right {
|
|
||||||
queue.append(right)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 下一层
|
||||||
|
if let node = current.left { queue.append(node) }
|
||||||
|
if let node = current.right { queue.append(node) }
|
||||||
}
|
}
|
||||||
|
previous.next = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -1933,28 +2115,48 @@ var maxDepth = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function maxDepth(root: TreeNode | null): number {
|
||||||
|
let helperQueue: TreeNode[] = [];
|
||||||
|
let resDepth: number = 0;
|
||||||
|
let tempNode: TreeNode;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
resDepth++;
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
tempNode = helperQueue.shift()!;
|
||||||
|
if (tempNode.left) helperQueue.push(tempNode.left);
|
||||||
|
if (tempNode.right) helperQueue.push(tempNode.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resDepth;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func maxDepth(_ root: TreeNode?) -> Int {
|
func maxDepth(_ root: TreeNode?) -> Int {
|
||||||
guard let root = root else {
|
guard root != nil else { return 0 }
|
||||||
return 0
|
var depth = 0
|
||||||
}
|
|
||||||
var queue = [TreeNode]()
|
var queue = [TreeNode]()
|
||||||
queue.append(root)
|
queue.append(root!)
|
||||||
var res: Int = 0
|
|
||||||
while !queue.isEmpty {
|
while !queue.isEmpty {
|
||||||
for _ in 0 ..< queue.count {
|
let count = queue.count
|
||||||
|
depth += 1
|
||||||
|
for _ in 0 ..< count {
|
||||||
|
// 当前层
|
||||||
let node = queue.removeFirst()
|
let node = queue.removeFirst()
|
||||||
if let left = node.left {
|
|
||||||
queue.append(left)
|
// 下一层
|
||||||
}
|
if let node = node.left { queue.append(node) }
|
||||||
if let right = node.right {
|
if let node = node.right { queue.append(node) }
|
||||||
queue.append(right)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
res += 1
|
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
|
return depth
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -2130,31 +2332,50 @@ var minDepth = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
TypeScript:
|
||||||
```swift
|
|
||||||
func minDepth(_ root: TreeNode?) -> Int {
|
```typescript
|
||||||
guard let root = root else {
|
function minDepth(root: TreeNode | null): number {
|
||||||
return 0
|
let helperQueue: TreeNode[] = [];
|
||||||
}
|
let resMin: number = 0;
|
||||||
var res = 0
|
let tempNode: TreeNode;
|
||||||
var queue = [TreeNode]()
|
if (root !== null) helperQueue.push(root);
|
||||||
queue.append(root)
|
while (helperQueue.length > 0) {
|
||||||
while !queue.isEmpty {
|
resMin++;
|
||||||
res += 1
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
for _ in 0 ..< queue.count {
|
tempNode = helperQueue.shift()!;
|
||||||
let node = queue.removeFirst()
|
if (tempNode.left === null && tempNode.right === null) return resMin;
|
||||||
if node.left == nil && node.right == nil {
|
if (tempNode.left !== null) helperQueue.push(tempNode.left);
|
||||||
return res
|
if (tempNode.right !== null) helperQueue.push(tempNode.right);
|
||||||
}
|
|
||||||
if let left = node.left {
|
|
||||||
queue.append(left)
|
|
||||||
}
|
|
||||||
if let right = node.right {
|
|
||||||
queue.append(right)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res
|
return resMin;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func minDepth(_ root: TreeNode?) -> Int {
|
||||||
|
guard root != nil else { return 0 }
|
||||||
|
var depth = 0
|
||||||
|
var queue = [root!]
|
||||||
|
while !queue.isEmpty {
|
||||||
|
let count = queue.count
|
||||||
|
depth += 1
|
||||||
|
for _ in 0 ..< count {
|
||||||
|
// 当前层
|
||||||
|
let node = queue.removeFirst()
|
||||||
|
if node.left == nil, node.right == nil { // 遇到叶子结点则返回
|
||||||
|
return depth
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下一层
|
||||||
|
if let node = node.left { queue.append(node) }
|
||||||
|
if let node = node.right { queue.append(node) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return depth
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -523,8 +523,8 @@ func maxdepth(root *treenode) int {
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var maxdepth = function(root) {
|
var maxdepth = function(root) {
|
||||||
if (!root) return root
|
if (root === null) return 0;
|
||||||
return 1 + math.max(maxdepth(root.left), maxdepth(root.right))
|
return 1 + Math.max(maxdepth(root.left), maxdepth(root.right))
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -541,7 +541,7 @@ var maxdepth = function(root) {
|
||||||
//3. 确定单层逻辑
|
//3. 确定单层逻辑
|
||||||
let leftdepth=getdepth(node.left);
|
let leftdepth=getdepth(node.left);
|
||||||
let rightdepth=getdepth(node.right);
|
let rightdepth=getdepth(node.right);
|
||||||
let depth=1+math.max(leftdepth,rightdepth);
|
let depth=1+Math.max(leftdepth,rightdepth);
|
||||||
return depth;
|
return depth;
|
||||||
}
|
}
|
||||||
return getdepth(root);
|
return getdepth(root);
|
||||||
|
|
@ -591,14 +591,90 @@ var maxDepth = function(root) {
|
||||||
count++
|
count++
|
||||||
while(size--) {
|
while(size--) {
|
||||||
let node = queue.shift()
|
let node = queue.shift()
|
||||||
node && (queue = [...queue, ...node.children])
|
for (let item of node.children) {
|
||||||
|
item && queue.push(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count
|
return count
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript:
|
||||||
|
|
||||||
|
> 二叉树的最大深度:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 后续遍历(自下而上)
|
||||||
|
function maxDepth(root: TreeNode | null): number {
|
||||||
|
if (root === null) return 0;
|
||||||
|
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 前序遍历(自上而下)
|
||||||
|
function maxDepth(root: TreeNode | null): number {
|
||||||
|
function recur(node: TreeNode | null, count: number) {
|
||||||
|
if (node === null) {
|
||||||
|
resMax = resMax > count ? resMax : count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
recur(node.left, count + 1);
|
||||||
|
recur(node.right, count + 1);
|
||||||
|
}
|
||||||
|
let resMax: number = 0;
|
||||||
|
let count: number = 0;
|
||||||
|
recur(root, count);
|
||||||
|
return resMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 层序遍历(迭代法)
|
||||||
|
function maxDepth(root: TreeNode | null): number {
|
||||||
|
let helperQueue: TreeNode[] = [];
|
||||||
|
let resDepth: number = 0;
|
||||||
|
let tempNode: TreeNode;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
resDepth++;
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
tempNode = helperQueue.shift()!;
|
||||||
|
if (tempNode.left) helperQueue.push(tempNode.left);
|
||||||
|
if (tempNode.right) helperQueue.push(tempNode.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resDepth;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> N叉树的最大深度
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 后续遍历(自下而上)
|
||||||
|
function maxDepth(root: TreeNode | null): number {
|
||||||
|
if (root === null) return 0;
|
||||||
|
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 前序遍历(自上而下)
|
||||||
|
function maxDepth(root: TreeNode | null): number {
|
||||||
|
function recur(node: TreeNode | null, count: number) {
|
||||||
|
if (node === null) {
|
||||||
|
resMax = resMax > count ? resMax : count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
recur(node.left, count + 1);
|
||||||
|
recur(node.right, count + 1);
|
||||||
|
}
|
||||||
|
let resMax: number = 0;
|
||||||
|
let count: number = 0;
|
||||||
|
recur(root, count);
|
||||||
|
return resMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
二叉树最大深度递归
|
二叉树最大深度递归
|
||||||
```c
|
```c
|
||||||
int maxDepth(struct TreeNode* root){
|
int maxDepth(struct TreeNode* root){
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,9 @@ TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
|
||||||
|
|
||||||
**难点大家应该发现了,就是如何切割,以及边界值找不好很容易乱套。**
|
**难点大家应该发现了,就是如何切割,以及边界值找不好很容易乱套。**
|
||||||
|
|
||||||
此时应该注意确定切割的标准,是左闭右开,还有左开又闭,还是左闭又闭,这个就是不变量,要在递归中保持这个不变量。
|
此时应该注意确定切割的标准,是左闭右开,还有左开右闭,还是左闭右闭,这个就是不变量,要在递归中保持这个不变量。
|
||||||
|
|
||||||
**在切割的过程中会产生四个区间,把握不好不变量的话,一会左闭右开,一会左闭又闭,必然乱套!**
|
**在切割的过程中会产生四个区间,把握不好不变量的话,一会左闭右开,一会左闭右闭,必然乱套!**
|
||||||
|
|
||||||
我在[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0035.搜索插入位置.html)和[数组:这个循环可以转懵很多人!](https://programmercarl.com/0059.螺旋矩阵II.html)中都强调过循环不变量的重要性,在二分查找以及螺旋矩阵的求解中,坚持循环不变量非常重要,本题也是。
|
我在[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0035.搜索插入位置.html)和[数组:这个循环可以转懵很多人!](https://programmercarl.com/0059.螺旋矩阵II.html)中都强调过循环不变量的重要性,在二分查找以及螺旋矩阵的求解中,坚持循环不变量非常重要,本题也是。
|
||||||
|
|
||||||
|
|
@ -103,7 +103,7 @@ TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
|
||||||
中序数组相对比较好切,找到切割点(后序数组的最后一个元素)在中序数组的位置,然后切割,如下代码中我坚持左闭右开的原则:
|
中序数组相对比较好切,找到切割点(后序数组的最后一个元素)在中序数组的位置,然后切割,如下代码中我坚持左闭右开的原则:
|
||||||
|
|
||||||
|
|
||||||
```C++
|
```CPP
|
||||||
// 找到中序遍历的切割点
|
// 找到中序遍历的切割点
|
||||||
int delimiterIndex;
|
int delimiterIndex;
|
||||||
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
|
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
|
||||||
|
|
@ -130,7 +130,7 @@ vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
// postorder 舍弃末尾元素,因为这个元素就是中间节点,已经用过了
|
// postorder 舍弃末尾元素,因为这个元素就是中间节点,已经用过了
|
||||||
postorder.resize(postorder.size() - 1);
|
postorder.resize(postorder.size() - 1);
|
||||||
|
|
||||||
|
|
@ -144,7 +144,7 @@ vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end
|
||||||
|
|
||||||
接下来可以递归了,代码如下:
|
接下来可以递归了,代码如下:
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
root->left = traversal(leftInorder, leftPostorder);
|
root->left = traversal(leftInorder, leftPostorder);
|
||||||
root->right = traversal(rightInorder, rightPostorder);
|
root->right = traversal(rightInorder, rightPostorder);
|
||||||
```
|
```
|
||||||
|
|
@ -790,7 +790,7 @@ func findRootIndex(target int,inorder []int) int{
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var buildTree = function(inorder, postorder) {
|
var buildTree = function(inorder, postorder) {
|
||||||
if (!preorder.length) return null;
|
if (!inorder.length) return null;
|
||||||
const rootVal = postorder.pop(); // 从后序遍历的数组中获取中间节点的值, 即数组最后一个值
|
const rootVal = postorder.pop(); // 从后序遍历的数组中获取中间节点的值, 即数组最后一个值
|
||||||
let rootIndex = inorder.indexOf(rootVal); // 获取中间节点在中序遍历中的下标
|
let rootIndex = inorder.indexOf(rootVal); // 获取中间节点在中序遍历中的下标
|
||||||
const root = new TreeNode(rootVal); // 创建中间节点
|
const root = new TreeNode(rootVal); // 创建中间节点
|
||||||
|
|
@ -814,7 +814,114 @@ var buildTree = function(preorder, inorder) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
> 106.从中序与后序遍历序列构造二叉树
|
||||||
|
|
||||||
|
**创建新数组:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function buildTree(inorder: number[], postorder: number[]): TreeNode | null {
|
||||||
|
if (postorder.length === 0) return null;
|
||||||
|
const rootVal: number = postorder.pop()!;
|
||||||
|
const rootValIndex: number = inorder.indexOf(rootVal);
|
||||||
|
const rootNode: TreeNode = new TreeNode(rootVal);
|
||||||
|
rootNode.left = buildTree(inorder.slice(0, rootValIndex), postorder.slice(0, rootValIndex));
|
||||||
|
rootNode.right = buildTree(inorder.slice(rootValIndex + 1), postorder.slice(rootValIndex));
|
||||||
|
return rootNode;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用数组索引:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function buildTree(inorder: number[], postorder: number[]): TreeNode | null {
|
||||||
|
function recur(
|
||||||
|
inorder: number[], postorder: number[],
|
||||||
|
inBegin: number, inEnd: number,
|
||||||
|
postBegin: number, postEnd: number
|
||||||
|
): TreeNode | null {
|
||||||
|
if (postBegin === postEnd) return null;
|
||||||
|
const rootVal: number = postorder[postEnd - 1]!;
|
||||||
|
const rootValIndex: number = inorder.indexOf(rootVal, inBegin);
|
||||||
|
const rootNode: TreeNode = new TreeNode(rootVal);
|
||||||
|
|
||||||
|
const leftInorderBegin: number = inBegin;
|
||||||
|
const leftInorderEnd: number = rootValIndex;
|
||||||
|
const rightInorderBegin: number = rootValIndex + 1;
|
||||||
|
const rightInorderEnd: number = inEnd;
|
||||||
|
|
||||||
|
const leftPostorderBegin: number = postBegin;
|
||||||
|
const leftPostorderEnd: number = postBegin + rootValIndex - inBegin;
|
||||||
|
const rightPostorderBegin: number = leftPostorderEnd;
|
||||||
|
const rightPostorderEnd: number = postEnd - 1;
|
||||||
|
|
||||||
|
rootNode.left = recur(
|
||||||
|
inorder, postorder,
|
||||||
|
leftInorderBegin, leftInorderEnd,
|
||||||
|
leftPostorderBegin, leftPostorderEnd
|
||||||
|
);
|
||||||
|
rootNode.right = recur(
|
||||||
|
inorder, postorder,
|
||||||
|
rightInorderBegin, rightInorderEnd,
|
||||||
|
rightPostorderBegin, rightPostorderEnd
|
||||||
|
);
|
||||||
|
return rootNode;
|
||||||
|
}
|
||||||
|
return recur(inorder, postorder, 0, inorder.length, 0, inorder.length);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 105.从前序与中序遍历序列构造二叉树
|
||||||
|
|
||||||
|
**新建数组:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function buildTree(preorder: number[], inorder: number[]): TreeNode | null {
|
||||||
|
if (preorder.length === 0) return null;
|
||||||
|
const rootVal: number = preorder[0];
|
||||||
|
const rootNode: TreeNode = new TreeNode(rootVal);
|
||||||
|
const rootValIndex: number = inorder.indexOf(rootVal);
|
||||||
|
rootNode.left = buildTree(preorder.slice(1, rootValIndex + 1), inorder.slice(0, rootValIndex));
|
||||||
|
rootNode.right = buildTree(preorder.slice(rootValIndex + 1), inorder.slice(rootValIndex + 1));
|
||||||
|
return rootNode;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用数组索引:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function buildTree(preorder: number[], inorder: number[]): TreeNode | null {
|
||||||
|
function recur(
|
||||||
|
preorder: number[], inorder: number[],
|
||||||
|
preBegin: number, preEnd: number,
|
||||||
|
inBegin: number, inEnd: number
|
||||||
|
): TreeNode | null {
|
||||||
|
if (preBegin === preEnd) return null;
|
||||||
|
const rootVal: number = preorder[preBegin];
|
||||||
|
const rootNode: TreeNode = new TreeNode(rootVal);
|
||||||
|
const rootValIndex: number = inorder.indexOf(rootVal, inBegin);
|
||||||
|
|
||||||
|
const leftPreBegin: number = preBegin + 1;
|
||||||
|
const leftPreEnd: number = preBegin + rootValIndex - inBegin + 1;
|
||||||
|
const leftInBegin: number = inBegin;
|
||||||
|
const leftInEnd: number = rootValIndex;
|
||||||
|
|
||||||
|
const rightPreBegin: number = leftPreEnd;
|
||||||
|
const rightPreEnd: number = preEnd;
|
||||||
|
const rightInBegin: number = rootValIndex + 1;
|
||||||
|
const rightInEnd: number = inEnd;
|
||||||
|
|
||||||
|
rootNode.left = recur(preorder, inorder, leftPreBegin, leftPreEnd, leftInBegin, leftInEnd);
|
||||||
|
rootNode.right = recur(preorder, inorder, rightPreBegin, rightPreEnd, rightInBegin, rightInEnd);
|
||||||
|
return rootNode;
|
||||||
|
};
|
||||||
|
return recur(preorder, inorder, 0, preorder.length, 0, inorder.length);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
106 从中序与后序遍历序列构造二叉树
|
106 从中序与后序遍历序列构造二叉树
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,7 @@ class Solution {
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
迭代: 左闭右闭 [left,right]
|
迭代: 左闭右闭 [left,right]
|
||||||
```java
|
```java
|
||||||
|
|
@ -305,7 +305,7 @@ class Solution {
|
||||||
## Python
|
## Python
|
||||||
**递归**
|
**递归**
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
# Definition for a binary tree node.
|
# Definition for a binary tree node.
|
||||||
# class TreeNode:
|
# class TreeNode:
|
||||||
# def __init__(self, val=0, left=None, right=None):
|
# def __init__(self, val=0, left=None, right=None):
|
||||||
|
|
@ -355,6 +355,7 @@ func sortedArrayToBST(nums []int) *TreeNode {
|
||||||
```
|
```
|
||||||
|
|
||||||
## JavaScript
|
## JavaScript
|
||||||
|
递归
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var sortedArrayToBST = function (nums) {
|
var sortedArrayToBST = function (nums) {
|
||||||
|
|
@ -372,8 +373,62 @@ var sortedArrayToBST = function (nums) {
|
||||||
return buildTree(nums, 0, nums.length - 1);
|
return buildTree(nums, 0, nums.length - 1);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
迭代
|
||||||
|
```JavaScript
|
||||||
|
var sortedArrayToBST = function(nums) {
|
||||||
|
if(nums.length===0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let root=new TreeNode(0); //初始根节点
|
||||||
|
let nodeQue=[root]; //放遍历的节点,并初始化
|
||||||
|
let leftQue=[0]; //放左区间的下标,初始化
|
||||||
|
let rightQue=[nums.length-1]; // 放右区间的下标
|
||||||
|
|
||||||
|
while(nodeQue.length){
|
||||||
|
let curNode=nodeQue.pop();
|
||||||
|
let left=leftQue.pop();
|
||||||
|
let right=rightQue.pop();
|
||||||
|
let mid=left+Math.floor((right-left)/2);
|
||||||
|
|
||||||
|
curNode.val=nums[mid]; //将下标为mid的元素给中间节点
|
||||||
|
|
||||||
|
// 处理左区间
|
||||||
|
if(left<=mid-1){
|
||||||
|
curNode.left=new TreeNode(0);
|
||||||
|
nodeQue.push(curNode.left);
|
||||||
|
leftQue.push(left);
|
||||||
|
rightQue.push(mid-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理右区间
|
||||||
|
if(right>=mid+1){
|
||||||
|
curNode.right=new TreeNode(0);
|
||||||
|
nodeQue.push(curNode.right);
|
||||||
|
leftQue.push(mid+1);
|
||||||
|
rightQue.push(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function sortedArrayToBST(nums: number[]): TreeNode | null {
|
||||||
|
function recur(nums: number[], left: number, right: number): TreeNode | null {
|
||||||
|
if (left > right) return null;
|
||||||
|
let mid: number = Math.floor((left + right) / 2);
|
||||||
|
const root: TreeNode = new TreeNode(nums[mid]);
|
||||||
|
root.left = recur(nums, left, mid - 1);
|
||||||
|
root.right = recur(nums, mid + 1, right);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
return recur(nums, 0, nums.length - 1);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
递归
|
递归
|
||||||
```c
|
```c
|
||||||
struct TreeNode* traversal(int* nums, int left, int right) {
|
struct TreeNode* traversal(int* nums, int left, int right) {
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ int getDepth(TreeNode* cur) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
然后再用栈来模拟前序遍历,遍历每一个节点的时候,再去判断左右孩子的高度是否符合,代码如下:
|
然后再用栈来模拟后序遍历,遍历每一个节点的时候,再去判断左右孩子的高度是否符合,代码如下:
|
||||||
|
|
||||||
```CPP
|
```CPP
|
||||||
bool isBalanced(TreeNode* root) {
|
bool isBalanced(TreeNode* root) {
|
||||||
|
|
@ -497,7 +497,7 @@ class Solution {
|
||||||
## Python
|
## Python
|
||||||
|
|
||||||
递归法:
|
递归法:
|
||||||
```python3
|
```python
|
||||||
# Definition for a binary tree node.
|
# Definition for a binary tree node.
|
||||||
# class TreeNode:
|
# class TreeNode:
|
||||||
# def __init__(self, val=0, left=None, right=None):
|
# def __init__(self, val=0, left=None, right=None):
|
||||||
|
|
@ -604,7 +604,8 @@ func abs(a int)int{
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## JavaScript
|
## JavaScript
|
||||||
|
递归法:
|
||||||
```javascript
|
```javascript
|
||||||
var isBalanced = function(root) {
|
var isBalanced = function(root) {
|
||||||
//还是用递归三部曲 + 后序遍历 左右中 当前左子树右子树高度相差大于1就返回-1
|
//还是用递归三部曲 + 后序遍历 左右中 当前左子树右子树高度相差大于1就返回-1
|
||||||
|
|
@ -614,8 +615,10 @@ var isBalanced = function(root) {
|
||||||
if(node === null) return 0;
|
if(node === null) return 0;
|
||||||
// 3. 确定单层递归逻辑
|
// 3. 确定单层递归逻辑
|
||||||
let leftDepth = getDepth(node.left); //左子树高度
|
let leftDepth = getDepth(node.left); //左子树高度
|
||||||
let rightDepth = getDepth(node.right); //右子树高度
|
// 当判定左子树不为平衡二叉树时,即可直接返回-1
|
||||||
if(leftDepth === -1) return -1;
|
if(leftDepth === -1) return -1;
|
||||||
|
let rightDepth = getDepth(node.right); //右子树高度
|
||||||
|
// 当判定右子树不为平衡二叉树时,即可直接返回-1
|
||||||
if(rightDepth === -1) return -1;
|
if(rightDepth === -1) return -1;
|
||||||
if(Math.abs(leftDepth - rightDepth) > 1) {
|
if(Math.abs(leftDepth - rightDepth) > 1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -627,7 +630,68 @@ var isBalanced = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
迭代法:
|
||||||
|
```javascript
|
||||||
|
// 获取当前节点的高度
|
||||||
|
var getHeight = function (curNode) {
|
||||||
|
let queue = [];
|
||||||
|
if (curNode !== null) queue.push(curNode); // 压入当前元素
|
||||||
|
let depth = 0, res = 0;
|
||||||
|
while (queue.length) {
|
||||||
|
let node = queue[queue.length - 1]; // 取出栈顶
|
||||||
|
if (node !== null) {
|
||||||
|
queue.pop();
|
||||||
|
queue.push(node); // 中
|
||||||
|
queue.push(null);
|
||||||
|
depth++;
|
||||||
|
node.right && queue.push(node.right); // 右
|
||||||
|
node.left && queue.push(node.left); // 左
|
||||||
|
} else {
|
||||||
|
queue.pop();
|
||||||
|
node = queue[queue.length - 1];
|
||||||
|
queue.pop();
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
res = res > depth ? res : depth;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
var isBalanced = function (root) {
|
||||||
|
if (root === null) return true;
|
||||||
|
let queue = [root];
|
||||||
|
while (queue.length) {
|
||||||
|
let node = queue[queue.length - 1]; // 取出栈顶
|
||||||
|
queue.pop();
|
||||||
|
if (Math.abs(getHeight(node.left) - getHeight(node.right)) > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
node.right && queue.push(node.right);
|
||||||
|
node.left && queue.push(node.left);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 递归法
|
||||||
|
function isBalanced(root: TreeNode | null): boolean {
|
||||||
|
function getDepth(root: TreeNode | null): number {
|
||||||
|
if (root === null) return 0;
|
||||||
|
let leftDepth: number = getDepth(root.left);
|
||||||
|
if (leftDepth === -1) return -1;
|
||||||
|
let rightDepth: number = getDepth(root.right);
|
||||||
|
if (rightDepth === -1) return -1;
|
||||||
|
if (Math.abs(leftDepth - rightDepth) > 1) return -1;
|
||||||
|
return 1 + Math.max(leftDepth, rightDepth);
|
||||||
|
}
|
||||||
|
return getDepth(root) !== -1;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
递归法:
|
递归法:
|
||||||
```c
|
```c
|
||||||
int getDepth(struct TreeNode* node) {
|
int getDepth(struct TreeNode* node) {
|
||||||
|
|
@ -730,5 +794,33 @@ bool isBalanced(struct TreeNode* root){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Swift:
|
||||||
|
|
||||||
|
>递归
|
||||||
|
```swift
|
||||||
|
func isBalanced(_ root: TreeNode?) -> Bool {
|
||||||
|
// -1 已经不是平衡二叉树
|
||||||
|
return getHeight(root) == -1 ? false : true
|
||||||
|
}
|
||||||
|
func getHeight(_ root: TreeNode?) -> Int {
|
||||||
|
guard let root = root else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
let leftHeight = getHeight(root.left)
|
||||||
|
if leftHeight == -1 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
let rightHeight = getHeight(root.right)
|
||||||
|
if rightHeight == -1 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if abs(leftHeight - rightHeight) > 1 {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return 1 + max(leftHeight, rightHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -404,6 +404,44 @@ var minDepth = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
> 递归法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function minDepth(root: TreeNode | null): number {
|
||||||
|
if (root === null) return 0;
|
||||||
|
if (root.left !== null && root.right === null) {
|
||||||
|
return 1 + minDepth(root.left);
|
||||||
|
}
|
||||||
|
if (root.left === null && root.right !== null) {
|
||||||
|
return 1 + minDepth(root.right);
|
||||||
|
}
|
||||||
|
return 1 + Math.min(minDepth(root.left), minDepth(root.right));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 迭代法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function minDepth(root: TreeNode | null): number {
|
||||||
|
let helperQueue: TreeNode[] = [];
|
||||||
|
let resMin: number = 0;
|
||||||
|
let tempNode: TreeNode;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
resMin++;
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
tempNode = helperQueue.shift()!;
|
||||||
|
if (tempNode.left === null && tempNode.right === null) return resMin;
|
||||||
|
if (tempNode.left !== null) helperQueue.push(tempNode.left);
|
||||||
|
if (tempNode.right !== null) helperQueue.push(tempNode.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resMin;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## Swift
|
## Swift
|
||||||
|
|
||||||
> 递归
|
> 递归
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
如果大家完全理解了本地的递归方法之后,就可以顺便把leetcode上113. 路径总和ii做了。
|
如果大家完全理解了本题的递归方法之后,就可以顺便把leetcode上113. 路径总和ii做了。
|
||||||
|
|
||||||
# 113. 路径总和ii
|
# 113. 路径总和ii
|
||||||
|
|
||||||
|
|
@ -496,25 +496,20 @@ class solution:
|
||||||
def pathsum(self, root: treenode, targetsum: int) -> list[list[int]]:
|
def pathsum(self, root: treenode, targetsum: int) -> list[list[int]]:
|
||||||
|
|
||||||
def traversal(cur_node, remain):
|
def traversal(cur_node, remain):
|
||||||
if not cur_node.left and not cur_node.right and remain == 0:
|
if not cur_node.left and not cur_node.right:
|
||||||
result.append(path[:])
|
if remain == 0:
|
||||||
return
|
result.append(path[:])
|
||||||
|
return
|
||||||
if not cur_node.left and not cur_node.right: return
|
|
||||||
|
|
||||||
if cur_node.left:
|
if cur_node.left:
|
||||||
path.append(cur_node.left.val)
|
path.append(cur_node.left.val)
|
||||||
remain -= cur_node.left.val
|
traversal(cur_node.left, remain-cur_node.left.val)
|
||||||
traversal(cur_node.left, remain)
|
|
||||||
path.pop()
|
path.pop()
|
||||||
remain += cur_node.left.val
|
|
||||||
|
|
||||||
if cur_node.right:
|
if cur_node.right:
|
||||||
path.append(cur_node.right.val)
|
path.append(cur_node.right.val)
|
||||||
remain -= cur_node.right.val
|
traversal(cur_node.right, remain-cur_node.left.val)
|
||||||
traversal(cur_node.right, remain)
|
|
||||||
path.pop()
|
path.pop()
|
||||||
remain += cur_node.right.val
|
|
||||||
|
|
||||||
result, path = [], []
|
result, path = [], []
|
||||||
if not root:
|
if not root:
|
||||||
|
|
@ -524,6 +519,30 @@ class solution:
|
||||||
return result
|
return result
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**迭代法,用第二个队列保存目前的总和与路径**
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
|
||||||
|
if not root:
|
||||||
|
return []
|
||||||
|
que, temp = deque([root]), deque([(root.val, [root.val])])
|
||||||
|
result = []
|
||||||
|
while que:
|
||||||
|
for _ in range(len(que)):
|
||||||
|
node = que.popleft()
|
||||||
|
value, path = temp.popleft()
|
||||||
|
if (not node.left) and (not node.right):
|
||||||
|
if value == targetSum:
|
||||||
|
result.append(path)
|
||||||
|
if node.left:
|
||||||
|
que.append(node.left)
|
||||||
|
temp.append((node.left.val+value, path+[node.left.val]))
|
||||||
|
if node.right:
|
||||||
|
que.append(node.right)
|
||||||
|
temp.append((node.right.val+value, path+[node.right.val]))
|
||||||
|
return result
|
||||||
|
```
|
||||||
|
|
||||||
## go
|
## go
|
||||||
|
|
||||||
112. 路径总和
|
112. 路径总和
|
||||||
|
|
@ -531,82 +550,63 @@ class solution:
|
||||||
```go
|
```go
|
||||||
//递归法
|
//递归法
|
||||||
/**
|
/**
|
||||||
* definition for a binary tree node.
|
* Definition for a binary tree node.
|
||||||
* type treenode struct {
|
* type TreeNode struct {
|
||||||
* val int
|
* Val int
|
||||||
* left *treenode
|
* Left *TreeNode
|
||||||
* right *treenode
|
* Right *TreeNode
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
func haspathsum(root *treenode, targetsum int) bool {
|
func hasPathSum(root *TreeNode, targetSum int) bool {
|
||||||
var flage bool //找没找到的标志
|
if root == nil {
|
||||||
if root==nil{
|
return false
|
||||||
return flage
|
|
||||||
}
|
}
|
||||||
pathsum(root,0,targetsum,&flage)
|
|
||||||
return flage
|
targetSum -= root.Val // 将targetSum在遍历每层的时候都减去本层节点的值
|
||||||
}
|
if root.Left == nil && root.Right == nil && targetSum == 0 { // 如果剩余的targetSum为0, 则正好就是符合的结果
|
||||||
func pathsum(root *treenode, sum int,targetsum int,flage *bool){
|
return true
|
||||||
sum+=root.val
|
|
||||||
if root.left==nil&&root.right==nil&&sum==targetsum{
|
|
||||||
*flage=true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if root.left!=nil&&!(*flage){//左节点不为空且还没找到
|
|
||||||
pathsum(root.left,sum,targetsum,flage)
|
|
||||||
}
|
|
||||||
if root.right!=nil&&!(*flage){//右节点不为空且没找到
|
|
||||||
pathsum(root.right,sum,targetsum,flage)
|
|
||||||
}
|
}
|
||||||
|
return hasPathSum(root.Left, targetSum) || hasPathSum(root.Right, targetSum) // 否则递归找
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
113 递归法
|
113. 路径总和 II
|
||||||
|
|
||||||
```go
|
```go
|
||||||
/**
|
/**
|
||||||
* definition for a binary tree node.
|
* Definition for a binary tree node.
|
||||||
* type treenode struct {
|
* type TreeNode struct {
|
||||||
* val int
|
* Val int
|
||||||
* left *treenode
|
* Left *TreeNode
|
||||||
* right *treenode
|
* Right *TreeNode
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
func pathsum(root *treenode, targetsum int) [][]int {
|
func pathSum(root *TreeNode, targetSum int) [][]int {
|
||||||
var result [][]int//最终结果
|
result := make([][]int, 0)
|
||||||
if root==nil{
|
traverse(root, &result, new([]int), targetSum)
|
||||||
return result
|
|
||||||
}
|
|
||||||
var sumnodes []int//经过路径的节点集合
|
|
||||||
haspathsum(root,&sumnodes,targetsum,&result)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
func haspathsum(root *treenode,sumnodes *[]int,targetsum int,result *[][]int){
|
|
||||||
*sumnodes=append(*sumnodes,root.val)
|
func traverse(node *TreeNode, result *[][]int, currPath *[]int, targetSum int) {
|
||||||
if root.left==nil&&root.right==nil{//叶子节点
|
if node == nil { // 这个判空也可以挪到递归遍历左右子树时去判断
|
||||||
fmt.println(*sumnodes)
|
return
|
||||||
var sum int
|
|
||||||
var number int
|
|
||||||
for k,v:=range *sumnodes{//求该路径节点的和
|
|
||||||
sum+=v
|
|
||||||
number=k
|
|
||||||
}
|
|
||||||
tempnodes:=make([]int,number+1)//新的nodes接受指针里的值,防止最终指针里的值发生变动,导致最后的结果都是最后一个sumnodes的值
|
|
||||||
for k,v:=range *sumnodes{
|
|
||||||
tempnodes[k]=v
|
|
||||||
}
|
|
||||||
if sum==targetsum{
|
|
||||||
*result=append(*result,tempnodes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if root.left!=nil{
|
|
||||||
haspathsum(root.left,sumnodes,targetsum,result)
|
targetSum -= node.Val // 将targetSum在遍历每层的时候都减去本层节点的值
|
||||||
*sumnodes=(*sumnodes)[:len(*sumnodes)-1]//回溯
|
*currPath = append(*currPath, node.Val) // 把当前节点放到路径记录里
|
||||||
}
|
|
||||||
if root.right!=nil{
|
if node.Left == nil && node.Right == nil && targetSum == 0 { // 如果剩余的targetSum为0, 则正好就是符合的结果
|
||||||
haspathsum(root.right,sumnodes,targetsum,result)
|
// 不能直接将currPath放到result里面, 因为currPath是共享的, 每次遍历子树时都会被修改
|
||||||
*sumnodes=(*sumnodes)[:len(*sumnodes)-1]//回溯
|
pathCopy := make([]int, len(*currPath))
|
||||||
|
for i, element := range *currPath {
|
||||||
|
pathCopy[i] = element
|
||||||
|
}
|
||||||
|
*result = append(*result, pathCopy) // 将副本放到结果集里
|
||||||
}
|
}
|
||||||
|
|
||||||
|
traverse(node.Left, result, currPath, targetSum)
|
||||||
|
traverse(node.Right, result, currPath, targetSum)
|
||||||
|
*currPath = (*currPath)[:len(*currPath)-1] // 当前节点遍历完成, 从路径记录里删除掉
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -766,7 +766,245 @@ let pathSum = function(root, targetSum) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
> 0112.路径总和
|
||||||
|
|
||||||
|
**递归法:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function hasPathSum(root: TreeNode | null, targetSum: number): boolean {
|
||||||
|
function recur(node: TreeNode, sum: number): boolean {
|
||||||
|
console.log(sum);
|
||||||
|
if (
|
||||||
|
node.left === null &&
|
||||||
|
node.right === null &&
|
||||||
|
sum === 0
|
||||||
|
) return true;
|
||||||
|
if (node.left !== null) {
|
||||||
|
sum -= node.left.val;
|
||||||
|
if (recur(node.left, sum) === true) return true;
|
||||||
|
sum += node.left.val;
|
||||||
|
}
|
||||||
|
if (node.right !== null) {
|
||||||
|
sum -= node.right.val;
|
||||||
|
if (recur(node.right, sum) === true) return true;
|
||||||
|
sum += node.right.val;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (root === null) return false;
|
||||||
|
return recur(root, targetSum - root.val);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**递归法(精简版):**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function hasPathSum(root: TreeNode | null, targetSum: number): boolean {
|
||||||
|
if (root === null) return false;
|
||||||
|
targetSum -= root.val;
|
||||||
|
if (
|
||||||
|
root.left === null &&
|
||||||
|
root.right === null &&
|
||||||
|
targetSum === 0
|
||||||
|
) return true;
|
||||||
|
return hasPathSum(root.left, targetSum) ||
|
||||||
|
hasPathSum(root.right, targetSum);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**迭代法:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function hasPathSum(root: TreeNode | null, targetSum: number): boolean {
|
||||||
|
type Pair = {
|
||||||
|
node: TreeNode, // 当前节点
|
||||||
|
sum: number // 根节点到当前节点的路径数值总和
|
||||||
|
}
|
||||||
|
|
||||||
|
const helperStack: Pair[] = [];
|
||||||
|
if (root !== null) helperStack.push({ node: root, sum: root.val });
|
||||||
|
let tempPair: Pair;
|
||||||
|
while (helperStack.length > 0) {
|
||||||
|
tempPair = helperStack.pop()!;
|
||||||
|
if (
|
||||||
|
tempPair.node.left === null &&
|
||||||
|
tempPair.node.right === null &&
|
||||||
|
tempPair.sum === targetSum
|
||||||
|
) return true;
|
||||||
|
if (tempPair.node.right !== null) {
|
||||||
|
helperStack.push({
|
||||||
|
node: tempPair.node.right,
|
||||||
|
sum: tempPair.sum + tempPair.node.right.val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (tempPair.node.left !== null) {
|
||||||
|
helperStack.push({
|
||||||
|
node: tempPair.node.left,
|
||||||
|
sum: tempPair.sum + tempPair.node.left.val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 0112.路径总和 ii
|
||||||
|
|
||||||
|
**递归法:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function pathSum(root: TreeNode | null, targetSum: number): number[][] {
|
||||||
|
function recur(node: TreeNode, sumGap: number, routeArr: number[]): void {
|
||||||
|
if (
|
||||||
|
node.left === null &&
|
||||||
|
node.right === null &&
|
||||||
|
sumGap === 0
|
||||||
|
) resArr.push([...routeArr]);
|
||||||
|
if (node.left !== null) {
|
||||||
|
sumGap -= node.left.val;
|
||||||
|
routeArr.push(node.left.val);
|
||||||
|
recur(node.left, sumGap, routeArr);
|
||||||
|
sumGap += node.left.val;
|
||||||
|
routeArr.pop();
|
||||||
|
}
|
||||||
|
if (node.right !== null) {
|
||||||
|
sumGap -= node.right.val;
|
||||||
|
routeArr.push(node.right.val);
|
||||||
|
recur(node.right, sumGap, routeArr);
|
||||||
|
sumGap += node.right.val;
|
||||||
|
routeArr.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
if (root === null) return resArr;
|
||||||
|
const routeArr: number[] = [];
|
||||||
|
routeArr.push(root.val);
|
||||||
|
recur(root, targetSum - root.val, routeArr);
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Swift
|
||||||
|
|
||||||
|
0112.路径总和
|
||||||
|
|
||||||
|
**递归**
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func hasPathSum(_ root: TreeNode?, _ targetSum: Int) -> Bool {
|
||||||
|
guard let root = root else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return traversal(root, targetSum - root.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func traversal(_ cur: TreeNode?, _ count: Int) -> Bool {
|
||||||
|
if cur?.left == nil && cur?.right == nil && count == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if cur?.left == nil && cur?.right == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if let leftNode = cur?.left {
|
||||||
|
if traversal(leftNode, count - leftNode.val) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let rightNode = cur?.right {
|
||||||
|
if traversal(rightNode, count - rightNode.val) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**迭代**
|
||||||
|
```swift
|
||||||
|
func hasPathSum(_ root: TreeNode?, _ targetSum: Int) -> Bool {
|
||||||
|
guard let root = root else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var stack = Array<(TreeNode, Int)>()
|
||||||
|
stack.append((root, root.val))
|
||||||
|
|
||||||
|
while !stack.isEmpty {
|
||||||
|
let node = stack.removeLast()
|
||||||
|
|
||||||
|
if node.0.left == nil && node.0.right == nil && targetSum == node.1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if let rightNode = node.0.right {
|
||||||
|
stack.append((rightNode, node.1 + rightNode.val))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let leftNode = node.0.left {
|
||||||
|
stack.append((leftNode, node.1 + leftNode.val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
0113.路径总和 II
|
||||||
|
|
||||||
|
**递归**
|
||||||
|
|
||||||
|
```swift
|
||||||
|
var result = [[Int]]()
|
||||||
|
var path = [Int]()
|
||||||
|
func pathSum(_ root: TreeNode?, _ targetSum: Int) -> [[Int]] {
|
||||||
|
result.removeAll()
|
||||||
|
path.removeAll()
|
||||||
|
guard let root = root else {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
path.append(root.val)
|
||||||
|
traversal(root, count: targetSum - root.val)
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func traversal(_ cur: TreeNode?, count: Int) {
|
||||||
|
var count = count
|
||||||
|
// 遇到了叶子节点且找到了和为targetSum的路径
|
||||||
|
if cur?.left == nil && cur?.right == nil && count == 0 {
|
||||||
|
result.append(path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遇到叶子节点而没有找到合适的边,直接返回
|
||||||
|
if cur?.left == nil && cur?.right == nil{
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let leftNode = cur?.left {
|
||||||
|
path.append(leftNode.val)
|
||||||
|
count -= leftNode.val
|
||||||
|
traversal(leftNode, count: count)// 递归
|
||||||
|
count += leftNode.val// 回溯
|
||||||
|
path.removeLast()// 回溯
|
||||||
|
}
|
||||||
|
|
||||||
|
if let rightNode = cur?.right {
|
||||||
|
path.append(rightNode.val)
|
||||||
|
count -= rightNode.val
|
||||||
|
traversal(rightNode, count: count)// 递归
|
||||||
|
count += rightNode.val// 回溯
|
||||||
|
path.removeLast()// 回溯
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,9 +211,52 @@ class Solution:
|
||||||
return root
|
return root
|
||||||
```
|
```
|
||||||
## Go
|
## Go
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
// 迭代法
|
||||||
|
func connect(root *Node) *Node {
|
||||||
|
if root == nil {
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
stack := make([]*Node, 0)
|
||||||
|
stack = append(stack, root)
|
||||||
|
for len(stack) > 0 {
|
||||||
|
n := len(stack) // 记录当前层节点个数
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
node := stack[0] // 依次弹出节点
|
||||||
|
stack = stack[1:]
|
||||||
|
if i == n - 1 { // 如果是这层最右的节点,next指向nil
|
||||||
|
node.Next = nil
|
||||||
|
} else {
|
||||||
|
node.Next = stack[0] // 如果不是最右的节点,next指向右边的节点
|
||||||
|
}
|
||||||
|
if node.Left != nil { // 如果存在左子节点,放入栈中
|
||||||
|
stack = append(stack, node.Left)
|
||||||
|
}
|
||||||
|
if node.Right != nil { // 如果存在右子节点,放入栈中
|
||||||
|
stack = append(stack, node.Right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```go
|
||||||
|
// 常量级额外空间,使用next
|
||||||
|
func connect(root *Node) *Node {
|
||||||
|
if root == nil {
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
for cur := root; cur.Left != nil; cur = cur.Left { // 遍历每层最左边的节点
|
||||||
|
for node := cur; node != nil; node = node.Next { // 当前层从左到右遍历
|
||||||
|
node.Left.Next = node.Right // 左子节点next指向右子节点
|
||||||
|
if node.Next != nil { //如果node next有值,右子节点指向next节点的左子节点
|
||||||
|
node.Right.Next = node.Next.Left
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,36 @@ class Solution:
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
> 贪心法:
|
||||||
|
```Go
|
||||||
|
func maxProfit(prices []int) int {
|
||||||
|
low := math.MaxInt32
|
||||||
|
rlt := 0
|
||||||
|
for i := range prices{
|
||||||
|
low = min(low, prices[i])
|
||||||
|
rlt = max(rlt, prices[i]-low)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rlt
|
||||||
|
}
|
||||||
|
func min(a, b int) int {
|
||||||
|
if a < b{
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(a, b int) int {
|
||||||
|
if a > b{
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 动态规划:版本一
|
||||||
```Go
|
```Go
|
||||||
func maxProfit(prices []int) int {
|
func maxProfit(prices []int) int {
|
||||||
length:=len(prices)
|
length:=len(prices)
|
||||||
|
|
@ -338,6 +367,29 @@ func max(a,b int)int {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 动态规划:版本二
|
||||||
|
```Go
|
||||||
|
func maxProfit(prices []int) int {
|
||||||
|
dp := [2][2]int{}
|
||||||
|
dp[0][0] = -prices[0]
|
||||||
|
dp[0][1] = 0
|
||||||
|
for i := 1; i < len(prices); i++{
|
||||||
|
dp[i%2][0] = max(dp[(i-1)%2][0], -prices[i])
|
||||||
|
dp[i%2][1] = max(dp[(i-1)%2][1], dp[(i-1)%2][0]+prices[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[(len(prices)-1)%2][1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(a, b int) int {
|
||||||
|
if a > b{
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
|
||||||
> 动态规划
|
> 动态规划
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
本题首先要清楚两点:
|
本题首先要清楚两点:
|
||||||
|
|
||||||
* 只有一只股票!
|
* 只有一只股票!
|
||||||
* 当前只有买股票或者买股票的操作
|
* 当前只有买股票或者卖股票的操作
|
||||||
|
|
||||||
想获得利润至少要两天为一个交易单元。
|
想获得利润至少要两天为一个交易单元。
|
||||||
|
|
||||||
|
|
@ -264,12 +264,24 @@ const maxProfit = (prices) => {
|
||||||
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i]);
|
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dp[prices.length -1][0];
|
return dp[prices.length -1][1];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function maxProfit(prices: number[]): number {
|
||||||
|
let resProfit: number = 0;
|
||||||
|
for (let i = 1, length = prices.length; i < length; i++) {
|
||||||
|
resProfit += Math.max(prices[i] - prices[i - 1], 0);
|
||||||
|
}
|
||||||
|
return resProfit;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
C:
|
C:
|
||||||
|
贪心:
|
||||||
```c
|
```c
|
||||||
int maxProfit(int* prices, int pricesSize){
|
int maxProfit(int* prices, int pricesSize){
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
@ -284,5 +296,27 @@ int maxProfit(int* prices, int pricesSize){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
动态规划:
|
||||||
|
```c
|
||||||
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
int maxProfit(int* prices, int pricesSize){
|
||||||
|
int dp[pricesSize][2];
|
||||||
|
dp[0][0] = 0 - prices[0];
|
||||||
|
dp[0][1] = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 1; i < pricesSize; ++i) {
|
||||||
|
// dp[i][0]为i-1天持股的钱数/在第i天用i-1天的钱买入的最大值。
|
||||||
|
// 若i-1天持股,且第i天买入股票比i-1天持股时更亏,说明应在i-1天时持股
|
||||||
|
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]);
|
||||||
|
//dp[i][1]为i-1天不持股钱数/在第i天卖出所持股票dp[i-1][0] + prices[i]的最大值
|
||||||
|
dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]);
|
||||||
|
}
|
||||||
|
// 返回在最后一天不持股时的钱数(将股票卖出后钱最大化)
|
||||||
|
return dp[pricesSize - 1][1];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
大家可以本题和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的代码几乎一样,唯一的区别在:
|
大家可以本题和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的代码几乎一样,唯一的区别在:
|
||||||
|
|
||||||
|
|
@ -121,8 +121,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -276,7 +276,7 @@ const maxProfit = (prices) => {
|
||||||
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i]);
|
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dp[prices.length -1][0];
|
return dp[prices.length -1][1];
|
||||||
};
|
};
|
||||||
|
|
||||||
// 方法二:动态规划(滚动数组)
|
// 方法二:动态规划(滚动数组)
|
||||||
|
|
|
||||||
|
|
@ -148,8 +148,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(n × 5)$
|
* 空间复杂度:O(n × 5)
|
||||||
|
|
||||||
当然,大家可以看到力扣官方题解里的一种优化空间写法,我这里给出对应的C++版本:
|
当然,大家可以看到力扣官方题解里的一种优化空间写法,我这里给出对应的C++版本:
|
||||||
|
|
||||||
|
|
@ -173,8 +173,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
大家会发现dp[2]利用的是当天的dp[1]。 但结果也是对的。
|
大家会发现dp[2]利用的是当天的dp[1]。 但结果也是对的。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/word-ladder/)
|
[力扣题目链接](https://leetcode-cn.com/problems/word-ladder/)
|
||||||
|
|
||||||
|
|
||||||
字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:
|
字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:
|
||||||
* 序列中第一个单词是 beginWord 。
|
* 序列中第一个单词是 beginWord 。
|
||||||
* 序列中最后一个单词是 endWord 。
|
* 序列中最后一个单词是 endWord 。
|
||||||
|
|
@ -135,7 +134,29 @@ public int ladderLength(String beginWord, String endWord, List<String> wordList)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Python
|
## Python
|
||||||
|
```
|
||||||
|
class Solution:
|
||||||
|
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
|
||||||
|
wordSet = set(wordList)
|
||||||
|
if len(wordSet)== 0 or endWord not in wordSet:
|
||||||
|
return 0
|
||||||
|
mapping = {beginWord:1}
|
||||||
|
queue = deque([beginWord])
|
||||||
|
while queue:
|
||||||
|
word = queue.popleft()
|
||||||
|
path = mapping[word]
|
||||||
|
for i in range(len(word)):
|
||||||
|
word_list = list(word)
|
||||||
|
for j in range(26):
|
||||||
|
word_list[i] = chr(ord('a')+j)
|
||||||
|
newWord = "".join(word_list)
|
||||||
|
if newWord == endWord:
|
||||||
|
return path+1
|
||||||
|
if newWord in wordSet and newWord not in mapping:
|
||||||
|
mapping[newWord] = path+1
|
||||||
|
queue.append(newWord)
|
||||||
|
return 0
|
||||||
|
```
|
||||||
## Go
|
## Go
|
||||||
|
|
||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ class Solution {
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def sumNumbers(self, root: TreeNode) -> int:
|
def sumNumbers(self, root: TreeNode) -> int:
|
||||||
res = 0
|
res = 0
|
||||||
|
|
@ -289,7 +289,33 @@ var sumNumbers = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C:
|
||||||
|
```c
|
||||||
|
//sum记录总和
|
||||||
|
int sum;
|
||||||
|
void traverse(struct TreeNode *node, int val) {
|
||||||
|
//更新val为根节点到当前节点的和
|
||||||
|
val = val * 10 + node->val;
|
||||||
|
//若当前节点为叶子节点,记录val
|
||||||
|
if(!node->left && !node->right) {
|
||||||
|
sum+=val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//若有左/右节点,遍历左/右节点
|
||||||
|
if(node->left)
|
||||||
|
traverse(node->left, val);
|
||||||
|
if(node->right)
|
||||||
|
traverse(node->right, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sumNumbers(struct TreeNode* root){
|
||||||
|
sum = 0;
|
||||||
|
|
||||||
|
traverse(root, 0);
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ class Solution {
|
||||||
|
|
||||||
## Python
|
## Python
|
||||||
**回溯+正反序判断回文串**
|
**回溯+正反序判断回文串**
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.paths = []
|
self.paths = []
|
||||||
|
|
@ -326,7 +326,7 @@ class Solution:
|
||||||
continue
|
continue
|
||||||
```
|
```
|
||||||
**回溯+函数判断回文串**
|
**回溯+函数判断回文串**
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.paths = []
|
self.paths = []
|
||||||
|
|
@ -450,6 +450,43 @@ var partition = function(s) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function partition(s: string): string[][] {
|
||||||
|
const res: string[][] = []
|
||||||
|
const path: string[] = []
|
||||||
|
const isHuiwen = (
|
||||||
|
str: string,
|
||||||
|
startIndex: number,
|
||||||
|
endIndex: number
|
||||||
|
): boolean => {
|
||||||
|
for (; startIndex < endIndex; startIndex++, endIndex--) {
|
||||||
|
if (str[startIndex] !== str[endIndex]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const rec = (str: string, index: number): void => {
|
||||||
|
if (index >= str.length) {
|
||||||
|
res.push([...path])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (let i = index; i < str.length; i++) {
|
||||||
|
if (!isHuiwen(str, index, i)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
path.push(str.substring(index, i + 1))
|
||||||
|
rec(str, i + 1)
|
||||||
|
path.pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rec(s, 0)
|
||||||
|
return res
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ public:
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n^2)$
|
* 时间复杂度:$O(n^2)$
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:$O(1)$
|
||||||
|
|
||||||
C++暴力解法在leetcode上提交也可以过。
|
C++暴力解法在leetcode上提交也可以过。
|
||||||
|
|
||||||
|
|
@ -235,10 +235,34 @@ class Solution {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
```python
|
```python
|
||||||
|
# 解法1
|
||||||
|
class Solution:
|
||||||
|
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
|
||||||
|
n = len(gas)
|
||||||
|
cur_sum = 0
|
||||||
|
min_sum = float('inf')
|
||||||
|
|
||||||
|
for i in range(n):
|
||||||
|
cur_sum += gas[i] - cost[i]
|
||||||
|
min_sum = min(min_sum, cur_sum)
|
||||||
|
|
||||||
|
if cur_sum < 0: return -1
|
||||||
|
if min_sum >= 0: return 0
|
||||||
|
|
||||||
|
for j in range(n - 1, 0, -1):
|
||||||
|
min_sum += gas[j] - cost[j]
|
||||||
|
if min_sum >= 0:
|
||||||
|
return j
|
||||||
|
|
||||||
|
return -1
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 解法2
|
||||||
class Solution:
|
class Solution:
|
||||||
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
|
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
|
||||||
start = 0
|
start = 0
|
||||||
|
|
@ -340,7 +364,53 @@ var canCompleteCircuit = function(gas, cost) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
**暴力法:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function canCompleteCircuit(gas: number[], cost: number[]): number {
|
||||||
|
for (let i = 0, length = gas.length; i < length; i++) {
|
||||||
|
let curSum: number = 0;
|
||||||
|
let index: number = i;
|
||||||
|
while (curSum >= 0 && index < i + length) {
|
||||||
|
let tempIndex: number = index % length;
|
||||||
|
curSum += gas[tempIndex] - cost[tempIndex];
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (index === i + length && curSum >= 0) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**解法二:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function canCompleteCircuit(gas: number[], cost: number[]): number {
|
||||||
|
let total: number = 0;
|
||||||
|
let curGas: number = 0;
|
||||||
|
let tempDiff: number = 0;
|
||||||
|
let resIndex: number = 0;
|
||||||
|
for (let i = 0, length = gas.length; i < length; i++) {
|
||||||
|
tempDiff = gas[i] - cost[i];
|
||||||
|
total += tempDiff;
|
||||||
|
curGas += tempDiff;
|
||||||
|
if (curGas < 0) {
|
||||||
|
resIndex = i + 1;
|
||||||
|
curGas = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (total < 0) return -1;
|
||||||
|
return resIndex;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### C
|
### C
|
||||||
|
|
||||||
|
贪心算法:方法一
|
||||||
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize){
|
int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize){
|
||||||
int curSum = 0;
|
int curSum = 0;
|
||||||
|
|
@ -370,5 +440,36 @@ int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
贪心算法:方法二
|
||||||
|
```c
|
||||||
|
int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize){
|
||||||
|
int curSum = 0;
|
||||||
|
int totalSum = 0;
|
||||||
|
int start = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < gasSize; ++i) {
|
||||||
|
// 当前i站中加油量与耗油量的差
|
||||||
|
int diff = gas[i] - cost[i];
|
||||||
|
|
||||||
|
curSum += diff;
|
||||||
|
totalSum += diff;
|
||||||
|
|
||||||
|
// 若0到i的加油量都为负,则开始位置应为i+1
|
||||||
|
if(curSum < 0) {
|
||||||
|
curSum = 0;
|
||||||
|
// 当i + 1 == gasSize时,totalSum < 0(此时i为gasSize - 1),油车不可能返回原点
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 若总和小于0,加油车无论如何都无法返回原点。返回-1
|
||||||
|
if(totalSum < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -239,5 +239,73 @@ var candy = function(ratings) {
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### C
|
||||||
|
```c
|
||||||
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
int *initCandyArr(int size) {
|
||||||
|
int *candyArr = (int*)malloc(sizeof(int) * size);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < size; ++i)
|
||||||
|
candyArr[i] = 1;
|
||||||
|
|
||||||
|
return candyArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int candy(int* ratings, int ratingsSize){
|
||||||
|
// 初始化数组,每个小孩开始至少有一颗糖
|
||||||
|
int *candyArr = initCandyArr(ratingsSize);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
// 先判断右边是否比左边评分高。若是,右边孩子的糖果为左边孩子+1(candyArr[i] = candyArr[i - 1] + 1)
|
||||||
|
for(i = 1; i < ratingsSize; ++i) {
|
||||||
|
if(ratings[i] > ratings[i - 1])
|
||||||
|
candyArr[i] = candyArr[i - 1] + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再判断左边评分是否比右边高。
|
||||||
|
// 若是,左边孩子糖果为右边孩子糖果+1/自己所持糖果最大值。(若糖果已经比右孩子+1多,则不需要更多糖果)
|
||||||
|
// 举例:ratings为[1, 2, 3, 1]。此时评分为3的孩子在判断右边比左边大后为3,虽然它比最末尾的1(ratings[3])大,但是candyArr[3]为1。所以不必更新candyArr[2]
|
||||||
|
for(i = ratingsSize - 2; i >= 0; --i) {
|
||||||
|
if(ratings[i] > ratings[i + 1])
|
||||||
|
candyArr[i] = max(candyArr[i], candyArr[i + 1] + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 求出糖果之和
|
||||||
|
int result = 0;
|
||||||
|
for(i = 0; i < ratingsSize; ++i) {
|
||||||
|
result += candyArr[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function candy(ratings: number[]): number {
|
||||||
|
const candies: number[] = [];
|
||||||
|
candies[0] = 1;
|
||||||
|
// 保证右边高分孩子一定比左边低分孩子发更多的糖果
|
||||||
|
for (let i = 1, length = ratings.length; i < length; i++) {
|
||||||
|
if (ratings[i] > ratings[i - 1]) {
|
||||||
|
candies[i] = candies[i - 1] + 1;
|
||||||
|
} else {
|
||||||
|
candies[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 保证左边高分孩子一定比右边低分孩子发更多的糖果
|
||||||
|
for (let i = ratings.length - 2; i >= 0; i--) {
|
||||||
|
if (ratings[i] > ratings[i + 1]) {
|
||||||
|
candies[i] = Math.max(candies[i], candies[i + 1] + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candies.reduce((pre, cur) => pre + cur);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(2^n)$,因为每一个单词都有两个状态,切割和不切割
|
* 时间复杂度:O(2^n),因为每一个单词都有两个状态,切割和不切割
|
||||||
* 空间复杂度:$O(n)$,算法递归系统调用栈的空间
|
* 空间复杂度:O(n),算法递归系统调用栈的空间
|
||||||
|
|
||||||
那么以上代码很明显要超时了,超时的数据如下:
|
那么以上代码很明显要超时了,超时的数据如下:
|
||||||
|
|
||||||
|
|
@ -89,33 +89,32 @@ class Solution {
|
||||||
private:
|
private:
|
||||||
bool backtracking (const string& s,
|
bool backtracking (const string& s,
|
||||||
const unordered_set<string>& wordSet,
|
const unordered_set<string>& wordSet,
|
||||||
vector<int>& memory,
|
vector<bool>& memory,
|
||||||
int startIndex) {
|
int startIndex) {
|
||||||
if (startIndex >= s.size()) {
|
if (startIndex >= s.size()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// 如果memory[startIndex]不是初始值了,直接使用memory[startIndex]的结果
|
// 如果memory[startIndex]不是初始值了,直接使用memory[startIndex]的结果
|
||||||
if (memory[startIndex] != -1) return memory[startIndex];
|
if (!memory[startIndex]) return memory[startIndex];
|
||||||
for (int i = startIndex; i < s.size(); i++) {
|
for (int i = startIndex; i < s.size(); i++) {
|
||||||
string word = s.substr(startIndex, i - startIndex + 1);
|
string word = s.substr(startIndex, i - startIndex + 1);
|
||||||
if (wordSet.find(word) != wordSet.end() && backtracking(s, wordSet, memory, i + 1)) {
|
if (wordSet.find(word) != wordSet.end() && backtracking(s, wordSet, memory, i + 1)) {
|
||||||
memory[startIndex] = 1; // 记录以startIndex开始的子串是可以被拆分的
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memory[startIndex] = 0; // 记录以startIndex开始的子串是不可以被拆分的
|
memory[startIndex] = false; // 记录以startIndex开始的子串是不可以被拆分的
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
bool wordBreak(string s, vector<string>& wordDict) {
|
bool wordBreak(string s, vector<string>& wordDict) {
|
||||||
unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
|
unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
|
||||||
vector<int> memory(s.size(), -1); // -1 表示初始化状态
|
vector<bool> memory(s.size(), 1); // -1 表示初始化状态
|
||||||
return backtracking(s, wordSet, memory, 0);
|
return backtracking(s, wordSet, memory, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
这个时间复杂度其实也是:$O(2^n)$。只不过对于上面那个超时测试用例优化效果特别明显。
|
这个时间复杂度其实也是:O(2^n)。只不过对于上面那个超时测试用例优化效果特别明显。
|
||||||
|
|
||||||
**这个代码就可以AC了,当然回溯算法不是本题的主菜,背包才是!**
|
**这个代码就可以AC了,当然回溯算法不是本题的主菜,背包才是!**
|
||||||
|
|
||||||
|
|
@ -208,8 +207,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n^3)$,因为substr返回子串的副本是$O(n)$的复杂度(这里的n是substring的长度)
|
* 时间复杂度:O(n^3),因为substr返回子串的副本是O(n)的复杂度(这里的n是substring的长度)
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
@ -248,6 +247,40 @@ class Solution {
|
||||||
return valid[s.length()];
|
return valid[s.length()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 回溯法+记忆化
|
||||||
|
class Solution {
|
||||||
|
private Set<String> set;
|
||||||
|
private int[] memo;
|
||||||
|
public boolean wordBreak(String s, List<String> wordDict) {
|
||||||
|
memo = new int[s.length()];
|
||||||
|
set = new HashSet<>(wordDict);
|
||||||
|
return backtracking(s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean backtracking(String s, int startIndex) {
|
||||||
|
// System.out.println(startIndex);
|
||||||
|
if (startIndex == s.length()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (memo[startIndex] == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = startIndex; i < s.length(); i++) {
|
||||||
|
String sub = s.substring(startIndex, i + 1);
|
||||||
|
// 拆分出来的单词无法匹配
|
||||||
|
if (!set.contains(sub)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean res = backtracking(s, i + 1);
|
||||||
|
if (res) return true;
|
||||||
|
}
|
||||||
|
// 这里是关键,找遍了startIndex~s.length()也没能完全匹配,标记从startIndex开始不能找到
|
||||||
|
memo[startIndex] = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,21 @@ class Solution:
|
||||||
## Go
|
## Go
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
func hasCycle(head *ListNode) bool {
|
||||||
|
if head==nil{
|
||||||
|
return false
|
||||||
|
} //空链表一定不会有环
|
||||||
|
fast:=head
|
||||||
|
slow:=head //快慢指针
|
||||||
|
for fast.Next!=nil&&fast.Next.Next!=nil{
|
||||||
|
fast=fast.Next.Next
|
||||||
|
slow=slow.Next
|
||||||
|
if fast==slow{
|
||||||
|
return true //快慢指针相遇则有环
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### JavaScript
|
### JavaScript
|
||||||
|
|
|
||||||
|
|
@ -336,7 +336,33 @@ class Solution:
|
||||||
return pre
|
return pre
|
||||||
```
|
```
|
||||||
### Go
|
### Go
|
||||||
|
```go
|
||||||
|
# 方法三 分割链表
|
||||||
|
func reorderList(head *ListNode) {
|
||||||
|
var slow=head
|
||||||
|
var fast=head
|
||||||
|
for fast!=nil&&fast.Next!=nil{
|
||||||
|
slow=slow.Next
|
||||||
|
fast=fast.Next.Next
|
||||||
|
} //双指针将链表分为左右两部分
|
||||||
|
var right =new(ListNode)
|
||||||
|
for slow!=nil{
|
||||||
|
temp:=slow.Next
|
||||||
|
slow.Next=right.Next
|
||||||
|
right.Next=slow
|
||||||
|
slow=temp
|
||||||
|
} //翻转链表右半部分
|
||||||
|
right=right.Next //right为反转后得右半部分
|
||||||
|
h:=head
|
||||||
|
for right.Next!=nil{
|
||||||
|
temp:=right.Next
|
||||||
|
right.Next=h.Next
|
||||||
|
h.Next=right
|
||||||
|
h=h.Next.Next
|
||||||
|
right=temp
|
||||||
|
} //将左右两部分重新组合
|
||||||
|
}
|
||||||
|
```
|
||||||
### JavaScript
|
### JavaScript
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
|
@ -439,7 +465,75 @@ var reorderList = function(head, s = [], tmp) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### C
|
||||||
|
方法三:反转链表
|
||||||
|
```c
|
||||||
|
//翻转链表
|
||||||
|
struct ListNode *reverseList(struct ListNode *head) {
|
||||||
|
if(!head)
|
||||||
|
return NULL;
|
||||||
|
struct ListNode *preNode = NULL, *curNode = head;
|
||||||
|
while(curNode) {
|
||||||
|
//创建tempNode记录curNode->next(即将被更新)
|
||||||
|
struct ListNode* tempNode = curNode->next;
|
||||||
|
//将curNode->next指向preNode
|
||||||
|
curNode->next = preNode;
|
||||||
|
//更新preNode为curNode
|
||||||
|
preNode = curNode;
|
||||||
|
//curNode更新为原链表中下一个元素
|
||||||
|
curNode = tempNode;
|
||||||
|
}
|
||||||
|
return preNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reorderList(struct ListNode* head){
|
||||||
|
//slow用来截取到链表的中间节点(第一个链表的最后节点),每次循环跳一个节点。fast用来辅助,每次循环跳两个节点
|
||||||
|
struct ListNode *fast = head, *slow = head;
|
||||||
|
while(fast && fast->next && fast->next->next) {
|
||||||
|
//fast每次跳两个节点
|
||||||
|
fast = fast->next->next;
|
||||||
|
//slow每次跳一个节点
|
||||||
|
slow = slow->next;
|
||||||
|
}
|
||||||
|
//将slow->next后的节点翻转
|
||||||
|
struct ListNode *sndLst = reverseList(slow->next);
|
||||||
|
//将第一个链表与第二个链表断开
|
||||||
|
slow->next = NULL;
|
||||||
|
//因为插入从curNode->next开始,curNode刚开始已经head。所以fstList要从head->next开始
|
||||||
|
struct ListNode *fstLst = head->next;
|
||||||
|
struct ListNode *curNode = head;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
//当第一个链表和第二个链表中都有节点时循环
|
||||||
|
while(sndLst && fstLst) {
|
||||||
|
//count为奇数,插入fstLst中的节点
|
||||||
|
if(count % 2) {
|
||||||
|
curNode->next = fstLst;
|
||||||
|
fstLst = fstLst->next;
|
||||||
|
}
|
||||||
|
//count为偶数,插入sndList的节点
|
||||||
|
else {
|
||||||
|
curNode->next = sndLst;
|
||||||
|
sndLst = sndLst->next;
|
||||||
|
}
|
||||||
|
//设置下一个节点
|
||||||
|
curNode = curNode->next;
|
||||||
|
//更新count
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//若两个链表fstList和sndLst中还有节点,将其放入链表
|
||||||
|
if(fstLst) {
|
||||||
|
curNode->next = fstLst;
|
||||||
|
}
|
||||||
|
if(sndLst) {
|
||||||
|
curNode->next = sndLst;
|
||||||
|
}
|
||||||
|
|
||||||
|
//返回链表
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
# 题外话
|
## 题外话
|
||||||
|
|
||||||
我们习惯看到的表达式都是中缀表达式,因为符合我们的习惯,但是中缀表达式对于计算机来说就不是很友好了。
|
我们习惯看到的表达式都是中缀表达式,因为符合我们的习惯,但是中缀表达式对于计算机来说就不是很友好了。
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
java:
|
java:
|
||||||
|
|
||||||
|
|
@ -210,6 +210,71 @@ var evalRPN = function(tokens) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
普通版:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function evalRPN(tokens: string[]): number {
|
||||||
|
let helperStack: number[] = [];
|
||||||
|
let temp: number;
|
||||||
|
let i: number = 0;
|
||||||
|
while (i < tokens.length) {
|
||||||
|
let t: string = tokens[i];
|
||||||
|
switch (t) {
|
||||||
|
case '+':
|
||||||
|
temp = helperStack.pop()! + helperStack.pop()!;
|
||||||
|
helperStack.push(temp);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
temp = helperStack.pop()!;
|
||||||
|
temp = helperStack.pop()! - temp;
|
||||||
|
helperStack.push(temp);
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
temp = helperStack.pop()! * helperStack.pop()!;
|
||||||
|
helperStack.push(temp);
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
temp = helperStack.pop()!;
|
||||||
|
temp = Math.trunc(helperStack.pop()! / temp);
|
||||||
|
helperStack.push(temp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
helperStack.push(Number(t));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return helperStack.pop()!;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
优化版:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function evalRPN(tokens: string[]): number {
|
||||||
|
const helperStack: number[] = [];
|
||||||
|
const operatorMap: Map<string, (a: number, b: number) => number> = new Map([
|
||||||
|
['+', (a, b) => a + b],
|
||||||
|
['-', (a, b) => a - b],
|
||||||
|
['/', (a, b) => Math.trunc(a / b)],
|
||||||
|
['*', (a, b) => a * b],
|
||||||
|
]);
|
||||||
|
let a: number, b: number;
|
||||||
|
for (let t of tokens) {
|
||||||
|
if (operatorMap.has(t)) {
|
||||||
|
b = helperStack.pop()!;
|
||||||
|
a = helperStack.pop()!;
|
||||||
|
helperStack.push(operatorMap.get(t)!(a, b));
|
||||||
|
} else {
|
||||||
|
helperStack.push(Number(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return helperStack.pop()!;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
python3
|
python3
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
一些同学会使用split库函数,分隔单词,然后定义一个新的string字符串,最后再把单词倒序相加,那么这道题题目就是一道水题了,失去了它的意义。
|
一些同学会使用split库函数,分隔单词,然后定义一个新的string字符串,最后再把单词倒序相加,那么这道题题目就是一道水题了,失去了它的意义。
|
||||||
|
|
||||||
所以这里我还是提高一下本题的难度:**不要使用辅助空间,空间复杂度要求为$O(1)$。**
|
所以这里我还是提高一下本题的难度:**不要使用辅助空间,空间复杂度要求为O(1)。**
|
||||||
|
|
||||||
不能使用辅助空间之后,那么只能在原字符串上下功夫了。
|
不能使用辅助空间之后,那么只能在原字符串上下功夫了。
|
||||||
|
|
||||||
|
|
@ -79,13 +79,13 @@ void removeExtraSpaces(string& s) {
|
||||||
|
|
||||||
逻辑很简单,从前向后遍历,遇到空格了就erase。
|
逻辑很简单,从前向后遍历,遇到空格了就erase。
|
||||||
|
|
||||||
如果不仔细琢磨一下erase的时间复杂读,还以为以上的代码是$O(n)$的时间复杂度呢。
|
如果不仔细琢磨一下erase的时间复杂读,还以为以上的代码是O(n)的时间复杂度呢。
|
||||||
|
|
||||||
想一下真正的时间复杂度是多少,一个erase本来就是$O(n)$的操作,erase实现原理题目:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html),最优的算法来移除元素也要$O(n)$。
|
想一下真正的时间复杂度是多少,一个erase本来就是O(n)的操作,erase实现原理题目:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html),最优的算法来移除元素也要O(n)。
|
||||||
|
|
||||||
erase操作上面还套了一个for循环,那么以上代码移除冗余空格的代码时间复杂度为$O(n^2)$。
|
erase操作上面还套了一个for循环,那么以上代码移除冗余空格的代码时间复杂度为O(n^2)。
|
||||||
|
|
||||||
那么使用双指针法来去移除空格,最后resize(重新设置)一下字符串的大小,就可以做到$O(n)$的时间复杂度。
|
那么使用双指针法来去移除空格,最后resize(重新设置)一下字符串的大小,就可以做到O(n)的时间复杂度。
|
||||||
|
|
||||||
如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)是如何移除元素的。
|
如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)是如何移除元素的。
|
||||||
|
|
||||||
|
|
@ -222,7 +222,44 @@ public:
|
||||||
效率:
|
效率:
|
||||||
<img src='https://code-thinking.cdn.bcebos.com/pics/151_翻转字符串里的单词.png' width=600> </img></div>
|
<img src='https://code-thinking.cdn.bcebos.com/pics/151_翻转字符串里的单词.png' width=600> </img></div>
|
||||||
|
|
||||||
|
```CPP
|
||||||
|
//版本二:
|
||||||
|
//原理同版本1,更简洁实现。
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
void reverse(string& s, int start, int end){ //翻转,区间写法:闭区间 []
|
||||||
|
for (int i = start, j = end; i < j; i++, j--) {
|
||||||
|
swap(s[i], s[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
|
||||||
|
int slow = 0; //整体思想参考Leetcode: 27. 移除元素:https://leetcode-cn.com/problems/remove-element/
|
||||||
|
for (int i = 0; i < s.size(); ++i) { //
|
||||||
|
if (s[i] != ' ') { //遇到非空格就处理,即删除所有空格。
|
||||||
|
if (slow != 0) s[slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
|
||||||
|
while (i < s.size() && s[i] != ' ') { //补上该单词,遇到空格说明单词结束。
|
||||||
|
s[slow++] = s[i++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.resize(slow); //slow的大小即为去除多余空格后的大小。
|
||||||
|
}
|
||||||
|
|
||||||
|
string reverseWords(string s) {
|
||||||
|
removeExtraSpaces(s); //去除多余空格,保证单词之间之只有一个空格,且字符串首尾没空格。
|
||||||
|
reverse(s, 0, s.size() - 1);
|
||||||
|
int start = 0; //removeExtraSpaces后保证第一个单词的开始下标一定是0。
|
||||||
|
for (int i = 0; i <= s.size(); ++i) {
|
||||||
|
if (i == s.size() || s[i] == ' ') { //到达空格或者串尾,说明一个单词结束。进行翻转。
|
||||||
|
reverse(s, start, i - 1); //翻转,注意是左闭右闭 []的翻转。
|
||||||
|
start = i + 1; //更新下一个单词的开始下标start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
@ -438,6 +475,38 @@ class Solution:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def reverseWords(self, s: str) -> str:
|
||||||
|
# method 1 - Rude but work & efficient method.
|
||||||
|
s_list = [i for i in s.split(" ") if len(i) > 0]
|
||||||
|
return " ".join(s_list[::-1])
|
||||||
|
|
||||||
|
# method 2 - Carlo's idea
|
||||||
|
def trim_head_tail_space(ss: str):
|
||||||
|
p = 0
|
||||||
|
while p < len(ss) and ss[p] == " ":
|
||||||
|
p += 1
|
||||||
|
return ss[p:]
|
||||||
|
|
||||||
|
# Trim the head and tail space
|
||||||
|
s = trim_head_tail_space(s)
|
||||||
|
s = trim_head_tail_space(s[::-1])[::-1]
|
||||||
|
|
||||||
|
pf, ps, s = 0, 0, s[::-1] # Reverse the string.
|
||||||
|
while pf < len(s):
|
||||||
|
if s[pf] == " ":
|
||||||
|
# Will not excede. Because we have clean the tail space.
|
||||||
|
if s[pf] == s[pf + 1]:
|
||||||
|
s = s[:pf] + s[pf + 1:]
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
s = s[:ps] + s[ps: pf][::-1] + s[pf:]
|
||||||
|
ps, pf = pf + 1, pf + 2
|
||||||
|
else:
|
||||||
|
pf += 1
|
||||||
|
return s[:ps] + s[ps:][::-1] # Must do the last step, because the last word is omit though the pointers are on the correct positions,
|
||||||
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
|
@ -553,6 +622,65 @@ function reverse(strArr, start, end) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function reverseWords(s: string): string {
|
||||||
|
/** Utils **/
|
||||||
|
// 删除多余空格, 如' hello world ' => 'hello world'
|
||||||
|
function delExtraSpace(arr: string[]): void {
|
||||||
|
let left: number = 0,
|
||||||
|
right: number = 0,
|
||||||
|
length: number = arr.length;
|
||||||
|
while (right < length && arr[right] === ' ') {
|
||||||
|
right++;
|
||||||
|
}
|
||||||
|
while (right < length) {
|
||||||
|
if (arr[right] === ' ' && arr[right - 1] === ' ') {
|
||||||
|
right++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
arr[left++] = arr[right++];
|
||||||
|
}
|
||||||
|
if (arr[left - 1] === ' ') {
|
||||||
|
arr.length = left - 1;
|
||||||
|
} else {
|
||||||
|
arr.length = left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 翻转字符串,如:'hello' => 'olleh'
|
||||||
|
function reverseWords(strArr: string[], start: number, end: number) {
|
||||||
|
let temp: string;
|
||||||
|
while (start < end) {
|
||||||
|
temp = strArr[start];
|
||||||
|
strArr[start] = strArr[end];
|
||||||
|
strArr[end] = temp;
|
||||||
|
start++;
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Main code **/
|
||||||
|
let strArr: string[] = s.split('');
|
||||||
|
delExtraSpace(strArr);
|
||||||
|
let length: number = strArr.length;
|
||||||
|
// 翻转整个字符串
|
||||||
|
reverseWords(strArr, 0, length - 1);
|
||||||
|
let start: number = 0,
|
||||||
|
end: number = 0;
|
||||||
|
while (start < length) {
|
||||||
|
end = start;
|
||||||
|
while (strArr[end] !== ' ' && end < length) {
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
// 翻转单个单词
|
||||||
|
reverseWords(strArr, start, end - 1);
|
||||||
|
start = end + 1;
|
||||||
|
}
|
||||||
|
return strArr.join('');
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
Swift:
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ class Solution:
|
||||||
return dp[-1][2*k]
|
return dp[-1][2*k]
|
||||||
```
|
```
|
||||||
版本二
|
版本二
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def maxProfit(self, k: int, prices: List[int]) -> int:
|
def maxProfit(self, k: int, prices: List[int]) -> int:
|
||||||
if len(prices) == 0: return 0
|
if len(prices) == 0: return 0
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
进阶:
|
进阶:
|
||||||
|
|
||||||
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
|
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
|
||||||
你可以使用空间复杂度为 $O(1)$ 的 原地 算法解决这个问题吗?
|
你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?
|
||||||
|
|
||||||
示例 1:
|
示例 1:
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
|
|
||||||
本题其实和[字符串:剑指Offer58-II.左旋转字符串](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)就非常像了,剑指offer上左旋转,本题是右旋转。
|
本题其实和[字符串:剑指Offer58-II.左旋转字符串](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)就非常像了,剑指offer上左旋转,本题是右旋转。
|
||||||
|
|
||||||
注意题目要求是**要求使用空间复杂度为 $O(1)$ 的 原地 算法**
|
注意题目要求是**要求使用空间复杂度为 O(1) 的 原地 算法**
|
||||||
|
|
||||||
那么我来提供一种旋转的方式哈。
|
那么我来提供一种旋转的方式哈。
|
||||||
|
|
||||||
|
|
@ -124,6 +124,19 @@ class Solution:
|
||||||
## Go
|
## Go
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
func rotate(nums []int, k int) {
|
||||||
|
l:=len(nums)
|
||||||
|
index:=l-k%l
|
||||||
|
reverse(nums)
|
||||||
|
reverse(nums[:l-index])
|
||||||
|
reverse(nums[l-index:])
|
||||||
|
}
|
||||||
|
func reverse(nums []int){
|
||||||
|
l:=len(nums)
|
||||||
|
for i:=0;i<l/2;i++{
|
||||||
|
nums[i],nums[l-1-i]=nums[l-1-i],nums[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,27 @@ var isHappy = function(n) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function isHappy(n: number): boolean {
|
||||||
|
// Utils
|
||||||
|
// 计算val各位的平方和
|
||||||
|
function calcSum(val: number): number {
|
||||||
|
return String(val).split("").reduce((pre, cur) => (pre + Number(cur) * Number(cur)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let storeSet: Set<number> = new Set();
|
||||||
|
while (n !== 1 && !storeSet.has(n)) {
|
||||||
|
storeSet.add(n);
|
||||||
|
n = calcSum(n);
|
||||||
|
}
|
||||||
|
return n === 1;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
Swift:
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
// number 每个位置上的数字的平方和
|
// number 每个位置上的数字的平方和
|
||||||
func getSum(_ number: Int) -> Int {
|
func getSum(_ number: Int) -> Int {
|
||||||
|
|
@ -295,5 +315,75 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C:
|
||||||
|
```C
|
||||||
|
typedef struct HashNodeTag {
|
||||||
|
int key; /* num */
|
||||||
|
struct HashNodeTag *next;
|
||||||
|
}HashNode;
|
||||||
|
|
||||||
|
/* Calcualte the hash key */
|
||||||
|
static inline int hash(int key, int size) {
|
||||||
|
int index = key % size;
|
||||||
|
return (index > 0) ? (index) : (-index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the sum of the squares of its digits*/
|
||||||
|
static inline int calcSquareSum(int num) {
|
||||||
|
unsigned int sum = 0;
|
||||||
|
while(num > 0) {
|
||||||
|
sum += (num % 10) * (num % 10);
|
||||||
|
num = num/10;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HASH_TABLE_SIZE (32)
|
||||||
|
|
||||||
|
bool isHappy(int n){
|
||||||
|
int sum = n;
|
||||||
|
int index = 0;
|
||||||
|
bool bHappy = false;
|
||||||
|
bool bExit = false;
|
||||||
|
/* allocate the memory for hash table with chaining method*/
|
||||||
|
HashNode ** hashTable = (HashNode **)calloc(HASH_TABLE_SIZE, sizeof(HashNode));
|
||||||
|
|
||||||
|
while(bExit == false) {
|
||||||
|
/* check if n has been calculated */
|
||||||
|
index = hash(n, HASH_TABLE_SIZE);
|
||||||
|
|
||||||
|
HashNode ** p = hashTable + index;
|
||||||
|
|
||||||
|
while((*p) && (bExit == false)) {
|
||||||
|
/* Check if this num was calculated, if yes, this will be endless loop */
|
||||||
|
if((*p)->key == n) {
|
||||||
|
bHappy = false;
|
||||||
|
bExit = true;
|
||||||
|
}
|
||||||
|
/* move to next node of the same index */
|
||||||
|
p = &((*p)->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put n intot hash table */
|
||||||
|
HashNode * newNode = (HashNode *)malloc(sizeof(HashNode));
|
||||||
|
newNode->key = n;
|
||||||
|
newNode->next = NULL;
|
||||||
|
|
||||||
|
*p = newNode;
|
||||||
|
|
||||||
|
sum = calcSquareSum(n);
|
||||||
|
if(sum == 1) {
|
||||||
|
bHappy = true;
|
||||||
|
bExit = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
n = sum;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bHappy;
|
||||||
|
}
|
||||||
|
```
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,38 @@ public:
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
C:
|
C:
|
||||||
|
用原来的链表操作:
|
||||||
|
```c
|
||||||
|
struct ListNode* removeElements(struct ListNode* head, int val){
|
||||||
|
struct ListNode* temp;
|
||||||
|
// 当头结点存在并且头结点的值等于val时
|
||||||
|
while(head && head->val == val) {
|
||||||
|
temp = head;
|
||||||
|
// 将新的头结点设置为head->next并删除原来的头结点
|
||||||
|
head = head->next;
|
||||||
|
free(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ListNode *cur = head;
|
||||||
|
// 当cur存在并且cur->next存在时
|
||||||
|
// 此解法需要判断cur存在因为cur指向head。若head本身为NULL或者原链表中元素都为val的话,cur也会为NULL
|
||||||
|
while(cur && (temp = cur->next)) {
|
||||||
|
// 若cur->next的值等于val
|
||||||
|
if(temp->val == val) {
|
||||||
|
// 将cur->next设置为cur->next->next并删除cur->next
|
||||||
|
cur->next = temp->next;
|
||||||
|
free(temp);
|
||||||
|
}
|
||||||
|
// 若cur->next不等于val,则将cur后移一位
|
||||||
|
else
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回头结点
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
设置一个虚拟头结点:
|
||||||
```c
|
```c
|
||||||
/**
|
/**
|
||||||
* Definition for singly-linked list.
|
* Definition for singly-linked list.
|
||||||
|
|
@ -324,7 +356,7 @@ function removeElements(head: ListNode | null, val: number): ListNode | null {
|
||||||
head = head.next;
|
head = head.next;
|
||||||
}
|
}
|
||||||
if (head === null) return head;
|
if (head === null) return head;
|
||||||
let pre: ListNode = head, cur: ListNode = head.next;
|
let pre: ListNode = head, cur: ListNode | null = head.next;
|
||||||
// 删除非头部节点
|
// 删除非头部节点
|
||||||
while (cur) {
|
while (cur) {
|
||||||
if (cur.val === val) {
|
if (cur.val === val) {
|
||||||
|
|
@ -342,14 +374,14 @@ function removeElements(head: ListNode | null, val: number): ListNode | null {
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
function removeElements(head: ListNode | null, val: number): ListNode | null {
|
function removeElements(head: ListNode | null, val: number): ListNode | null {
|
||||||
head = new ListNode(0, head);
|
let dummyHead = new ListNode(0, head);
|
||||||
let pre: ListNode = head, cur: ListNode = head.next;
|
let pre: ListNode = dummyHead, cur: ListNode | null = dummyHead.next;
|
||||||
// 删除非头部节点
|
// 删除非头部节点
|
||||||
while (cur) {
|
while (cur) {
|
||||||
if (cur.val === val) {
|
if (cur.val === val) {
|
||||||
pre.next = cur.next;
|
pre.next = cur.next;
|
||||||
} else {
|
} else {
|
||||||
pre = pre.next;
|
pre = cur;
|
||||||
}
|
}
|
||||||
cur = cur.next;
|
cur = cur.next;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
## 暴力解法
|
## 暴力解法
|
||||||
|
|
||||||
这道题目暴力解法当然是 两个for循环,然后不断的寻找符合条件的子序列,时间复杂度很明显是$O(n^2)$。
|
这道题目暴力解法当然是 两个for循环,然后不断的寻找符合条件的子序列,时间复杂度很明显是O(n^2)。
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
|
|
@ -47,8 +47,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
时间复杂度:$O(n^2)$
|
时间复杂度:O(n^2)
|
||||||
空间复杂度:$O(1)$
|
空间复杂度:O(1)
|
||||||
|
|
||||||
## 滑动窗口
|
## 滑动窗口
|
||||||
|
|
||||||
|
|
@ -80,7 +80,7 @@ public:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
可以发现**滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将$O(n^2)$的暴力解法降为$O(n)$。**
|
可以发现**滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。**
|
||||||
|
|
||||||
C++代码如下:
|
C++代码如下:
|
||||||
|
|
||||||
|
|
@ -107,12 +107,12 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
时间复杂度:$O(n)$
|
时间复杂度:O(n)
|
||||||
空间复杂度:$O(1)$
|
空间复杂度:O(1)
|
||||||
|
|
||||||
**一些录友会疑惑为什么时间复杂度是$O(n)$**。
|
**一些录友会疑惑为什么时间复杂度是O(n)**。
|
||||||
|
|
||||||
不要以为for里放一个while就以为是$O(n^2)$啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被被操作两次,所以时间复杂度是 2 × n 也就是$O(n)$。
|
不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
|
||||||
|
|
||||||
## 相关题目推荐
|
## 相关题目推荐
|
||||||
|
|
||||||
|
|
@ -198,7 +198,7 @@ JavaScript:
|
||||||
var minSubArrayLen = function(target, nums) {
|
var minSubArrayLen = function(target, nums) {
|
||||||
// 长度计算一次
|
// 长度计算一次
|
||||||
const len = nums.length;
|
const len = nums.length;
|
||||||
let l = r = sum = 0,
|
let l = r = sum = 0,
|
||||||
res = len + 1; // 子数组最大不会超过自身
|
res = len + 1; // 子数组最大不会超过自身
|
||||||
while(r < len) {
|
while(r < len) {
|
||||||
sum += nums[r++];
|
sum += nums[r++];
|
||||||
|
|
@ -260,12 +260,12 @@ Rust:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
impl Solution {
|
impl Solution {
|
||||||
pub fn min_sub_array_len(target: i32, nums: Vec<i32>) -> i32 {
|
pub fn min_sub_array_len(target: i32, nums: Vec<i32>) -> i32 {
|
||||||
let (mut result, mut subLength): (i32, i32) = (i32::MAX, 0);
|
let (mut result, mut subLength): (i32, i32) = (i32::MAX, 0);
|
||||||
let (mut sum, mut i) = (0, 0);
|
let (mut sum, mut i) = (0, 0);
|
||||||
|
|
||||||
for (pos, val) in nums.iter().enumerate() {
|
for (pos, val) in nums.iter().enumerate() {
|
||||||
sum += val;
|
sum += val;
|
||||||
while sum >= target {
|
while sum >= target {
|
||||||
subLength = (pos - i + 1) as i32;
|
subLength = (pos - i + 1) as i32;
|
||||||
if result > subLength {
|
if result > subLength {
|
||||||
|
|
@ -330,5 +330,76 @@ def min_sub_array_len(target, nums)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C:
|
||||||
|
暴力解法:
|
||||||
|
```c
|
||||||
|
int minSubArrayLen(int target, int* nums, int numsSize){
|
||||||
|
//初始化最小长度为INT_MAX
|
||||||
|
int minLength = INT_MAX;
|
||||||
|
int sum;
|
||||||
|
|
||||||
|
int left, right;
|
||||||
|
for(left = 0; left < numsSize; ++left) {
|
||||||
|
//每次遍历都清零sum,计算当前位置后和>=target的子数组的长度
|
||||||
|
sum = 0;
|
||||||
|
//从left开始,sum中添加元素
|
||||||
|
for(right = left; right < numsSize; ++right) {
|
||||||
|
sum += nums[right];
|
||||||
|
//若加入当前元素后,和大于target,则更新minLength
|
||||||
|
if(sum >= target) {
|
||||||
|
int subLength = right - left + 1;
|
||||||
|
minLength = minLength < subLength ? minLength : subLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//若minLength不为INT_MAX,则返回minLnegth
|
||||||
|
return minLength == INT_MAX ? 0 : minLength;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
滑动窗口:
|
||||||
|
```c
|
||||||
|
int minSubArrayLen(int target, int* nums, int numsSize){
|
||||||
|
//初始化最小长度为INT_MAX
|
||||||
|
int minLength = INT_MAX;
|
||||||
|
int sum = 0;
|
||||||
|
|
||||||
|
int left = 0, right = 0;
|
||||||
|
//右边界向右扩展
|
||||||
|
for(; right < numsSize; ++right) {
|
||||||
|
sum += nums[right];
|
||||||
|
//当sum的值大于等于target时,保存长度,并且收缩左边界
|
||||||
|
while(sum >= target) {
|
||||||
|
int subLength = right - left + 1;
|
||||||
|
minLength = minLength < subLength ? minLength : subLength;
|
||||||
|
sum -= nums[left++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//若minLength不为INT_MAX,则返回minLnegth
|
||||||
|
return minLength == INT_MAX ? 0 : minLength;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Kotlin:
|
||||||
|
```kotlin
|
||||||
|
class Solution {
|
||||||
|
fun minSubArrayLen(target: Int, nums: IntArray): Int {
|
||||||
|
var start = 0
|
||||||
|
var end = 0
|
||||||
|
var ret = Int.MAX_VALUE
|
||||||
|
var count = 0
|
||||||
|
while (end < nums.size) {
|
||||||
|
count += nums[end]
|
||||||
|
while (count >= target) {
|
||||||
|
ret = if (ret > (end - start + 1)) end - start + 1 else ret
|
||||||
|
count -= nums[start++]
|
||||||
|
}
|
||||||
|
end++
|
||||||
|
}
|
||||||
|
return if (ret == Int.MAX_VALUE) 0 else ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -123,22 +123,24 @@ Python:
|
||||||
```Python
|
```Python
|
||||||
class Solution:
|
class Solution:
|
||||||
def rob(self, nums: List[int]) -> int:
|
def rob(self, nums: List[int]) -> int:
|
||||||
if (n := len(nums)) == 0:
|
#在198入门级的打家劫舍问题上分两种情况考虑
|
||||||
return 0
|
#一是不偷第一间房,二是不偷最后一间房
|
||||||
if n == 1:
|
if len(nums)==1:#题目中提示nums.length>=1,所以不需要考虑len(nums)==0的情况
|
||||||
return nums[0]
|
return nums[0]
|
||||||
result1 = self.robRange(nums, 0, n - 2)
|
val1=self.roblist(nums[1:])#不偷第一间房
|
||||||
result2 = self.robRange(nums, 1, n - 1)
|
val2=self.roblist(nums[:-1])#不偷最后一间房
|
||||||
return max(result1 , result2)
|
return max(val1,val2)
|
||||||
|
|
||||||
def robRange(self, nums: List[int], start: int, end: int) -> int:
|
def robRange(self,nums):
|
||||||
if end == start: return nums[start]
|
l=len(nums)
|
||||||
dp = [0] * len(nums)
|
dp=[0]*l
|
||||||
dp[start] = nums[start]
|
dp[0]=nums[0]
|
||||||
dp[start + 1] = max(nums[start], nums[start + 1])
|
for i in range(1,l):
|
||||||
for i in range(start + 2, end + 1):
|
if i==1:
|
||||||
dp[i] = max(dp[i -2] + nums[i], dp[i - 1])
|
dp[i]=max(dp[i-1],nums[i])
|
||||||
return dp[end]
|
else:
|
||||||
|
dp[i]=max(dp[i-1],dp[i-2]+nums[i])
|
||||||
|
return dp[-1]
|
||||||
```
|
```
|
||||||
|
|
||||||
javascipt:
|
javascipt:
|
||||||
|
|
|
||||||
|
|
@ -396,6 +396,30 @@ var combinationSum3 = function(k, n) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function combinationSum3(k: number, n: number): number[][] {
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
function backTracking(k: number, n: number, sum: number, startIndex: number, tempArr: number[]): void {
|
||||||
|
if (sum > n) return;
|
||||||
|
if (tempArr.length === k) {
|
||||||
|
if (sum === n) {
|
||||||
|
resArr.push(tempArr.slice());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = startIndex; i <= 9 - (k - tempArr.length) + 1; i++) {
|
||||||
|
tempArr.push(i);
|
||||||
|
backTracking(k, n, sum + i, i + 1, tempArr);
|
||||||
|
tempArr.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backTracking(k, n, 0, 1, []);
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C
|
## C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(\log n)$,算上了递归系统栈占用的空间
|
* 空间复杂度:O(log n),算上了递归系统栈占用的空间
|
||||||
|
|
||||||
**网上基本都是这个精简的代码版本,其实不建议大家照着这个来写,代码确实精简,但隐藏了一些内容,连遍历的顺序都看不出来,所以初学者建议学习版本一的代码,稳稳的打基础**。
|
**网上基本都是这个精简的代码版本,其实不建议大家照着这个来写,代码确实精简,但隐藏了一些内容,连遍历的顺序都看不出来,所以初学者建议学习版本一的代码,稳稳的打基础**。
|
||||||
|
|
||||||
|
|
@ -138,8 +138,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
## 完全二叉树
|
## 完全二叉树
|
||||||
|
|
||||||
|
|
@ -185,8 +185,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(\log n × \log n)$
|
* 时间复杂度:O(log n × log n)
|
||||||
* 空间复杂度:$O(\log n)$
|
* 空间复杂度:O(log n)
|
||||||
|
|
||||||
# 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
@ -447,7 +447,63 @@ var countNodes = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScrpt:
|
||||||
|
|
||||||
|
> 递归法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function countNodes(root: TreeNode | null): number {
|
||||||
|
if (root === null) return 0;
|
||||||
|
return 1 + countNodes(root.left) + countNodes(root.right);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 迭代法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function countNodes(root: TreeNode | null): number {
|
||||||
|
let helperQueue: TreeNode[] = [];
|
||||||
|
let resCount: number = 0;
|
||||||
|
let tempNode: TreeNode;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
tempNode = helperQueue.shift()!;
|
||||||
|
resCount++;
|
||||||
|
if (tempNode.left) helperQueue.push(tempNode.left);
|
||||||
|
if (tempNode.right) helperQueue.push(tempNode.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resCount;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 利用完全二叉树性质
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function countNodes(root: TreeNode | null): number {
|
||||||
|
if (root === null) return 0;
|
||||||
|
let left: number = 0,
|
||||||
|
right: number = 0;
|
||||||
|
let curNode: TreeNode | null= root;
|
||||||
|
while (curNode !== null) {
|
||||||
|
left++;
|
||||||
|
curNode = curNode.left;
|
||||||
|
}
|
||||||
|
curNode = root;
|
||||||
|
while (curNode !== null) {
|
||||||
|
right++;
|
||||||
|
curNode = curNode.right;
|
||||||
|
}
|
||||||
|
if (left === right) {
|
||||||
|
return 2 ** left - 1;
|
||||||
|
}
|
||||||
|
return 1 + countNodes(root.left) + countNodes(root.right);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## C:
|
## C:
|
||||||
|
|
||||||
递归法
|
递归法
|
||||||
```c
|
```c
|
||||||
int countNodes(struct TreeNode* root) {
|
int countNodes(struct TreeNode* root) {
|
||||||
|
|
@ -538,7 +594,7 @@ func _countNodes(_ root: TreeNode?) -> Int {
|
||||||
return 1 + leftCount + rightCount
|
return 1 + leftCount + rightCount
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> 层序遍历
|
> 层序遍历
|
||||||
```Swift
|
```Swift
|
||||||
func countNodes(_ root: TreeNode?) -> Int {
|
func countNodes(_ root: TreeNode?) -> Int {
|
||||||
|
|
@ -564,7 +620,7 @@ func countNodes(_ root: TreeNode?) -> Int {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> 利用完全二叉树性质
|
> 利用完全二叉树性质
|
||||||
```Swift
|
```Swift
|
||||||
func countNodes(_ root: TreeNode?) -> Int {
|
func countNodes(_ root: TreeNode?) -> Int {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
|
|
||||||
模拟的队列执行语句如下:
|
模拟的队列执行语句如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
queue.push(1);
|
queue.push(1);
|
||||||
queue.push(2);
|
queue.push(2);
|
||||||
queue.pop(); // 注意弹出的操作
|
queue.pop(); // 注意弹出的操作
|
||||||
|
|
@ -354,6 +354,32 @@ class MyStack:
|
||||||
return len(self.queue_in) == 0
|
return len(self.queue_in) == 0
|
||||||
|
|
||||||
```
|
```
|
||||||
|
优化,使用一个队列实现
|
||||||
|
```python
|
||||||
|
class MyStack:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.que = deque()
|
||||||
|
|
||||||
|
def push(self, x: int) -> None:
|
||||||
|
self.que.append(x)
|
||||||
|
|
||||||
|
def pop(self) -> int:
|
||||||
|
if self.empty():
|
||||||
|
return None
|
||||||
|
for i in range(len(self.que)-1):
|
||||||
|
self.que.append(self.que.popleft())
|
||||||
|
return self.que.popleft()
|
||||||
|
|
||||||
|
def top(self) -> int:
|
||||||
|
if self.empty():
|
||||||
|
return None
|
||||||
|
return self.que[-1]
|
||||||
|
|
||||||
|
def empty(self) -> bool:
|
||||||
|
return not self.que
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
|
@ -598,7 +624,80 @@ MyStack.prototype.empty = function() {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
版本一:使用两个队列模拟栈
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class MyStack {
|
||||||
|
private queue: number[];
|
||||||
|
private tempQueue: number[];
|
||||||
|
constructor() {
|
||||||
|
this.queue = [];
|
||||||
|
this.tempQueue = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
push(x: number): void {
|
||||||
|
this.queue.push(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(): number {
|
||||||
|
for (let i = 0, length = this.queue.length - 1; i < length; i++) {
|
||||||
|
this.tempQueue.push(this.queue.shift()!);
|
||||||
|
}
|
||||||
|
let res: number = this.queue.pop()!;
|
||||||
|
let temp: number[] = this.queue;
|
||||||
|
this.queue = this.tempQueue;
|
||||||
|
this.tempQueue = temp;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
top(): number {
|
||||||
|
let res: number = this.pop();
|
||||||
|
this.push(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
empty(): boolean {
|
||||||
|
return this.queue.length === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
版本二:使用一个队列模拟栈
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class MyStack {
|
||||||
|
private queue: number[];
|
||||||
|
constructor() {
|
||||||
|
this.queue = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
push(x: number): void {
|
||||||
|
this.queue.push(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(): number {
|
||||||
|
for (let i = 0, length = this.queue.length - 1; i < length; i++) {
|
||||||
|
this.queue.push(this.queue.shift()!);
|
||||||
|
}
|
||||||
|
return this.queue.shift()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
top(): number {
|
||||||
|
let res: number = this.pop();
|
||||||
|
this.push(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
empty(): boolean {
|
||||||
|
return this.queue.length === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Swift
|
Swift
|
||||||
|
|
||||||
```Swift
|
```Swift
|
||||||
// 定义一个队列数据结构
|
// 定义一个队列数据结构
|
||||||
class Queue {
|
class Queue {
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,6 @@
|
||||||
|
|
||||||
## 递归法
|
## 递归法
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://programmercarl.com/二叉树的递归遍历.html)详细讲解了。
|
对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://programmercarl.com/二叉树的递归遍历.html)详细讲解了。
|
||||||
|
|
||||||
我们下文以前序遍历为例,通过动画来看一下翻转的过程:
|
我们下文以前序遍历为例,通过动画来看一下翻转的过程:
|
||||||
|
|
@ -63,7 +61,7 @@
|
||||||
|
|
||||||
返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为`TreeNode*`。
|
返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为`TreeNode*`。
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
TreeNode* invertTree(TreeNode* root)
|
TreeNode* invertTree(TreeNode* root)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -71,7 +69,7 @@ TreeNode* invertTree(TreeNode* root)
|
||||||
|
|
||||||
当前节点为空的时候,就返回
|
当前节点为空的时候,就返回
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
if (root == NULL) return root;
|
if (root == NULL) return root;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -79,7 +77,7 @@ if (root == NULL) return root;
|
||||||
|
|
||||||
因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。
|
因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
swap(root->left, root->right);
|
swap(root->left, root->right);
|
||||||
invertTree(root->left);
|
invertTree(root->left);
|
||||||
invertTree(root->right);
|
invertTree(root->right);
|
||||||
|
|
@ -257,7 +255,7 @@ public:
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
### Java:
|
### Java
|
||||||
|
|
||||||
```Java
|
```Java
|
||||||
//DFS递归
|
//DFS递归
|
||||||
|
|
@ -469,8 +467,6 @@ func invertTree(root *TreeNode) *TreeNode {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### JavaScript
|
### JavaScript
|
||||||
|
|
||||||
使用递归版本的前序遍历
|
使用递归版本的前序遍历
|
||||||
|
|
@ -563,7 +559,135 @@ var invertTree = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### C:
|
### TypeScript:
|
||||||
|
|
||||||
|
递归法:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 递归法(前序遍历)
|
||||||
|
function invertTree(root: TreeNode | null): TreeNode | null {
|
||||||
|
if (root === null) return root;
|
||||||
|
let tempNode: TreeNode | null = root.left;
|
||||||
|
root.left = root.right;
|
||||||
|
root.right = tempNode;
|
||||||
|
invertTree(root.left);
|
||||||
|
invertTree(root.right);
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 递归法(后序遍历)
|
||||||
|
function invertTree(root: TreeNode | null): TreeNode | null {
|
||||||
|
if (root === null) return root;
|
||||||
|
invertTree(root.left);
|
||||||
|
invertTree(root.right);
|
||||||
|
let tempNode: TreeNode | null = root.left;
|
||||||
|
root.left = root.right;
|
||||||
|
root.right = tempNode;
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 递归法(中序遍历)
|
||||||
|
function invertTree(root: TreeNode | null): TreeNode | null {
|
||||||
|
if (root === null) return root;
|
||||||
|
invertTree(root.left);
|
||||||
|
let tempNode: TreeNode | null = root.left;
|
||||||
|
root.left = root.right;
|
||||||
|
root.right = tempNode;
|
||||||
|
// 因为左右节点已经进行交换,此时的root.left 是原先的root.right
|
||||||
|
invertTree(root.left);
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
迭代法:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 迭代法(栈模拟前序遍历)
|
||||||
|
function invertTree(root: TreeNode | null): TreeNode | null {
|
||||||
|
let helperStack: TreeNode[] = [];
|
||||||
|
let curNode: TreeNode,
|
||||||
|
tempNode: TreeNode | null;
|
||||||
|
if (root !== null) helperStack.push(root);
|
||||||
|
while (helperStack.length > 0) {
|
||||||
|
curNode = helperStack.pop()!;
|
||||||
|
// 入栈操作最好在交换节点之前进行,便于理解
|
||||||
|
if (curNode.right) helperStack.push(curNode.right);
|
||||||
|
if (curNode.left) helperStack.push(curNode.left);
|
||||||
|
tempNode = curNode.left;
|
||||||
|
curNode.left = curNode.right;
|
||||||
|
curNode.right = tempNode;
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 迭代法(栈模拟中序遍历-统一写法形式)
|
||||||
|
function invertTree(root: TreeNode | null): TreeNode | null {
|
||||||
|
let helperStack: (TreeNode | null)[] = [];
|
||||||
|
let curNode: TreeNode | null,
|
||||||
|
tempNode: TreeNode | null;
|
||||||
|
if (root !== null) helperStack.push(root);
|
||||||
|
while (helperStack.length > 0) {
|
||||||
|
curNode = helperStack.pop();
|
||||||
|
if (curNode !== null) {
|
||||||
|
if (curNode.right !== null) helperStack.push(curNode.right);
|
||||||
|
helperStack.push(curNode);
|
||||||
|
helperStack.push(null);
|
||||||
|
if (curNode.left !== null) helperStack.push(curNode.left);
|
||||||
|
} else {
|
||||||
|
curNode = helperStack.pop()!;
|
||||||
|
tempNode = curNode.left;
|
||||||
|
curNode.left = curNode.right;
|
||||||
|
curNode.right = tempNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 迭代法(栈模拟后序遍历-统一写法形式)
|
||||||
|
function invertTree(root: TreeNode | null): TreeNode | null {
|
||||||
|
let helperStack: (TreeNode | null)[] = [];
|
||||||
|
let curNode: TreeNode | null,
|
||||||
|
tempNode: TreeNode | null;
|
||||||
|
if (root !== null) helperStack.push(root);
|
||||||
|
while (helperStack.length > 0) {
|
||||||
|
curNode = helperStack.pop();
|
||||||
|
if (curNode !== null) {
|
||||||
|
helperStack.push(curNode);
|
||||||
|
helperStack.push(null);
|
||||||
|
if (curNode.right !== null) helperStack.push(curNode.right);
|
||||||
|
if (curNode.left !== null) helperStack.push(curNode.left);
|
||||||
|
} else {
|
||||||
|
curNode = helperStack.pop()!;
|
||||||
|
tempNode = curNode.left;
|
||||||
|
curNode.left = curNode.right;
|
||||||
|
curNode.right = tempNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 迭代法(队列模拟层序遍历)
|
||||||
|
function invertTree(root: TreeNode | null): TreeNode | null {
|
||||||
|
const helperQueue: TreeNode[] = [];
|
||||||
|
let curNode: TreeNode,
|
||||||
|
tempNode: TreeNode | null;
|
||||||
|
if (root !== null) helperQueue.push(root);
|
||||||
|
while (helperQueue.length > 0) {
|
||||||
|
for (let i = 0, length = helperQueue.length; i < length; i++) {
|
||||||
|
curNode = helperQueue.shift()!;
|
||||||
|
tempNode = curNode.left;
|
||||||
|
curNode.left = curNode.right;
|
||||||
|
curNode.right = tempNode;
|
||||||
|
if (curNode.left !== null) helperQueue.push(curNode.left);
|
||||||
|
if (curNode.right !== null) helperQueue.push(curNode.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### C
|
||||||
|
|
||||||
递归法
|
递归法
|
||||||
```c
|
```c
|
||||||
struct TreeNode* invertTree(struct TreeNode* root){
|
struct TreeNode* invertTree(struct TreeNode* root){
|
||||||
|
|
@ -647,5 +771,54 @@ func invertTree1(_ root: TreeNode?) -> TreeNode? {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Swift
|
||||||
|
|
||||||
|
深度优先递归。
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func invertTree(_ root: TreeNode?) -> TreeNode? {
|
||||||
|
guard let node = root else { return root }
|
||||||
|
swap(&node.left, &node.right)
|
||||||
|
_ = invertTree(node.left)
|
||||||
|
_ = invertTree(node.right)
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
深度优先迭代,子结点顺序不重要,从根结点出发深度遍历即可。
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func invertTree(_ root: TreeNode?) -> TreeNode? {
|
||||||
|
guard let node = root else { return root }
|
||||||
|
var stack = [node]
|
||||||
|
while !stack.isEmpty {
|
||||||
|
guard let node = stack.popLast() else { break }
|
||||||
|
swap(&node.left, &node.right)
|
||||||
|
if let node = node.left { stack.append(node) }
|
||||||
|
if let node = node.right { stack.append(node) }
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
广度优先迭代。
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func invertTree(_ root: TreeNode?) -> TreeNode? {
|
||||||
|
guard let node = root else { return root }
|
||||||
|
var queue = [node]
|
||||||
|
while !queue.isEmpty {
|
||||||
|
let count = queue.count
|
||||||
|
for _ in 0 ..< count {
|
||||||
|
let node = queue.removeFirst()
|
||||||
|
swap(&node.left, &node.right)
|
||||||
|
if let node = node.left { queue.append(node) }
|
||||||
|
if let node = node.right { queue.append(node) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ empty() -- 返回队列是否为空。
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
MyQueue queue = new MyQueue();
|
MyQueue queue = new MyQueue();
|
||||||
queue.push(1);
|
queue.push(1);
|
||||||
queue.push(2);
|
queue.push(2);
|
||||||
|
|
@ -275,15 +275,11 @@ func (this *MyQueue) Pop() int {
|
||||||
|
|
||||||
/** Get the front element. */
|
/** Get the front element. */
|
||||||
func (this *MyQueue) Peek() int {
|
func (this *MyQueue) Peek() int {
|
||||||
for len(this.stack) != 0 {
|
val := this.Pop()
|
||||||
val := this.stack[len(this.stack)-1]
|
if val == 0 {
|
||||||
this.stack = this.stack[:len(this.stack)-1]
|
|
||||||
this.back = append(this.back, val)
|
|
||||||
}
|
|
||||||
if len(this.back) == 0 {
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
val := this.back[len(this.back)-1]
|
this.back = append(this.back, val)
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,7 +344,44 @@ MyQueue.prototype.empty = function() {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class MyQueue {
|
||||||
|
private stackIn: number[]
|
||||||
|
private stackOut: number[]
|
||||||
|
constructor() {
|
||||||
|
this.stackIn = [];
|
||||||
|
this.stackOut = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
push(x: number): void {
|
||||||
|
this.stackIn.push(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(): number {
|
||||||
|
if (this.stackOut.length === 0) {
|
||||||
|
while (this.stackIn.length > 0) {
|
||||||
|
this.stackOut.push(this.stackIn.pop()!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.stackOut.pop()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
peek(): number {
|
||||||
|
let temp: number = this.pop();
|
||||||
|
this.stackOut.push(temp);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
empty(): boolean {
|
||||||
|
return this.stackIn.length === 0 && this.stackOut.length === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Swift:
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
class MyQueue {
|
class MyQueue {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -350,6 +350,39 @@ var lowestCommonAncestor = function(root, p, q) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
> 递归法:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
|
||||||
|
if (root.val > p.val && root.val > q.val)
|
||||||
|
return lowestCommonAncestor(root.left, p, q);
|
||||||
|
if (root.val < p.val && root.val < q.val)
|
||||||
|
return lowestCommonAncestor(root.right, p, q);
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 迭代法:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
|
||||||
|
while (root !== null) {
|
||||||
|
if (root.val > p.val && root.val > q.val) {
|
||||||
|
root = root.left;
|
||||||
|
} else if (root.val < p.val && root.val < q.val) {
|
||||||
|
root = root.right;
|
||||||
|
} else {
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,13 @@
|
||||||
|
|
||||||
接下来就看如何判断一个节点是节点q和节点p的公共公共祖先呢。
|
接下来就看如何判断一个节点是节点q和节点p的公共公共祖先呢。
|
||||||
|
|
||||||
**如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。**
|
**首先最容易想到的一个情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。**
|
||||||
|
|
||||||
使用后序遍历,回溯的过程,就是从低向上遍历节点,一旦发现如何这个条件的节点,就是最近公共节点了。
|
**但是很多人容易忽略一个情况,就是节点本身p(q),它拥有一个子孙节点q(p)。**
|
||||||
|
|
||||||
|
使用后序遍历,回溯的过程,就是从低向上遍历节点,一旦发现满足第一种情况的节点,就是最近公共节点了。
|
||||||
|
|
||||||
|
**但是如果p或者q本身就是最近公共祖先呢?其实只需要找到一个节点是p或者q的时候,直接返回当前节点,无需继续递归子树。如果接下来的遍历中找到了后继节点满足第一种情况则修改返回值为后继节点,否则,继续返回已找到的节点即可。为什么满足第一种情况的节点一定是p或q的后继节点呢?大家可以仔细思考一下。**
|
||||||
|
|
||||||
递归三部曲:
|
递归三部曲:
|
||||||
|
|
||||||
|
|
@ -325,6 +329,20 @@ var lowestCommonAncestor = function(root, p, q) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
|
||||||
|
if (root === null || root === p || root === q) return root;
|
||||||
|
const left = lowestCommonAncestor(root.left, p, q);
|
||||||
|
const right = lowestCommonAncestor(root.right, p, q);
|
||||||
|
if (left !== null && right !== null) return root;
|
||||||
|
if (left !== null) return left;
|
||||||
|
if (right !== null) return right;
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
|
|
||||||
这个队列应该长这个样子:
|
这个队列应该长这个样子:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
class MyQueue {
|
class MyQueue {
|
||||||
public:
|
public:
|
||||||
void pop(int value) {
|
void pop(int value) {
|
||||||
|
|
@ -193,7 +193,7 @@ public:
|
||||||
|
|
||||||
# 扩展
|
# 扩展
|
||||||
|
|
||||||
大家貌似对单调队列 都有一些疑惑,首先要明确的是,题解中单调队列里的pop和push接口,仅适用于本题哈。单调队列不是一成不变的,而是不同场景不同写法,总之要保证队列里单调递减或递增的原则,所以叫做单调队列。 不要以为本地中的单调队列实现就是固定的写法哈。
|
大家貌似对单调队列 都有一些疑惑,首先要明确的是,题解中单调队列里的pop和push接口,仅适用于本题哈。单调队列不是一成不变的,而是不同场景不同写法,总之要保证队列里单调递减或递增的原则,所以叫做单调队列。 不要以为本题中的单调队列实现就是固定的写法哈。
|
||||||
|
|
||||||
大家貌似对deque也有一些疑惑,C++中deque是stack和queue默认的底层实现容器(这个我们之前已经讲过啦),deque是可以两边扩展的,而且deque里元素并不是严格的连续分布的。
|
大家貌似对deque也有一些疑惑,C++中deque是stack和queue默认的底层实现容器(这个我们之前已经讲过啦),deque是可以两边扩展的,而且deque里元素并不是严格的连续分布的。
|
||||||
|
|
||||||
|
|
@ -395,30 +395,102 @@ func maxSlidingWindow(nums []int, k int) []int {
|
||||||
|
|
||||||
Javascript:
|
Javascript:
|
||||||
```javascript
|
```javascript
|
||||||
|
/**
|
||||||
|
* @param {number[]} nums
|
||||||
|
* @param {number} k
|
||||||
|
* @return {number[]}
|
||||||
|
*/
|
||||||
var maxSlidingWindow = function (nums, k) {
|
var maxSlidingWindow = function (nums, k) {
|
||||||
// 队列数组(存放的是元素下标,为了取值方便)
|
class MonoQueue {
|
||||||
const q = [];
|
queue;
|
||||||
// 结果数组
|
constructor() {
|
||||||
const ans = [];
|
this.queue = [];
|
||||||
for (let i = 0; i < nums.length; i++) {
|
}
|
||||||
// 若队列不为空,且当前元素大于等于队尾所存下标的元素,则弹出队尾
|
enqueue(value) {
|
||||||
while (q.length && nums[i] >= nums[q[q.length - 1]]) {
|
let back = this.queue[this.queue.length - 1];
|
||||||
q.pop();
|
while (back !== undefined && back < value) {
|
||||||
|
this.queue.pop();
|
||||||
|
back = this.queue[this.queue.length - 1];
|
||||||
|
}
|
||||||
|
this.queue.push(value);
|
||||||
|
}
|
||||||
|
dequeue(value) {
|
||||||
|
let front = this.front();
|
||||||
|
if (front === value) {
|
||||||
|
this.queue.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
front() {
|
||||||
|
return this.queue[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 入队当前元素下标
|
let helperQueue = new MonoQueue();
|
||||||
q.push(i);
|
let i = 0, j = 0;
|
||||||
// 判断当前最大值(即队首元素)是否在窗口中,若不在便将其出队
|
let resArr = [];
|
||||||
if (q[0] <= i - k) {
|
while (j < k) {
|
||||||
q.shift();
|
helperQueue.enqueue(nums[j++]);
|
||||||
}
|
}
|
||||||
// 当达到窗口大小时便开始向结果中添加数据
|
resArr.push(helperQueue.front());
|
||||||
if (i >= k - 1) ans.push(nums[q[0]]);
|
while (j < nums.length) {
|
||||||
}
|
helperQueue.enqueue(nums[j]);
|
||||||
return ans;
|
helperQueue.dequeue(nums[i]);
|
||||||
|
resArr.push(helperQueue.front());
|
||||||
|
i++, j++;
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function maxSlidingWindow(nums: number[], k: number): number[] {
|
||||||
|
/** 单调递减队列 */
|
||||||
|
class MonoQueue {
|
||||||
|
private queue: number[];
|
||||||
|
constructor() {
|
||||||
|
this.queue = [];
|
||||||
|
};
|
||||||
|
/** 入队:value如果大于队尾元素,则将队尾元素删除,直至队尾元素大于value,或者队列为空 */
|
||||||
|
public enqueue(value: number): void {
|
||||||
|
let back: number | undefined = this.queue[this.queue.length - 1];
|
||||||
|
while (back !== undefined && back < value) {
|
||||||
|
this.queue.pop();
|
||||||
|
back = this.queue[this.queue.length - 1];
|
||||||
|
}
|
||||||
|
this.queue.push(value);
|
||||||
|
};
|
||||||
|
/** 出队:只有当队头元素等于value,才出队 */
|
||||||
|
public dequeue(value: number): void {
|
||||||
|
let top: number | undefined = this.top();
|
||||||
|
if (top !== undefined && top === value) {
|
||||||
|
this.queue.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public top(): number | undefined {
|
||||||
|
return this.queue[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const helperQueue: MonoQueue = new MonoQueue();
|
||||||
|
let i: number = 0,
|
||||||
|
j: number = 0;
|
||||||
|
let resArr: number[] = [];
|
||||||
|
while (j < k) {
|
||||||
|
helperQueue.enqueue(nums[j++]);
|
||||||
|
}
|
||||||
|
resArr.push(helperQueue.top()!);
|
||||||
|
while (j < nums.length) {
|
||||||
|
helperQueue.enqueue(nums[j]);
|
||||||
|
helperQueue.dequeue(nums[i]);
|
||||||
|
resArr.push(helperQueue.top()!);
|
||||||
|
j++, i++;
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
Swift:
|
||||||
|
|
||||||
```Swift
|
```Swift
|
||||||
/// 双向链表
|
/// 双向链表
|
||||||
class DoublyListNode {
|
class DoublyListNode {
|
||||||
|
|
@ -525,5 +597,39 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Swift解法二:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] {
|
||||||
|
var result = [Int]()
|
||||||
|
var window = [Int]()
|
||||||
|
var right = 0, left = right - k + 1
|
||||||
|
|
||||||
|
while right < nums.count {
|
||||||
|
let value = nums[right]
|
||||||
|
|
||||||
|
// 因为窗口移动丢弃的左边数
|
||||||
|
if left > 0, left - 1 == window.first {
|
||||||
|
window.removeFirst()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保证末尾的是最大的
|
||||||
|
while !window.isEmpty, value > nums[window.last!] {
|
||||||
|
window.removeLast()
|
||||||
|
}
|
||||||
|
window.append(right)
|
||||||
|
|
||||||
|
if left >= 0 { // 窗口形成
|
||||||
|
result.append(nums[window.first!])
|
||||||
|
}
|
||||||
|
|
||||||
|
right += 1
|
||||||
|
left += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
## 思路
|
## 思路
|
||||||
|
|
||||||
先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 $O(n^2)$。
|
先看暴力的解法,两层for循环,同时还要记录字符是否重复出现,很明显时间复杂度是 O(n^2)。
|
||||||
|
|
||||||
暴力的方法这里就不做介绍了,直接看一下有没有更优的方式。
|
暴力的方法这里就不做介绍了,直接看一下有没有更优的方式。
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
|
|
||||||
最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。
|
最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。
|
||||||
|
|
||||||
时间复杂度为$O(n)$,空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为$O(1)$。
|
时间复杂度为O(n),空间上因为定义是的一个常量大小的辅助数组,所以空间复杂度为O(1)。
|
||||||
|
|
||||||
|
|
||||||
C++ 代码如下:
|
C++ 代码如下:
|
||||||
|
|
|
||||||
|
|
@ -433,9 +433,9 @@ class Solution:
|
||||||
if cur.right:
|
if cur.right:
|
||||||
self.traversal(cur.right, path + '->', result)
|
self.traversal(cur.right, path + '->', result)
|
||||||
```
|
```
|
||||||
|
|
||||||
迭代法:
|
迭代法:
|
||||||
|
|
||||||
```python3
|
```python3
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
|
|
@ -463,13 +463,13 @@ class Solution:
|
||||||
|
|
||||||
return result
|
return result
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
递归法:
|
递归法:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func binaryTreePaths(root *TreeNode) []string {
|
func binaryTreePaths(root *TreeNode) []string {
|
||||||
res := make([]string, 0)
|
res := make([]string, 0)
|
||||||
|
|
@ -492,7 +492,7 @@ func binaryTreePaths(root *TreeNode) []string {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
迭代法:
|
迭代法:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
|
@ -581,7 +581,126 @@ var binaryTreePaths = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
> 递归法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function binaryTreePaths(root: TreeNode | null): string[] {
|
||||||
|
function recur(node: TreeNode, route: string, resArr: string[]): void {
|
||||||
|
route += String(node.val);
|
||||||
|
if (node.left === null && node.right === null) {
|
||||||
|
resArr.push(route);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node.left !== null) recur(node.left, route + '->', resArr);
|
||||||
|
if (node.right !== null) recur(node.right, route + '->', resArr);
|
||||||
|
}
|
||||||
|
const resArr: string[] = [];
|
||||||
|
if (root === null) return resArr;
|
||||||
|
recur(root, '', resArr);
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 迭代法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 迭代法2
|
||||||
|
function binaryTreePaths(root: TreeNode | null): string[] {
|
||||||
|
let helperStack: TreeNode[] = [];
|
||||||
|
let tempNode: TreeNode;
|
||||||
|
let routeArr: string[] = [];
|
||||||
|
let resArr: string[] = [];
|
||||||
|
if (root !== null) {
|
||||||
|
helperStack.push(root);
|
||||||
|
routeArr.push(String(root.val));
|
||||||
|
};
|
||||||
|
while (helperStack.length > 0) {
|
||||||
|
tempNode = helperStack.pop()!;
|
||||||
|
let route: string = routeArr.pop()!; // tempNode 对应的路径
|
||||||
|
if (tempNode.left === null && tempNode.right === null) {
|
||||||
|
resArr.push(route);
|
||||||
|
}
|
||||||
|
if (tempNode.right !== null) {
|
||||||
|
helperStack.push(tempNode.right);
|
||||||
|
routeArr.push(route + '->' + tempNode.right.val); // tempNode.right 对应的路径
|
||||||
|
}
|
||||||
|
if (tempNode.left !== null) {
|
||||||
|
helperStack.push(tempNode.left);
|
||||||
|
routeArr.push(route + '->' + tempNode.left.val); // tempNode.left 对应的路径
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
|
||||||
|
> 递归/回溯
|
||||||
|
```swift
|
||||||
|
func binaryTreePaths(_ root: TreeNode?) -> [String] {
|
||||||
|
var res = [String]()
|
||||||
|
guard let root = root else {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
var path = [Int]()
|
||||||
|
_binaryTreePaths(root, path: &path, res: &res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
func _binaryTreePaths(_ root: TreeNode, path: inout [Int], res: inout [String]) {
|
||||||
|
path.append(root.val)
|
||||||
|
if root.left == nil && root.right == nil {
|
||||||
|
var str = ""
|
||||||
|
for i in 0 ..< path.count - 1 {
|
||||||
|
str.append("\(path[i])->")
|
||||||
|
}
|
||||||
|
str.append("\(path.last!)")
|
||||||
|
res.append(str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let left = root.left {
|
||||||
|
_binaryTreePaths(left, path: &path, res: &res)
|
||||||
|
path.removeLast()
|
||||||
|
}
|
||||||
|
if let right = root.right {
|
||||||
|
_binaryTreePaths(right, path: &path, res: &res)
|
||||||
|
path.removeLast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 迭代
|
||||||
|
```swift
|
||||||
|
func binaryTreePaths(_ root: TreeNode?) -> [String] {
|
||||||
|
var res = [String]()
|
||||||
|
guard let root = root else {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
var stackNode = [TreeNode]()
|
||||||
|
stackNode.append(root)
|
||||||
|
|
||||||
|
var stackStr = [String]()
|
||||||
|
stackStr.append("\(root.val)")
|
||||||
|
|
||||||
|
while !stackNode.isEmpty {
|
||||||
|
let node = stackNode.popLast()!
|
||||||
|
let str = stackStr.popLast()!
|
||||||
|
if node.left == nil && node.right == nil {
|
||||||
|
res.append(str)
|
||||||
|
}
|
||||||
|
if let left = node.left {
|
||||||
|
stackNode.append(left)
|
||||||
|
stackStr.append("\(str)->\(left.val)")
|
||||||
|
}
|
||||||
|
if let right = node.right {
|
||||||
|
stackNode.append(right)
|
||||||
|
stackStr.append("\(str)->\(right.val)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@ class Solution {
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def numSquares(self, n: int) -> int:
|
def numSquares(self, n: int) -> int:
|
||||||
'''版本一,先遍历背包, 再遍历物品'''
|
'''版本一,先遍历背包, 再遍历物品'''
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
好了,我们说一说双指针法,大家如果对双指针还不熟悉,可以看我的这篇总结[双指针法:总结篇!](https://programmercarl.com/双指针总结.html)。
|
好了,我们说一说双指针法,大家如果对双指针还不熟悉,可以看我的这篇总结[双指针法:总结篇!](https://programmercarl.com/双指针总结.html)。
|
||||||
|
|
||||||
双指针法在数组移除元素中,可以达到$O(n)$的时间复杂度,在[27.移除元素](https://programmercarl.com/0027.移除元素.html)里已经详细讲解了,那么本题和移除元素其实是一个套路。
|
双指针法在数组移除元素中,可以达到O(n)的时间复杂度,在[27.移除元素](https://programmercarl.com/0027.移除元素.html)里已经详细讲解了,那么本题和移除元素其实是一个套路。
|
||||||
|
|
||||||
**相当于对整个数组移除元素0,然后slowIndex之后都是移除元素0的冗余元素,把这些元素都赋值为0就可以了**。
|
**相当于对整个数组移除元素0,然后slowIndex之后都是移除元素0的冗余元素,把这些元素都赋值为0就可以了**。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
1. dp[i]的定义
|
1. dp[i]的定义
|
||||||
|
|
||||||
**dp[i]表示i之前包括i的最长上升子序列的长度**。
|
**dp[i]表示i之前包括i的以nums[i]结尾最长上升子序列的长度**
|
||||||
|
|
||||||
2. 状态转移方程
|
2. 状态转移方程
|
||||||
|
|
||||||
|
|
@ -168,6 +168,39 @@ func lengthOfLIS(nums []int ) int {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 动态规划求解
|
||||||
|
func lengthOfLIS(nums []int) int {
|
||||||
|
// dp数组的定义 dp[i]表示取第i个元素的时候,表示子序列的长度,其中包括 nums[i] 这个元素
|
||||||
|
dp := make([]int, len(nums))
|
||||||
|
|
||||||
|
// 初始化,所有的元素都应该初始化为1
|
||||||
|
for i := range dp {
|
||||||
|
dp[i] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ans := dp[0]
|
||||||
|
for i := 1; i < len(nums); i++ {
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if nums[i] > nums[j] {
|
||||||
|
dp[i] = max(dp[i], dp[j] + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dp[i] > ans {
|
||||||
|
ans = dp[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(x, y int) int {
|
||||||
|
if x > y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Javascript
|
Javascript
|
||||||
```javascript
|
```javascript
|
||||||
const lengthOfLIS = (nums) => {
|
const lengthOfLIS = (nums) => {
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,29 @@ class Solution {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
//另一种解题思路
|
||||||
|
class Solution {
|
||||||
|
public int maxProfit(int[] prices) {
|
||||||
|
int[][] dp = new int[prices.length + 1][2];
|
||||||
|
dp[1][0] = -prices[0];
|
||||||
|
|
||||||
|
for (int i = 2; i <= prices.length; i++) {
|
||||||
|
/*
|
||||||
|
dp[i][0] 第i天持有股票收益;
|
||||||
|
dp[i][1] 第i天不持有股票收益;
|
||||||
|
情况一:第i天是冷静期,不能以dp[i-1][1]购买股票,所以以dp[i - 2][1]买股票,没问题
|
||||||
|
情况二:第i天不是冷静期,理论上应该以dp[i-1][1]购买股票,但是第i天不是冷静期说明,第i-1天没有卖出股票,
|
||||||
|
则dp[i-1][1]=dp[i-2][1],所以可以用dp[i-2][1]买股票,没问题
|
||||||
|
*/
|
||||||
|
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 2][1] - prices[i - 1]);
|
||||||
|
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[prices.length][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
|
|
@ -284,6 +307,24 @@ const maxProfit = (prices) => {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 一维数组空间优化
|
||||||
|
const maxProfit = (prices) => {
|
||||||
|
const n = prices.length
|
||||||
|
const dp = new Array(4).fill(0)
|
||||||
|
dp[0] = -prices[0]
|
||||||
|
for (let i = 1; i < n; i ++) {
|
||||||
|
const temp = dp[0] // 缓存上一次的状态
|
||||||
|
const temp1 = dp[2]
|
||||||
|
dp[0] = Math.max(dp[0], Math.max(dp[3] - prices[i], dp[1] - prices[i])) // 持有状态
|
||||||
|
dp[1] = Math.max(dp[1], dp[3]) // 今天不操作且不持有股票
|
||||||
|
dp[2] = temp + prices[i] // 今天卖出股票
|
||||||
|
dp[3] = temp1 // 冷冻期
|
||||||
|
}
|
||||||
|
return Math.max(...dp)
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@ class Solution {
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def coinChange(self, coins: List[int], amount: int) -> int:
|
def coinChange(self, coins: List[int], amount: int) -> int:
|
||||||
'''版本一'''
|
'''版本一'''
|
||||||
|
|
|
||||||
|
|
@ -342,6 +342,64 @@ class Solution:
|
||||||
return path
|
return path
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### GO
|
||||||
|
```go
|
||||||
|
type pair struct {
|
||||||
|
target string
|
||||||
|
visited bool
|
||||||
|
}
|
||||||
|
type pairs []*pair
|
||||||
|
|
||||||
|
func (p pairs) Len() int {
|
||||||
|
return len(p)
|
||||||
|
}
|
||||||
|
func (p pairs) Swap(i, j int) {
|
||||||
|
p[i], p[j] = p[j], p[i]
|
||||||
|
}
|
||||||
|
func (p pairs) Less(i, j int) bool {
|
||||||
|
return p[i].target < p[j].target
|
||||||
|
}
|
||||||
|
|
||||||
|
func findItinerary(tickets [][]string) []string {
|
||||||
|
result := []string{}
|
||||||
|
// map[出发机场] pair{目的地,是否被访问过}
|
||||||
|
targets := make(map[string]pairs)
|
||||||
|
for _, ticket := range tickets {
|
||||||
|
if targets[ticket[0]] == nil {
|
||||||
|
targets[ticket[0]] = make(pairs, 0)
|
||||||
|
}
|
||||||
|
targets[ticket[0]] = append(targets[ticket[0]], &pair{target: ticket[1], visited: false})
|
||||||
|
}
|
||||||
|
for k, _ := range targets {
|
||||||
|
sort.Sort(targets[k])
|
||||||
|
}
|
||||||
|
result = append(result, "JFK")
|
||||||
|
var backtracking func() bool
|
||||||
|
backtracking = func() bool {
|
||||||
|
if len(tickets)+1 == len(result) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 取出起飞航班对应的目的地
|
||||||
|
for _, pair := range targets[result[len(result)-1]] {
|
||||||
|
if pair.visited == false {
|
||||||
|
result = append(result, pair.target)
|
||||||
|
pair.visited = true
|
||||||
|
if backtracking() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
result = result[:len(result)-1]
|
||||||
|
pair.visited = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
backtracking()
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### C语言
|
### C语言
|
||||||
|
|
||||||
```C
|
```C
|
||||||
|
|
@ -448,6 +506,50 @@ var findItinerary = function(tickets) {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function findItinerary(tickets: string[][]): string[] {
|
||||||
|
/**
|
||||||
|
TicketsMap 实例:
|
||||||
|
{ NRT: Map(1) { 'JFK' => 1 }, JFK: Map(2) { 'KUL' => 1, 'NRT' => 1 } }
|
||||||
|
这里选择Map数据结构的原因是:与Object类型的一个主要差异是,Map实例会维护键值对的插入顺序。
|
||||||
|
*/
|
||||||
|
type TicketsMap = {
|
||||||
|
[index: string]: Map<string, number>
|
||||||
|
};
|
||||||
|
tickets.sort((a, b) => {
|
||||||
|
return a[1] < b[1] ? -1 : 1;
|
||||||
|
});
|
||||||
|
const ticketMap: TicketsMap = {};
|
||||||
|
for (const [from, to] of tickets) {
|
||||||
|
if (ticketMap[from] === undefined) {
|
||||||
|
ticketMap[from] = new Map();
|
||||||
|
}
|
||||||
|
ticketMap[from].set(to, (ticketMap[from].get(to) || 0) + 1);
|
||||||
|
}
|
||||||
|
const resRoute = ['JFK'];
|
||||||
|
backTracking(tickets.length, ticketMap, resRoute);
|
||||||
|
return resRoute;
|
||||||
|
function backTracking(ticketNum: number, ticketMap: TicketsMap, route: string[]): boolean {
|
||||||
|
if (route.length === ticketNum + 1) return true;
|
||||||
|
const targetMap = ticketMap[route[route.length - 1]];
|
||||||
|
if (targetMap !== undefined) {
|
||||||
|
for (const [to, count] of targetMap.entries()) {
|
||||||
|
if (count > 0) {
|
||||||
|
route.push(to);
|
||||||
|
targetMap.set(to, count - 1);
|
||||||
|
if (backTracking(ticketNum, ticketMap, route) === true) return true;
|
||||||
|
targetMap.set(to, count);
|
||||||
|
route.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### Swift
|
### Swift
|
||||||
|
|
||||||
直接迭代tickets数组:
|
直接迭代tickets数组:
|
||||||
|
|
@ -568,5 +670,77 @@ for line in tickets {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Go
|
||||||
|
```Go
|
||||||
|
|
||||||
|
// 先排序,然后找到第一条路径即可返回
|
||||||
|
func findItinerary(tickets [][]string) []string {
|
||||||
|
var path []string // 用来保存搜索的路径
|
||||||
|
data := make(map[string]ticketSlice) // 用来保存tickets排序后的结果
|
||||||
|
|
||||||
|
var search func(airport string) bool
|
||||||
|
search = func(airport string) bool {
|
||||||
|
if len(path) == len(tickets) {
|
||||||
|
path = append(path, airport)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
to := data[airport]
|
||||||
|
for _, item := range to {
|
||||||
|
if item.Count == 0 {
|
||||||
|
// 已用完
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
path = append(path, airport)
|
||||||
|
item.Count--
|
||||||
|
if search(item.To) { return true }
|
||||||
|
item.Count++
|
||||||
|
path = path[:len(path) - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
// 感觉这段代码有点啰嗦,不知道能不能简化一下
|
||||||
|
tmp := make(map[string]map[string]int)
|
||||||
|
for _, ticket := range tickets {
|
||||||
|
if to, ok := tmp[ticket[0]]; ok {
|
||||||
|
if _, ok2 := to[ticket[1]]; ok2 {
|
||||||
|
to[ticket[1]]++
|
||||||
|
} else {
|
||||||
|
to[ticket[1]] = 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmp[ticket[0]] = map[string]int{
|
||||||
|
ticket[1]: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for from, to := range tmp {
|
||||||
|
var tmp ticketSlice
|
||||||
|
for to, num := range to {
|
||||||
|
tmp = append(tmp, &ticketStat{To: to, Count: num})
|
||||||
|
}
|
||||||
|
sort.Sort(tmp)
|
||||||
|
data[from] = tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
search("JFK")
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
type ticketStat struct {
|
||||||
|
To string
|
||||||
|
Count int
|
||||||
|
}
|
||||||
|
type ticketSlice []*ticketStat
|
||||||
|
|
||||||
|
func (p ticketSlice) Len() int { return len(p) }
|
||||||
|
func (p ticketSlice) Less(i, j int) bool { return strings.Compare(p[i].To, p[j].To) == -1 }
|
||||||
|
func (p ticketSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@ public:
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
### Java
|
||||||
```Java
|
```Java
|
||||||
class Solution {
|
class Solution {
|
||||||
// 1.递归去偷,超时
|
// 1.递归去偷,超时
|
||||||
|
|
@ -284,11 +284,11 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
### Python
|
||||||
|
|
||||||
> 暴力递归
|
> 暴力递归
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
|
|
||||||
# Definition for a binary tree node.
|
# Definition for a binary tree node.
|
||||||
# class TreeNode:
|
# class TreeNode:
|
||||||
|
|
@ -315,7 +315,7 @@ class Solution:
|
||||||
|
|
||||||
> 记忆化递归
|
> 记忆化递归
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
|
|
||||||
# Definition for a binary tree node.
|
# Definition for a binary tree node.
|
||||||
# class TreeNode:
|
# class TreeNode:
|
||||||
|
|
@ -345,7 +345,7 @@ class Solution:
|
||||||
```
|
```
|
||||||
|
|
||||||
> 动态规划
|
> 动态规划
|
||||||
```python3
|
```python
|
||||||
# Definition for a binary tree node.
|
# Definition for a binary tree node.
|
||||||
# class TreeNode:
|
# class TreeNode:
|
||||||
# def __init__(self, val=0, left=None, right=None):
|
# def __init__(self, val=0, left=None, right=None):
|
||||||
|
|
@ -367,7 +367,7 @@ class Solution:
|
||||||
return (val1, val2)
|
return (val1, val2)
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
### Go
|
||||||
|
|
||||||
动态规划
|
动态规划
|
||||||
|
|
||||||
|
|
@ -402,7 +402,7 @@ func robTree(cur *TreeNode) []int {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
JavaScript:
|
### JavaScript
|
||||||
|
|
||||||
> 动态规划
|
> 动态规划
|
||||||
|
|
||||||
|
|
@ -429,7 +429,7 @@ const rob = root => {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
### Go
|
||||||
```go
|
```go
|
||||||
// 打家劫舍Ⅲ 动态规划
|
// 打家劫舍Ⅲ 动态规划
|
||||||
// 时间复杂度O(n) 空间复杂度O(logn)
|
// 时间复杂度O(n) 空间复杂度O(logn)
|
||||||
|
|
|
||||||
|
|
@ -4,23 +4,22 @@
|
||||||
</a>
|
</a>
|
||||||
<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>
|
||||||
|
|
||||||
## 343. 整数拆分
|
# 343. 整数拆分
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/integer-break/)
|
[力扣题目链接](https://leetcode-cn.com/problems/integer-break/)
|
||||||
|
|
||||||
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
|
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
|
||||||
|
|
||||||
示例 1:
|
示例 1:
|
||||||
输入: 2
|
* 输入: 2
|
||||||
输出: 1
|
* 输出: 1
|
||||||
|
* 解释: 2 = 1 + 1, 1 × 1 = 1。
|
||||||
\解释: 2 = 1 + 1, 1 × 1 = 1。
|
|
||||||
|
|
||||||
示例 2:
|
示例 2:
|
||||||
输入: 10
|
* 输入: 10
|
||||||
输出: 36
|
* 输出: 36
|
||||||
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
|
* 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
|
||||||
说明: 你可以假设 n 不小于 2 且不大于 58。
|
* 说明: 你可以假设 n 不小于 2 且不大于 58。
|
||||||
|
|
||||||
## 思路
|
## 思路
|
||||||
|
|
||||||
|
|
@ -120,8 +119,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n^2)$
|
* 时间复杂度:O(n^2)
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
### 贪心
|
### 贪心
|
||||||
|
|
||||||
|
|
@ -149,8 +148,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n)$
|
* 时间复杂度:O(n)
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
|
|
@ -193,18 +192,21 @@ public:
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
### Java
|
||||||
```Java
|
```Java
|
||||||
class Solution {
|
class Solution {
|
||||||
public int integerBreak(int n) {
|
public int integerBreak(int n) {
|
||||||
//dp[i]为正整数i拆分结果的最大乘积
|
//dp[i] 为正整数 i 拆分后的结果的最大乘积
|
||||||
int[] dp = new int[n+1];
|
int[]dp=new int[n+1];
|
||||||
dp[2] = 1;
|
dp[2]=1;
|
||||||
for (int i = 3; i <= n; ++i) {
|
for(int i=3;i<=n;i++){
|
||||||
for (int j = 1; j < i - 1; ++j) {
|
for(int j=1;j<=i-j;j++){
|
||||||
//j*(i-j)代表把i拆分为j和i-j两个数相乘
|
// 这里的 j 其实最大值为 i-j,再大只不过是重复而已,
|
||||||
//j*dp[i-j]代表把i拆分成j和继续把(i-j)这个数拆分,取(i-j)拆分结果中的最大乘积与j相乘
|
//并且,在本题中,我们分析 dp[0], dp[1]都是无意义的,
|
||||||
dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
|
//j 最大到 i-j,就不会用到 dp[0]与dp[1]
|
||||||
|
dp[i]=Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
|
||||||
|
// j * (i - j) 是单纯的把整数 i 拆分为两个数 也就是 i,i-j ,再相乘
|
||||||
|
//而j * dp[i - j]是将 i 拆分成两个以及两个以上的个数,再相乘。
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dp[n];
|
return dp[n];
|
||||||
|
|
@ -212,7 +214,7 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
### Python
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def integerBreak(self, n: int) -> int:
|
def integerBreak(self, n: int) -> int:
|
||||||
|
|
@ -226,7 +228,8 @@ class Solution:
|
||||||
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
|
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
|
||||||
return dp[n]
|
return dp[n]
|
||||||
```
|
```
|
||||||
Go:
|
|
||||||
|
### Go
|
||||||
```golang
|
```golang
|
||||||
func integerBreak(n int) int {
|
func integerBreak(n int) int {
|
||||||
/**
|
/**
|
||||||
|
|
@ -256,7 +259,7 @@ func max(a,b int) int{
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Javascript:
|
### Javascript
|
||||||
```Javascript
|
```Javascript
|
||||||
var integerBreak = function(n) {
|
var integerBreak = function(n) {
|
||||||
let dp = new Array(n + 1).fill(0)
|
let dp = new Array(n + 1).fill(0)
|
||||||
|
|
@ -271,5 +274,40 @@ var integerBreak = function(n) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C:
|
||||||
|
```c
|
||||||
|
//初始化DP数组
|
||||||
|
int *initDP(int num) {
|
||||||
|
int* dp = (int*)malloc(sizeof(int) * (num + 1));
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < num + 1; ++i) {
|
||||||
|
dp[i] = 0;
|
||||||
|
}
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//取三数最大值
|
||||||
|
int max(int num1, int num2, int num3) {
|
||||||
|
int tempMax = num1 > num2 ? num1 : num2;
|
||||||
|
return tempMax > num3 ? tempMax : num3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int integerBreak(int n){
|
||||||
|
int *dp = initDP(n);
|
||||||
|
//初始化dp[2]为1
|
||||||
|
dp[2] = 1;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 3; i <= n; ++i) {
|
||||||
|
int j;
|
||||||
|
for(j = 1; j < i - 1; ++j) {
|
||||||
|
//取得上次循环:dp[i],原数相乘,或j*dp[]i-j] 三数中的最大值
|
||||||
|
dp[i] = max(dp[i], j * (i - j), j * dp[i - j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[n];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,27 @@ var reverseString = function(s) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
/**
|
||||||
|
Do not return anything, modify s in-place instead.
|
||||||
|
*/
|
||||||
|
function reverseString(s: string[]): void {
|
||||||
|
let length: number = s.length;
|
||||||
|
let left: number = 0,
|
||||||
|
right: number = length - 1;
|
||||||
|
let tempStr: string;
|
||||||
|
while (left < right) {
|
||||||
|
tempStr = s[left];
|
||||||
|
s[left] = s[right];
|
||||||
|
s[right] = tempStr;
|
||||||
|
left++;
|
||||||
|
right--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
Swift:
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
|
|
@ -232,6 +253,19 @@ void reverseString(char* s, int sSize){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C#:
|
||||||
|
```csharp
|
||||||
|
public class Solution
|
||||||
|
{
|
||||||
|
public void ReverseString(char[] s)
|
||||||
|
{
|
||||||
|
for (int i = 0, j = s.Length - 1; i < j; i++, j--)
|
||||||
|
{
|
||||||
|
(s[i], s[j]) = (s[j], s[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ class Solution {
|
||||||
|
|
||||||
Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
|
Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
|
||||||
// 根据map的value值正序排,相当于一个小顶堆
|
// 根据map的value值正序排,相当于一个小顶堆
|
||||||
PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o2.getValue() - o1.getValue());
|
PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue());
|
||||||
for (Map.Entry<Integer, Integer> entry : entries) {
|
for (Map.Entry<Integer, Integer> entry : entries) {
|
||||||
queue.offer(entry);
|
queue.offer(entry);
|
||||||
if (queue.size() > k) {
|
if (queue.size() > k) {
|
||||||
|
|
@ -358,6 +358,22 @@ PriorityQueue.prototype.compare = function(index1, index2) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function topKFrequent(nums: number[], k: number): number[] {
|
||||||
|
const countMap: Map<number, number> = new Map();
|
||||||
|
for (let num of nums) {
|
||||||
|
countMap.set(num, (countMap.get(num) || 0) + 1);
|
||||||
|
}
|
||||||
|
// tS没有最小堆的数据结构,所以直接对整个数组进行排序,取前k个元素
|
||||||
|
return [...countMap.entries()]
|
||||||
|
.sort((a, b) => b[1] - a[1])
|
||||||
|
.slice(0, k)
|
||||||
|
.map(i => i[0]);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
注意题目特意说明:**输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序**
|
注意题目特意说明:**输出结果中的每个元素一定是唯一的,也就是说输出的结果的去重的, 同时可以不考虑输出结果的顺序**
|
||||||
|
|
||||||
这道题用暴力的解法时间复杂度是$O(n^2)$,那来看看使用哈希法进一步优化。
|
这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。
|
||||||
|
|
||||||
那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)
|
那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)
|
||||||
|
|
||||||
|
|
@ -190,7 +190,33 @@ var intersection = function(nums1, nums2) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
版本一(正常解法):
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function intersection(nums1: number[], nums2: number[]): number[] {
|
||||||
|
let resSet: Set<number> = new Set(),
|
||||||
|
nums1Set: Set<number> = new Set(nums1);
|
||||||
|
for (let i of nums2) {
|
||||||
|
if (nums1Set.has(i)) {
|
||||||
|
resSet.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Array.from(resSet);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
版本二(秀操作):
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function intersection(nums1: number[], nums2: number[]): number[] {
|
||||||
|
return Array.from(new Set(nums1.filter(i => nums2.includes(i))))
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
Swift:
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func intersection(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
|
func intersection(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
|
||||||
var set1 = Set<Int>()
|
var set1 = Set<Int>()
|
||||||
|
|
@ -255,6 +281,38 @@ impl Solution {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C:
|
||||||
|
```C
|
||||||
|
int* intersection1(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){
|
||||||
|
|
||||||
|
int nums1Cnt[1000] = {0};
|
||||||
|
int lessSize = nums1Size < nums2Size ? nums1Size : nums2Size;
|
||||||
|
int * result = (int *) calloc(lessSize, sizeof(int));
|
||||||
|
int resultIndex = 0;
|
||||||
|
int* tempNums;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Calculate the number's counts for nums1 array */
|
||||||
|
for(i = 0; i < nums1Size; i ++) {
|
||||||
|
nums1Cnt[nums1[i]]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the value in nums2 is existing in nums1 count array */
|
||||||
|
for(i = 0; i < nums2Size; i ++) {
|
||||||
|
if(nums1Cnt[nums2[i]] > 0) {
|
||||||
|
result[resultIndex] = nums2[i];
|
||||||
|
resultIndex ++;
|
||||||
|
/* Clear this count to avoid duplicated value */
|
||||||
|
nums1Cnt[nums2[i]] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
* returnSize = resultIndex;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 相关题目
|
## 相关题目
|
||||||
|
|
||||||
* 350.两个数组的交集 II
|
* 350.两个数组的交集 II
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ public:
|
||||||
```Java
|
```Java
|
||||||
class Solution {
|
class Solution {
|
||||||
public int wiggleMaxLength(int[] nums) {
|
public int wiggleMaxLength(int[] nums) {
|
||||||
if (nums == null || nums.length <= 1) {
|
if (nums.length <= 1) {
|
||||||
return nums.length;
|
return nums.length;
|
||||||
}
|
}
|
||||||
//当前差值
|
//当前差值
|
||||||
|
|
@ -228,7 +228,7 @@ class Solution {
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def wiggleMaxLength(self, nums: List[int]) -> int:
|
def wiggleMaxLength(self, nums: List[int]) -> int:
|
||||||
preC,curC,res = 0,0,1 #题目里nums长度大于等于1,当长度为1时,其实到不了for循环里去,所以不用考虑nums长度
|
preC,curC,res = 0,0,1 #题目里nums长度大于等于1,当长度为1时,其实到不了for循环里去,所以不用考虑nums长度
|
||||||
|
|
@ -298,5 +298,84 @@ var wiggleMaxLength = function(nums) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### C
|
||||||
|
**贪心**
|
||||||
|
```c
|
||||||
|
int wiggleMaxLength(int* nums, int numsSize){
|
||||||
|
if(numsSize <= 1)
|
||||||
|
return numsSize;
|
||||||
|
|
||||||
|
int length = 1;
|
||||||
|
int preDiff , curDiff;
|
||||||
|
preDiff = curDiff = 0;
|
||||||
|
for(int i = 0; i < numsSize - 1; ++i) {
|
||||||
|
// 计算当前i元素与i+1元素差值
|
||||||
|
curDiff = nums[i+1] - nums[i];
|
||||||
|
|
||||||
|
// 若preDiff与curDiff符号不符,则子序列长度+1。更新preDiff的符号
|
||||||
|
// 若preDiff与curDiff符号一致,当前i元素为连续升序/连续降序子序列的中间元素。不被记录入长度
|
||||||
|
// 注:当preDiff为0时,curDiff为正或为负都属于符号不同
|
||||||
|
if((curDiff > 0 && preDiff <= 0) || (preDiff >= 0 && curDiff < 0)) {
|
||||||
|
preDiff = curDiff;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
**贪心**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function wiggleMaxLength(nums: number[]): number {
|
||||||
|
let length: number = nums.length;
|
||||||
|
if (length <= 1) return length;
|
||||||
|
let preDiff: number = 0;
|
||||||
|
let curDiff: number = 0;
|
||||||
|
let count: number = 1;
|
||||||
|
for (let i = 1; i < length; i++) {
|
||||||
|
curDiff = nums[i] - nums[i - 1];
|
||||||
|
if (
|
||||||
|
(preDiff <= 0 && curDiff > 0) ||
|
||||||
|
(preDiff >= 0 && curDiff < 0)
|
||||||
|
) {
|
||||||
|
preDiff = curDiff;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**动态规划**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function wiggleMaxLength(nums: number[]): number {
|
||||||
|
const length: number = nums.length;
|
||||||
|
if (length <= 1) return length;
|
||||||
|
const dp: number[][] = new Array(length).fill(0).map(_ => []);
|
||||||
|
dp[0][0] = 1; // 第一个数作为波峰
|
||||||
|
dp[0][1] = 1; // 第一个数作为波谷
|
||||||
|
for (let i = 1; i < length; i++) {
|
||||||
|
dp[i][0] = 1;
|
||||||
|
dp[i][1] = 1;
|
||||||
|
for (let j = 0; j < i; j++) {
|
||||||
|
if (nums[j] < nums[i]) dp[i][0] = Math.max(dp[i][0], dp[j][1] + 1);
|
||||||
|
}
|
||||||
|
for (let j = 0; j < i; j++) {
|
||||||
|
if (nums[j] > nums[i]) dp[i][1] = Math.max(dp[i][1], dp[j][0] + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.max(dp[length - 1][0], dp[length - 1][1]);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ public:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
C++测试用例有超过两个树相加超过int的数据,所以需要在if里加上dp[i] < INT_MAX - dp[i - num]。
|
C++测试用例有两个数相加超过int的数据,所以需要在if里加上dp[i] < INT_MAX - dp[i - num]。
|
||||||
|
|
||||||
但java就不用考虑这个限制,java里的int也是四个字节吧,也有可能leetcode后台对不同语言的测试数据不一样。
|
但java就不用考虑这个限制,java里的int也是四个字节吧,也有可能leetcode后台对不同语言的测试数据不一样。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,10 @@ class Solution {
|
||||||
public:
|
public:
|
||||||
bool canConstruct(string ransomNote, string magazine) {
|
bool canConstruct(string ransomNote, string magazine) {
|
||||||
int record[26] = {0};
|
int record[26] = {0};
|
||||||
|
//add
|
||||||
|
if (ransomNote.size() > magazine.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
for (int i = 0; i < magazine.length(); i++) {
|
for (int i = 0; i < magazine.length(); i++) {
|
||||||
// 通过recode数据记录 magazine里各个字符出现次数
|
// 通过recode数据记录 magazine里各个字符出现次数
|
||||||
record[magazine[i]-'a'] ++;
|
record[magazine[i]-'a'] ++;
|
||||||
|
|
@ -209,7 +213,7 @@ class Solution(object):
|
||||||
|
|
||||||
Python写法四:
|
Python写法四:
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
|
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
|
||||||
c1 = collections.Counter(ransomNote)
|
c1 = collections.Counter(ransomNote)
|
||||||
|
|
@ -264,6 +268,27 @@ var canConstruct = function(ransomNote, magazine) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TypeScript:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function canConstruct(ransomNote: string, magazine: string): boolean {
|
||||||
|
let helperArr: number[] = new Array(26).fill(0);
|
||||||
|
let base: number = 'a'.charCodeAt(0);
|
||||||
|
let index: number;
|
||||||
|
for (let i = 0, length = magazine.length; i < length; i++) {
|
||||||
|
helperArr[magazine[i].charCodeAt(0) - base]++;
|
||||||
|
}
|
||||||
|
for (let i = 0, length = ransomNote.length; i < length; i++) {
|
||||||
|
index = ransomNote[i].charCodeAt(0) - base;
|
||||||
|
helperArr[index]--;
|
||||||
|
if (helperArr[index] < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
PHP:
|
PHP:
|
||||||
```php
|
```php
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ if (s[i - 1] != t[j - 1]),此时相当于t要删除元素,t如果把当前
|
||||||
|
|
||||||
如果要是定义的dp[i][j]是以下标i为结尾的字符串s和以下标j为结尾的字符串t,初始化就比较麻烦了。
|
如果要是定义的dp[i][j]是以下标i为结尾的字符串s和以下标j为结尾的字符串t,初始化就比较麻烦了。
|
||||||
|
|
||||||
这里dp[i][0]和dp[0][j]是没有含义的,仅仅是为了给递推公式做前期铺垫,所以初始化为0。
|
dp[i][0] 表示以下标i-1为结尾的字符串,与空字符串的相同子序列长度,所以为0. dp[0][j]同理。
|
||||||
|
|
||||||
**其实这里只初始化dp[i][0]就够了,但一起初始化也方便,所以就一起操作了**,代码如下:
|
**其实这里只初始化dp[i][0]就够了,但一起初始化也方便,所以就一起操作了**,代码如下:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
**首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。**
|
**首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。**
|
||||||
|
|
||||||
因为题目中其实没有说清楚左叶子究竟是什么节点,那么我来给出左叶子的明确定义:**如果左节点不为空,且左节点没有左右孩子,那么这个节点就是左叶子**
|
因为题目中其实没有说清楚左叶子究竟是什么节点,那么我来给出左叶子的明确定义:**如果左节点不为空,且左节点没有左右孩子,那么这个节点的左节点就是左叶子**
|
||||||
|
|
||||||
大家思考一下如下图中二叉树,左叶子之和究竟是多少?
|
大家思考一下如下图中二叉树,左叶子之和究竟是多少?
|
||||||
|
|
||||||
|
|
@ -229,7 +229,7 @@ class Solution {
|
||||||
## Python
|
## Python
|
||||||
|
|
||||||
**递归后序遍历**
|
**递归后序遍历**
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def sumOfLeftLeaves(self, root: TreeNode) -> int:
|
def sumOfLeftLeaves(self, root: TreeNode) -> int:
|
||||||
if not root:
|
if not root:
|
||||||
|
|
@ -246,7 +246,7 @@ class Solution:
|
||||||
```
|
```
|
||||||
|
|
||||||
**迭代**
|
**迭代**
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def sumOfLeftLeaves(self, root: TreeNode) -> int:
|
def sumOfLeftLeaves(self, root: TreeNode) -> int:
|
||||||
"""
|
"""
|
||||||
|
|
@ -372,8 +372,149 @@ var sumOfLeftLeaves = function(root) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
> 递归法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function sumOfLeftLeaves(root: TreeNode | null): number {
|
||||||
|
if (root === null) return 0;
|
||||||
|
let midVal: number = 0;
|
||||||
|
if (
|
||||||
|
root.left !== null &&
|
||||||
|
root.left.left === null &&
|
||||||
|
root.left.right === null
|
||||||
|
) {
|
||||||
|
midVal = root.left.val;
|
||||||
|
}
|
||||||
|
let leftVal: number = sumOfLeftLeaves(root.left);
|
||||||
|
let rightVal: number = sumOfLeftLeaves(root.right);
|
||||||
|
return midVal + leftVal + rightVal;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 迭代法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function sumOfLeftLeaves(root: TreeNode | null): number {
|
||||||
|
let helperStack: TreeNode[] = [];
|
||||||
|
let tempNode: TreeNode;
|
||||||
|
let sum: number = 0;
|
||||||
|
if (root !== null) helperStack.push(root);
|
||||||
|
while (helperStack.length > 0) {
|
||||||
|
tempNode = helperStack.pop()!;
|
||||||
|
if (
|
||||||
|
tempNode.left !== null &&
|
||||||
|
tempNode.left.left === null &&
|
||||||
|
tempNode.left.right === null
|
||||||
|
) {
|
||||||
|
sum += tempNode.left.val;
|
||||||
|
}
|
||||||
|
if (tempNode.right !== null) helperStack.push(tempNode.right);
|
||||||
|
if (tempNode.left !== null) helperStack.push(tempNode.left);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Swift
|
||||||
|
|
||||||
|
**递归法**
|
||||||
|
```swift
|
||||||
|
func sumOfLeftLeaves(_ root: TreeNode?) -> Int {
|
||||||
|
guard let root = root else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
let leftValue = sumOfLeftLeaves(root.left)
|
||||||
|
let rightValue = sumOfLeftLeaves(root.right)
|
||||||
|
|
||||||
|
var midValue: Int = 0
|
||||||
|
if root.left != nil && root.left?.left == nil && root.left?.right == nil {
|
||||||
|
midValue = root.left!.val
|
||||||
|
}
|
||||||
|
|
||||||
|
let sum = midValue + leftValue + rightValue
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**迭代法**
|
||||||
|
```swift
|
||||||
|
func sumOfLeftLeaves(_ root: TreeNode?) -> Int {
|
||||||
|
guard let root = root else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var stack = Array<TreeNode>()
|
||||||
|
stack.append(root)
|
||||||
|
var sum = 0
|
||||||
|
|
||||||
|
while !stack.isEmpty {
|
||||||
|
let lastNode = stack.removeLast()
|
||||||
|
|
||||||
|
if lastNode.left != nil && lastNode.left?.left == nil && lastNode.left?.right == nil {
|
||||||
|
sum += lastNode.left!.val
|
||||||
|
}
|
||||||
|
if let right = lastNode.right {
|
||||||
|
stack.append(right)
|
||||||
|
}
|
||||||
|
if let left = lastNode.left {
|
||||||
|
stack.append(left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## C
|
||||||
|
递归法:
|
||||||
|
```c
|
||||||
|
int sumOfLeftLeaves(struct TreeNode* root){
|
||||||
|
// 递归结束条件:若当前结点为空,返回0
|
||||||
|
if(!root)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// 递归取左子树的左结点和和右子树的左结点和
|
||||||
|
int leftValue = sumOfLeftLeaves(root->left);
|
||||||
|
int rightValue = sumOfLeftLeaves(root->right);
|
||||||
|
|
||||||
|
// 若当前结点的左结点存在,且其为叶子结点。取它的值
|
||||||
|
int midValue = 0;
|
||||||
|
if(root->left && (!root->left->left && !root->left->right))
|
||||||
|
midValue = root->left->val;
|
||||||
|
|
||||||
|
return leftValue + rightValue + midValue;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
迭代法:
|
||||||
|
```c
|
||||||
|
int sumOfLeftLeaves(struct TreeNode* root){
|
||||||
|
struct TreeNode* stack[1000];
|
||||||
|
int stackTop = 0;
|
||||||
|
|
||||||
|
// 若传入root结点不为空,将其入栈
|
||||||
|
if(root)
|
||||||
|
stack[stackTop++] = root;
|
||||||
|
|
||||||
|
int sum = 0;
|
||||||
|
//若栈不为空,进行循环
|
||||||
|
while(stackTop) {
|
||||||
|
// 出栈栈顶元素
|
||||||
|
struct TreeNode *topNode = stack[--stackTop];
|
||||||
|
// 若栈顶元素的左孩子为左叶子结点,将其值加入sum中
|
||||||
|
if(topNode->left && (!topNode->left->left && !topNode->left->right))
|
||||||
|
sum += topNode->left->val;
|
||||||
|
|
||||||
|
// 若当前栈顶结点有左右孩子。将他们加入栈中进行遍历
|
||||||
|
if(topNode->right)
|
||||||
|
stack[stackTop++] = topNode->right;
|
||||||
|
if(topNode->left)
|
||||||
|
stack[stackTop++] = topNode->left;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
||||||
|
|
@ -116,12 +116,12 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
* 时间复杂度:$O(n\log n + n^2)$
|
* 时间复杂度:O(nlog n + n^2)
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
但使用vector是非常费时的,C++中vector(可以理解是一个动态数组,底层是普通数组实现的)如果插入元素大于预先普通数组大小,vector底部会有一个扩容的操作,即申请两倍于原先普通数组的大小,然后把数据拷贝到另一个更大的数组上。
|
但使用vector是非常费时的,C++中vector(可以理解是一个动态数组,底层是普通数组实现的)如果插入元素大于预先普通数组大小,vector底部会有一个扩容的操作,即申请两倍于原先普通数组的大小,然后把数据拷贝到另一个更大的数组上。
|
||||||
|
|
||||||
所以使用vector(动态数组)来insert,是费时的,插入再拷贝的话,单纯一个插入的操作就是$O(n^2)$了,甚至可能拷贝好几次,就不止$O(n^2)$了。
|
所以使用vector(动态数组)来insert,是费时的,插入再拷贝的话,单纯一个插入的操作就是O(n^2)了,甚至可能拷贝好几次,就不止O(n^2)了。
|
||||||
|
|
||||||
改成链表之后,C++代码如下:
|
改成链表之后,C++代码如下:
|
||||||
|
|
||||||
|
|
@ -150,8 +150,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n\log n + n^2)$
|
* 时间复杂度:O(nlog n + n^2)
|
||||||
* 空间复杂度:$O(n)$
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
大家可以把两个版本的代码提交一下试试,就可以发现其差别了!
|
大家可以把两个版本的代码提交一下试试,就可以发现其差别了!
|
||||||
|
|
||||||
|
|
@ -291,5 +291,72 @@ var reconstructQueue = function(people) {
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### C
|
||||||
|
```c
|
||||||
|
int cmp(const void *p1, const void *p2) {
|
||||||
|
int *pp1 = *(int**)p1;
|
||||||
|
int *pp2 = *(int**)p2;
|
||||||
|
// 若身高相同,则按照k从小到大排列
|
||||||
|
// 若身高不同,按身高从大到小排列
|
||||||
|
return pp1[0] == pp2[0] ? pp1[1] - pp2[1] : pp2[0] - pp1[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将start与end中间的元素都后移一位
|
||||||
|
// start为将要新插入元素的位置
|
||||||
|
void moveBack(int **people, int peopleSize, int start, int end) {
|
||||||
|
int i;
|
||||||
|
for(i = end; i > start; i--) {
|
||||||
|
people[i] = people[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int** reconstructQueue(int** people, int peopleSize, int* peopleColSize, int* returnSize, int** returnColumnSizes){
|
||||||
|
int i;
|
||||||
|
// 将people按身高从大到小排列(若身高相同,按k从小到大排列)
|
||||||
|
qsort(people, peopleSize, sizeof(int*), cmp);
|
||||||
|
|
||||||
|
for(i = 0; i < peopleSize; ++i) {
|
||||||
|
// people[i]要插入的位置
|
||||||
|
int position = people[i][1];
|
||||||
|
int *temp = people[i];
|
||||||
|
// 将position到i中间的元素后移一位
|
||||||
|
// 注:因为已经排好序,position不会比i大。(举例:排序后people最后一位元素最小,其可能的k最大值为peopleSize-2,小于此时的i)
|
||||||
|
moveBack(people, peopleSize, position, i);
|
||||||
|
// 将temp放置到position处
|
||||||
|
people[position] = temp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 设置返回二维数组的大小以及里面每个一维数组的长度
|
||||||
|
*returnSize = peopleSize;
|
||||||
|
*returnColumnSizes = (int*)malloc(sizeof(int) * peopleSize);
|
||||||
|
for(i = 0; i < peopleSize; ++i) {
|
||||||
|
(*returnColumnSizes)[i] = 2;
|
||||||
|
}
|
||||||
|
return people;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function reconstructQueue(people: number[][]): number[][] {
|
||||||
|
people.sort((a, b) => {
|
||||||
|
if (a[0] === b[0]) return a[1] - b[1];
|
||||||
|
return b[0] - a[0];
|
||||||
|
});
|
||||||
|
const resArr: number[][] = [];
|
||||||
|
for (let i = 0, length = people.length; i < length; i++) {
|
||||||
|
resArr.splice(people[i][1], 0, people[i]);
|
||||||
|
}
|
||||||
|
return resArr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
|
|
||||||
## 01背包问题
|
## 01背包问题
|
||||||
|
|
||||||
背包问题,大家都知道,有N件物品和一个最多能被重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
|
背包问题,大家都知道,有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
|
||||||
|
|
||||||
**背包问题有多种背包方式,常见的有:01背包、完全背包、多重背包、分组背包和混合背包等等。**
|
**背包问题有多种背包方式,常见的有:01背包、完全背包、多重背包、分组背包和混合背包等等。**
|
||||||
|
|
||||||
|
|
@ -127,9 +127,9 @@ for(int i = 0; i < nums.size(); i++) {
|
||||||
|
|
||||||
5. 举例推导dp数组
|
5. 举例推导dp数组
|
||||||
|
|
||||||
dp[i]的数值一定是小于等于i的。
|
dp[j]的数值一定是小于等于j的。
|
||||||
|
|
||||||
**如果dp[i] == i 说明,集合中的子集总和正好可以凑成总和i,理解这一点很重要。**
|
**如果dp[j] == j 说明,集合中的子集总和正好可以凑成总和j,理解这一点很重要。**
|
||||||
|
|
||||||
用例1,输入[1,5,11,5] 为例,如图:
|
用例1,输入[1,5,11,5] 为例,如图:
|
||||||
|
|
||||||
|
|
@ -168,8 +168,8 @@ public:
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
* 时间复杂度:$O(n^2)$
|
* 时间复杂度:O(n^2)
|
||||||
* 空间复杂度:$O(n)$,虽然dp数组大小为一个常数,但是大常数
|
* 空间复杂度:O(n),虽然dp数组大小为一个常数,但是大常数
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
|
|
@ -180,8 +180,6 @@ public:
|
||||||
看代码的话,就可以发现,基本就是按照01背包的写法来的。
|
看代码的话,就可以发现,基本就是按照01背包的写法来的。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -210,18 +208,126 @@ class Solution {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class Solution {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int num[] = {1,5,11,5};
|
||||||
|
canPartition(num);
|
||||||
|
|
||||||
|
}
|
||||||
|
public static boolean canPartition(int[] nums) {
|
||||||
|
int len = nums.length;
|
||||||
|
// 题目已经说非空数组,可以不做非空判断
|
||||||
|
int sum = 0;
|
||||||
|
for (int num : nums) {
|
||||||
|
sum += num;
|
||||||
|
}
|
||||||
|
// 特判:如果是奇数,就不符合要求
|
||||||
|
if ((sum %2 ) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int target = sum / 2; //目标背包容量
|
||||||
|
// 创建二维状态数组,行:物品索引,列:容量(包括 0)
|
||||||
|
/*
|
||||||
|
dp[i][j]表示从数组的 [0, i] 这个子区间内挑选一些正整数
|
||||||
|
每个数只能用一次,使得这些数的和恰好等于 j。
|
||||||
|
*/
|
||||||
|
boolean[][] dp = new boolean[len][target + 1];
|
||||||
|
|
||||||
|
// 先填表格第 0 行,第 1 个数只能让容积为它自己的背包恰好装满 (这里的dp[][]数组的含义就是“恰好”,所以就算容积比它大的也不要)
|
||||||
|
if (nums[0] <= target) {
|
||||||
|
dp[0][nums[0]] = true;
|
||||||
|
}
|
||||||
|
// 再填表格后面几行
|
||||||
|
//外层遍历物品
|
||||||
|
for (int i = 1; i < len; i++) {
|
||||||
|
//内层遍历背包
|
||||||
|
for (int j = 0; j <= target; j++) {
|
||||||
|
// 直接从上一行先把结果抄下来,然后再修正
|
||||||
|
dp[i][j] = dp[i - 1][j];
|
||||||
|
|
||||||
|
//如果某个物品单独的重量恰好就等于背包的重量,那么也是满足dp数组的定义的
|
||||||
|
if (nums[i] == j) {
|
||||||
|
dp[i][j] = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//如果某个物品的重量小于j,那就可以看该物品是否放入背包
|
||||||
|
//dp[i - 1][j]表示该物品不放入背包,如果在 [0, i - 1] 这个子区间内已经有一部分元素,使得它们的和为 j ,那么 dp[i][j] = true;
|
||||||
|
//dp[i - 1][j - nums[i]]表示该物品放入背包。如果在 [0, i - 1] 这个子区间内就得找到一部分元素,使得它们的和为 j - nums[i]。
|
||||||
|
if (nums[i] < j) {
|
||||||
|
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
for (int j = 0; j <= target; j++) {
|
||||||
|
System.out.print(dp[i][j]+" ");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
return dp[len - 1][target];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//dp数组的打印结果
|
||||||
|
false true false false false false false false false false false false
|
||||||
|
false true false false false true true false false false false false
|
||||||
|
false true false false false true true false false false false true
|
||||||
|
false true false false false true true false false false true true
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
二维数组版本(易于理解):
|
||||||
|
```Java
|
||||||
|
class Solution {
|
||||||
|
public boolean canPartition(int[] nums) {
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
sum += nums[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sum % 2 == 1)
|
||||||
|
return false;
|
||||||
|
int target = sum / 2;
|
||||||
|
|
||||||
|
//dp[i][j]代表可装物品为0-i,背包容量为j的情况下,背包内容量的最大价值
|
||||||
|
int[][] dp = new int[nums.length][target + 1];
|
||||||
|
|
||||||
|
//初始化,dp[0][j]的最大价值nums[0](if j > weight[i])
|
||||||
|
//dp[i][0]均为0,不用初始化
|
||||||
|
for (int j = nums[0]; j <= target; j++) {
|
||||||
|
dp[0][j] = nums[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
//遍历物品,遍历背包
|
||||||
|
//递推公式:
|
||||||
|
for (int i = 1; i < nums.length; i++) {
|
||||||
|
for (int j = 0; j <= target; j++) {
|
||||||
|
//背包容量可以容纳nums[i]
|
||||||
|
if (j >= nums[i]) {
|
||||||
|
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
|
||||||
|
} else {
|
||||||
|
dp[i][j] = dp[i - 1][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[nums.length - 1][target] == target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
Python:
|
Python:
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def canPartition(self, nums: List[int]) -> bool:
|
def canPartition(self, nums: List[int]) -> bool:
|
||||||
taraget = sum(nums)
|
target = sum(nums)
|
||||||
if taraget % 2 == 1: return False
|
if target % 2 == 1: return False
|
||||||
taraget //= 2
|
target //= 2
|
||||||
dp = [0] * 10001
|
dp = [0] * 10001
|
||||||
for i in range(len(nums)):
|
for i in range(len(nums)):
|
||||||
for j in range(taraget, nums[i] - 1, -1):
|
for j in range(target, nums[i] - 1, -1):
|
||||||
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
|
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
|
||||||
return taraget == dp[taraget]
|
return target == dp[target]
|
||||||
```
|
```
|
||||||
Go:
|
Go:
|
||||||
```go
|
```go
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
* 时间复杂度:$O(n\log n)$ ,有一个快排
|
* 时间复杂度:O(nlog n) ,有一个快排
|
||||||
* 空间复杂度:$O(1)$
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
大家此时会发现如此复杂的一个问题,代码实现却这么简单!
|
大家此时会发现如此复杂的一个问题,代码实现却这么简单!
|
||||||
|
|
||||||
|
|
@ -183,28 +183,23 @@ public:
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
public int eraseOverlapIntervals(int[][] intervals) {
|
public int eraseOverlapIntervals(int[][] intervals) {
|
||||||
if (intervals.length < 2) return 0;
|
Arrays.sort(intervals, (a, b) -> {
|
||||||
|
// 按照区间右边界升序排序
|
||||||
Arrays.sort(intervals, new Comparator<int[]>() {
|
return a[1] - b[1];
|
||||||
@Override
|
|
||||||
public int compare(int[] o1, int[] o2) {
|
|
||||||
if (o1[1] != o2[1]) {
|
|
||||||
return Integer.compare(o1[1],o2[1]);
|
|
||||||
} else {
|
|
||||||
return Integer.compare(o1[0],o2[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
int count = 1;
|
int count = 0;
|
||||||
int edge = intervals[0][1];
|
int edge = Integer.MIN_VALUE;
|
||||||
for (int i = 1; i < intervals.length; i++) {
|
for (int i = 0; i < intervals.length; i++) {
|
||||||
if (edge <= intervals[i][0]){
|
// 若上一个区间的右边界小于当前区间的左边界,说明无交集
|
||||||
count ++; //non overlap + 1
|
if (edge <= intervals[i][0]) {
|
||||||
edge = intervals[i][1];
|
edge = intervals[i][1];
|
||||||
|
} else {
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return intervals.length - count;
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -269,7 +264,7 @@ func min(a,b int)int{
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Javascript:
|
### Javascript:
|
||||||
- 按右边界排序
|
- 按右边界排序
|
||||||
|
|
@ -312,6 +307,55 @@ var eraseOverlapIntervals = function(intervals) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
> 按右边界排序,从左往右遍历
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function eraseOverlapIntervals(intervals: number[][]): number {
|
||||||
|
const length = intervals.length;
|
||||||
|
if (length === 0) return 0;
|
||||||
|
intervals.sort((a, b) => a[1] - b[1]);
|
||||||
|
let right: number = intervals[0][1];
|
||||||
|
let count: number = 1;
|
||||||
|
for (let i = 1; i < length; i++) {
|
||||||
|
if (intervals[i][0] >= right) {
|
||||||
|
count++;
|
||||||
|
right = intervals[i][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return length - count;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 按左边界排序,从左往右遍历
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function eraseOverlapIntervals(intervals: number[][]): number {
|
||||||
|
if (intervals.length === 0) return 0;
|
||||||
|
intervals.sort((a, b) => a[0] - b[0]);
|
||||||
|
let right: number = intervals[0][1];
|
||||||
|
let tempInterval: number[];
|
||||||
|
let resCount: number = 0;
|
||||||
|
for (let i = 1, length = intervals.length; i < length; i++) {
|
||||||
|
tempInterval = intervals[i];
|
||||||
|
if (tempInterval[0] >= right) {
|
||||||
|
// 未重叠
|
||||||
|
right = tempInterval[1];
|
||||||
|
} else {
|
||||||
|
// 有重叠,移除当前interval和前一个interval中右边界更大的那个
|
||||||
|
right = Math.min(right, tempInterval[1]);
|
||||||
|
resCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resCount;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ if (root == nullptr) return root;
|
||||||
|
|
||||||
* 确定单层递归的逻辑
|
* 确定单层递归的逻辑
|
||||||
|
|
||||||
这里就把平衡二叉树中删除节点遇到的情况都搞清楚。
|
这里就把二叉搜索树中删除节点遇到的情况都搞清楚。
|
||||||
|
|
||||||
有以下五种情况:
|
有以下五种情况:
|
||||||
|
|
||||||
|
|
@ -518,6 +518,70 @@ var deleteNode = function (root, key) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
> 递归法:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function deleteNode(root: TreeNode | null, key: number): TreeNode | null {
|
||||||
|
if (root === null) return null;
|
||||||
|
if (root.val === key) {
|
||||||
|
if (root.left === null && root.right === null) return null;
|
||||||
|
if (root.left === null) return root.right;
|
||||||
|
if (root.right === null) return root.left;
|
||||||
|
let curNode: TreeNode = root.right;
|
||||||
|
while (curNode.left !== null) {
|
||||||
|
curNode = curNode.left;
|
||||||
|
}
|
||||||
|
curNode.left = root.left;
|
||||||
|
return root.right;
|
||||||
|
}
|
||||||
|
if (root.val > key) root.left = deleteNode(root.left, key);
|
||||||
|
if (root.val < key) root.right = deleteNode(root.right, key);
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 迭代法:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function deleteNode(root: TreeNode | null, key: number): TreeNode | null {
|
||||||
|
function removeTargetNode(root: TreeNode): TreeNode | null {
|
||||||
|
if (root.left === null && root.right === null) return null;
|
||||||
|
if (root.right === null) return root.left;
|
||||||
|
if (root.left === null) return root.right;
|
||||||
|
let curNode: TreeNode | null = root.right;
|
||||||
|
while (curNode.left !== null) {
|
||||||
|
curNode = curNode.left;
|
||||||
|
}
|
||||||
|
curNode.left = root.left;
|
||||||
|
return root.right;
|
||||||
|
}
|
||||||
|
let preNode: TreeNode | null = null,
|
||||||
|
curNode: TreeNode | null = root;
|
||||||
|
while (curNode !== null) {
|
||||||
|
if (curNode.val === key) break;
|
||||||
|
preNode = curNode;
|
||||||
|
if (curNode.val > key) {
|
||||||
|
curNode = curNode.left;
|
||||||
|
} else {
|
||||||
|
curNode = curNode.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curNode === null) return root;
|
||||||
|
if (preNode === null) {
|
||||||
|
// 删除头节点
|
||||||
|
return removeTargetNode(curNode);
|
||||||
|
}
|
||||||
|
if (preNode.val > key) {
|
||||||
|
preNode.left = removeTargetNode(curNode);
|
||||||
|
} else {
|
||||||
|
preNode.right = removeTargetNode(curNode);
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ func min(a,b int) int{
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Javascript
|
### Javascript
|
||||||
```Javascript
|
```Javascript
|
||||||
|
|
@ -214,7 +214,31 @@ var findMinArrowShots = function(points) {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function findMinArrowShots(points: number[][]): number {
|
||||||
|
const length: number = points.length;
|
||||||
|
if (length === 0) return 0;
|
||||||
|
points.sort((a, b) => a[0] - b[0]);
|
||||||
|
let resCount: number = 1;
|
||||||
|
let right: number = points[0][1]; // 右边界
|
||||||
|
let tempPoint: number[];
|
||||||
|
for (let i = 1; i < length; i++) {
|
||||||
|
tempPoint = points[i];
|
||||||
|
if (tempPoint[0] > right) {
|
||||||
|
resCount++;
|
||||||
|
right = tempPoint[1];
|
||||||
|
} else {
|
||||||
|
right = Math.min(right, tempPoint[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resCount;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### C
|
### C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int cmp(const void *a,const void *b)
|
int cmp(const void *a,const void *b)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue