mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-11 21:10:58 +08:00
Merge branch 'master' into remote
This commit is contained in:
51
README.md
51
README.md
@ -88,6 +88,7 @@
|
|||||||
|
|
||||||
* 编程语言
|
* 编程语言
|
||||||
* [C++面试&C++学习指南知识点整理](https://github.com/youngyangyang04/TechCPP)
|
* [C++面试&C++学习指南知识点整理](https://github.com/youngyangyang04/TechCPP)
|
||||||
|
|
||||||
* 项目
|
* 项目
|
||||||
* [基于跳表的轻量级KV存储引擎](https://github.com/youngyangyang04/Skiplist-CPP)
|
* [基于跳表的轻量级KV存储引擎](https://github.com/youngyangyang04/Skiplist-CPP)
|
||||||
* [Nosql数据库注入攻击系统](https://github.com/youngyangyang04/NoSQLAttack)
|
* [Nosql数据库注入攻击系统](https://github.com/youngyangyang04/NoSQLAttack)
|
||||||
@ -96,6 +97,7 @@
|
|||||||
* [看了这么多代码,谈一谈代码风格!](./problems/前序/代码风格.md)
|
* [看了这么多代码,谈一谈代码风格!](./problems/前序/代码风格.md)
|
||||||
* [力扣上的代码想在本地编译运行?](./problems/前序/力扣上的代码想在本地编译运行?.md)
|
* [力扣上的代码想在本地编译运行?](./problems/前序/力扣上的代码想在本地编译运行?.md)
|
||||||
* [什么是核心代码模式,什么又是ACM模式?](./problems/前序/什么是核心代码模式,什么又是ACM模式?.md)
|
* [什么是核心代码模式,什么又是ACM模式?](./problems/前序/什么是核心代码模式,什么又是ACM模式?.md)
|
||||||
|
|
||||||
* 工具
|
* 工具
|
||||||
* [一站式vim配置](https://github.com/youngyangyang04/PowerVim)
|
* [一站式vim配置](https://github.com/youngyangyang04/PowerVim)
|
||||||
* [保姆级Git入门教程,万字详解](https://mp.weixin.qq.com/s/Q_O0ey4C9tryPZaZeJocbA)
|
* [保姆级Git入门教程,万字详解](https://mp.weixin.qq.com/s/Q_O0ey4C9tryPZaZeJocbA)
|
||||||
@ -120,30 +122,29 @@
|
|||||||
* [递归算法的时间与空间复杂度分析!](./problems/前序/递归算法的时间与空间复杂度分析.md)
|
* [递归算法的时间与空间复杂度分析!](./problems/前序/递归算法的时间与空间复杂度分析.md)
|
||||||
* [刷了这么多题,你了解自己代码的内存消耗么?](./problems/前序/刷了这么多题,你了解自己代码的内存消耗么?.md)
|
* [刷了这么多题,你了解自己代码的内存消耗么?](./problems/前序/刷了这么多题,你了解自己代码的内存消耗么?.md)
|
||||||
|
|
||||||
|
|
||||||
## 社群
|
|
||||||
|
|
||||||
* [准备秋招的录友们,组织在这里!](https://mp.weixin.qq.com/s/xX4LFwZQIG_XiQAxVBrfeA)
|
|
||||||
* [准备社招的录友们,组织在这里!](https://mp.weixin.qq.com/s/mbQ3s17ZJ4LXFRb-VD58Ww)
|
|
||||||
|
|
||||||
## 知识星球精选
|
## 知识星球精选
|
||||||
|
|
||||||
* [HR面注意事项](https://mp.weixin.qq.com/s/0mDyCyCBfa0DeGov3Pebnw)
|
* [秋招下半场依然没offer,怎么办?](./problems/知识星球精选/秋招下半场依然没offer.md)
|
||||||
* [刷题攻略要刷两遍!](https://mp.weixin.qq.com/s/e3_L7FZglY4UlTVvKolZyQ)
|
* [合适自己的就是最好的](./problems/知识星球精选/合适自己的就是最好的.md)
|
||||||
* [秋招进行中的迷茫与焦虑......](https://mp.weixin.qq.com/s/X15MUw4sfH_AQNHdAivEvg)
|
* [为什么都说客户端会消失](./problems/知识星球精选/客三消.md)
|
||||||
* [大厂新人培养体系应该是什么样的?](https://mp.weixin.qq.com/s/WBaPCosOljB5NEkFL2GhOQ)
|
* [博士转计算机如何找工作](./problems/知识星球精选/博士转行计算机.md)
|
||||||
* [你的简历里「专业技能」写的够专业么?](https://mp.weixin.qq.com/s/bp6y-e5FVN28H9qc8J9zrg)
|
* [不一样的七夕](./problems/知识星球精选/不一样的七夕.md)
|
||||||
* [Carl看了上百份简历,总结了这些!](https://mp.weixin.qq.com/s/sJa87MZD28piCOVMFkIbwQ)
|
* [HR面注意事项](./problems/知识星球精选/HR面注意事项.md)
|
||||||
* [备战2022届秋招](https://mp.weixin.qq.com/s/7q7W8Cb2-a5U5atZdOnOFA)
|
* [刷题攻略要刷两遍!](./problems/知识星球精选/刷题攻略要刷两遍.md)
|
||||||
* [技术不太好,如果选择方向](https://mp.weixin.qq.com/s/ZCzFiAHZHLqHPLJQXNm75g)
|
* [秋招进行中的迷茫与焦虑......](./problems/知识星球精选/秋招进行中的迷茫与焦虑.md)
|
||||||
* [刷题要不要使用库函数](https://mp.weixin.qq.com/s/6K3_OSaudnHGq2Ey8vqYfg)
|
* [大厂新人培养体系应该是什么样的?](./problems/知识星球精选/大厂新人培养体系.md)
|
||||||
* [关于实习的几点问题](https://mp.weixin.qq.com/s/xcxzi7c78kQGjvZ8hh7taA)
|
* [你的简历里「专业技能」写的够专业么?](./problems/知识星球精选/专业技能可以这么写.md)
|
||||||
* [面试中遇到了发散性问题,怎么帮?](https://mp.weixin.qq.com/s/SSonDxi2pjkSVwHNzZswng)
|
* [Carl看了上百份简历,总结了这些!](./problems/知识星球精选/写简历的一些问题.md)
|
||||||
* [英语到底重不重要!](https://mp.weixin.qq.com/s/1PRZiyF_-TVA-ipwDNjdKw)
|
* [备战2022届秋招](./problems/知识星球精选/备战2022届秋招.md)
|
||||||
* [计算机专业要不要读研!](https://mp.weixin.qq.com/s/c9v1L3IjqiXtkNH7sOMAdg)
|
* [技术不太好,如果选择方向](./problems/知识星球精选/技术不好如何选择技术方向.md)
|
||||||
* [关于提前批的一些建议](https://mp.weixin.qq.com/s/SNFiRDx8CKyjhTPlys6ywQ)
|
* [刷题要不要使用库函数](./problems/知识星球精选/刷力扣用不用库函数.md)
|
||||||
* [已经在实习的录友要如何准备秋招](https://mp.weixin.qq.com/s/ka07IPryFnfmIjByFFcXDg)
|
* [关于实习的几点问题](./problems/知识星球精选/关于实习大家的疑问.md)
|
||||||
* [华为提前批已经开始了](https://mp.weixin.qq.com/s/OC35QDG8pn5OwLpCxieStw)
|
* [面试中遇到了发散性问题,怎么办?](./problems/知识星球精选/面试中发散性问题.md)
|
||||||
|
* [英语到底重不重要!](./problems/知识星球精选/英语到底重不重要.md)
|
||||||
|
* [计算机专业要不要读研!](./problems/知识星球精选/要不要考研.md)
|
||||||
|
* [关于提前批的一些建议](./problems/知识星球精选/关于提前批的一些建议.md)
|
||||||
|
* [已经在实习的录友要如何准备秋招](./problems/知识星球精选/如何权衡实习与秋招复习.md)
|
||||||
|
* [华为提前批已经开始了](./problems/知识星球精选/提前批已经开始了.md)
|
||||||
|
|
||||||
## 杂谈
|
## 杂谈
|
||||||
|
|
||||||
@ -153,7 +154,6 @@
|
|||||||
* [大半年过去了......](https://mp.weixin.qq.com/s/lubfeistPxBLSQIe5XYg5g)
|
* [大半年过去了......](https://mp.weixin.qq.com/s/lubfeistPxBLSQIe5XYg5g)
|
||||||
* [一万录友在B站学算法!](https://mp.weixin.qq.com/s/Vzq4zkMZY7erKeu0fqGLgw)
|
* [一万录友在B站学算法!](https://mp.weixin.qq.com/s/Vzq4zkMZY7erKeu0fqGLgw)
|
||||||
|
|
||||||
|
|
||||||
## 数组
|
## 数组
|
||||||
|
|
||||||
1. [数组过于简单,但你该了解这些!](./problems/数组理论基础.md)
|
1. [数组过于简单,但你该了解这些!](./problems/数组理论基础.md)
|
||||||
@ -304,7 +304,8 @@
|
|||||||
|
|
||||||
题目分类大纲如下:
|
题目分类大纲如下:
|
||||||
|
|
||||||
<img src='https://img-blog.csdnimg.cn/20210220152245584.png' width=600 alt='贪心算法大纲'> </img></div>
|
|
||||||
|
<img src='https://code-thinking-1253855093.file.myqcloud.com/pics/20210917104315.png' width=600 alt='贪心算法大纲'> </img></div>
|
||||||
|
|
||||||
1. [关于贪心算法,你该了解这些!](./problems/贪心算法理论基础.md)
|
1. [关于贪心算法,你该了解这些!](./problems/贪心算法理论基础.md)
|
||||||
2. [贪心算法:分发饼干](./problems/0455.分发饼干.md)
|
2. [贪心算法:分发饼干](./problems/0455.分发饼干.md)
|
||||||
@ -457,6 +458,7 @@
|
|||||||
* [724.寻找数组的中心索引](./problems/0724.寻找数组的中心索引.md)
|
* [724.寻找数组的中心索引](./problems/0724.寻找数组的中心索引.md)
|
||||||
* [34.在排序数组中查找元素的第一个和最后一个位置](./problems/0034.在排序数组中查找元素的第一个和最后一个位置.md) (二分法)
|
* [34.在排序数组中查找元素的第一个和最后一个位置](./problems/0034.在排序数组中查找元素的第一个和最后一个位置.md) (二分法)
|
||||||
* [922.按奇偶排序数组II](./problems/0922.按奇偶排序数组II.md)
|
* [922.按奇偶排序数组II](./problems/0922.按奇偶排序数组II.md)
|
||||||
|
* [35.搜索插入位置](./problems/0035.搜索插入位置.md)
|
||||||
|
|
||||||
## 链表
|
## 链表
|
||||||
|
|
||||||
@ -485,6 +487,7 @@
|
|||||||
|
|
||||||
## 贪心
|
## 贪心
|
||||||
* [649.Dota2参议院](./problems/0649.Dota2参议院.md) 有难度
|
* [649.Dota2参议院](./problems/0649.Dota2参议院.md) 有难度
|
||||||
|
* [1221.分割平衡字符](./problems/1221.分割平衡字符串.md) 简单贪心
|
||||||
|
|
||||||
## 动态规划
|
## 动态规划
|
||||||
* [5.最长回文子串](./problems/0005.最长回文子串.md) 和[647.回文子串](https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw) 差不多是一样的
|
* [5.最长回文子串](./problems/0005.最长回文子串.md) 和[647.回文子串](https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw) 差不多是一样的
|
||||||
|
@ -253,4 +253,4 @@ class Solution {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -8,6 +7,7 @@
|
|||||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 5.最长回文子串
|
# 5.最长回文子串
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/longest-palindromic-substring/)
|
[力扣题目链接](https://leetcode-cn.com/problems/longest-palindromic-substring/)
|
||||||
@ -288,7 +288,34 @@ class Solution:
|
|||||||
return s[left:right + 1]
|
return s[left:right + 1]
|
||||||
|
|
||||||
```
|
```
|
||||||
|
> 双指针法:
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def longestPalindrome(self, s: str) -> str:
|
||||||
|
|
||||||
|
def find_point(i, j, s):
|
||||||
|
while i >= 0 and j < len(s) and s[i] == s[j]:
|
||||||
|
i -= 1
|
||||||
|
j += 1
|
||||||
|
return i + 1, j
|
||||||
|
|
||||||
|
def compare(start, end, left, right):
|
||||||
|
if right - left > end - start:
|
||||||
|
return left, right
|
||||||
|
else:
|
||||||
|
return start, end
|
||||||
|
|
||||||
|
start = 0
|
||||||
|
end = 0
|
||||||
|
for i in range(len(s)):
|
||||||
|
left, right = find_point(i, i, s)
|
||||||
|
start, end = compare(start, end, left, right)
|
||||||
|
|
||||||
|
left, right = find_point(i, i + 1, s)
|
||||||
|
start, end = compare(start, end, left, right)
|
||||||
|
return s[start:end]
|
||||||
|
|
||||||
|
```
|
||||||
## Go
|
## Go
|
||||||
|
|
||||||
```go
|
```go
|
||||||
@ -297,12 +324,123 @@ class Solution:
|
|||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
//动态规划解法
|
||||||
|
var longestPalindrome = function(s) {
|
||||||
|
const len = s.length;
|
||||||
|
// 布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false
|
||||||
|
let dp = new Array(len).fill(false).map(() => new Array(len).fill(false));
|
||||||
|
// left起始位置 maxlenth回文串长度
|
||||||
|
let left = 0, maxlenth = 0;
|
||||||
|
for(let i = len - 1; i >= 0; i--){
|
||||||
|
for(let j = i; j < len; j++){
|
||||||
|
// 情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串 j - i == 0
|
||||||
|
// 情况二:下标i 与 j相差为1,例如aa,也是文子串 j - i == 1
|
||||||
|
// 情况一和情况二 可以合并为 j - i <= 1
|
||||||
|
// 情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,我们看i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,这个区间是不是回文就看dp[i + 1][j - 1]===true
|
||||||
|
if(s[i] === s[j] && (j - i <= 1 || dp[i + 1][j - 1])){
|
||||||
|
dp[i][j] = true;
|
||||||
|
}
|
||||||
|
// 只要 dp[i][j] == true 成立,就表示子串 s[i..j] 是回文,此时记录回文长度和起始位置
|
||||||
|
if(dp[i][j] && j - i + 1 > maxlenth) {
|
||||||
|
maxlenth = j - i + 1; // 回文串长度
|
||||||
|
left = i; // 起始位置
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.substr(left, maxlenth); // 找到子串
|
||||||
|
};
|
||||||
|
|
||||||
|
//双指针
|
||||||
|
var longestPalindrome = function(s) {
|
||||||
|
let left = 0, right = 0, maxLength = 0;
|
||||||
|
const extend = (s, i, j, n) => {// s为字符串 i,j为双指针 n为字符串长度
|
||||||
|
while(i >= 0 && j < n && s[i] === s[j]){
|
||||||
|
if(j - i + 1 > maxLength){
|
||||||
|
left = i; // 更新开始位置
|
||||||
|
right = j; // 更新结尾位置
|
||||||
|
maxLength = j - i + 1; // 更新子串最大长度
|
||||||
|
}
|
||||||
|
// 指针移动
|
||||||
|
i--;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(let i = 0; i < s.length; i++){
|
||||||
|
extend(s, i, i, s.length); // 以i为中心
|
||||||
|
extend(s, i, i + 1, s.length); // 以i和i+1为中心
|
||||||
|
}
|
||||||
|
return s.substr(left, maxLength);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Manacher算法
|
||||||
|
var longestPalindrome = function(s) {
|
||||||
|
const len = s.length;
|
||||||
|
if(len < 2) return s;
|
||||||
|
let maxLength = 1, index = 0;
|
||||||
|
//Manacher算法,利用回文对称的性质,根据i在上一个回文中心的臂长里的位置去判断i的回文性
|
||||||
|
//需要知道上一个回文中心,以及其臂长
|
||||||
|
let center = 0;
|
||||||
|
//注意这里使用了maxRight的而不是真实的臂长length,因为之后需要判断i在臂长的什么位置
|
||||||
|
//如果这里臂长用了length,之后还要 计算i - center 去和 length比较,太繁琐
|
||||||
|
let maxRight = 0;
|
||||||
|
//考虑到回文串的长度是偶数的情况,所以这里预处理一下字符串,每个字符间插入特殊字符,把可能性都化为奇数
|
||||||
|
//这个处理把回文串长度的可能性都化为了奇数
|
||||||
|
//#c#b#b#a#
|
||||||
|
//#c#b#a#b#d#
|
||||||
|
let ss = "";
|
||||||
|
for(let i = 0; i < s.length; i++){
|
||||||
|
ss += "#"+s[i];
|
||||||
|
}
|
||||||
|
ss += "#";
|
||||||
|
//需要维护一个每个位置臂长的信息数组positionLength
|
||||||
|
const pl = new Array(ss.length).fill(0);
|
||||||
|
//这里需要注意参考的是i关于center对称的点i'的回文性
|
||||||
|
//i' = 2*center - i;
|
||||||
|
//所以列下情况:
|
||||||
|
//1.i>maxRight,找不到i',无法参考,自己算自己的
|
||||||
|
//2.i<=maxRight:
|
||||||
|
//2.1 i<maxRight-pl[i'],pl[i']的臂长没有超过center的臂长,根据对称性,pl[i] = pl[i']
|
||||||
|
//2.2 i=maxRight-pl[i'],pl[i']的臂长刚好等于center的臂长,根据对称性,pl[i] >= pl[i‘],大多少需要尝试扩散
|
||||||
|
//2.3 i>maxRight-pl[i'],pl[i']的臂长超过了center的臂长,根据对称性,i中心扩散到MaxRight处,
|
||||||
|
// s[2*i-maxRight] !== s[MaxRight]必不相等,所以pl[i] = maxRight-i;
|
||||||
|
//总结就是pl[i] = Math.min(maxRight-i,pl[i']);提示i<maxRight-pl[i'] 也可写成 pl[i']<maxRight-i
|
||||||
|
//0没有意义,从1开始计算
|
||||||
|
for(let i = 1; i < ss.length; i++){
|
||||||
|
if(i <= maxRight){//可以参考之前的
|
||||||
|
pl[i] = Math.min(maxRight - i, pl[2 * center - i]);
|
||||||
|
//尝试中心扩散
|
||||||
|
}
|
||||||
|
//注意到i<maxRight时都要尝试中心扩散,所以写else完全无意义,把中心扩散的代码写在下面
|
||||||
|
// else{//i不在之前回文中心的臂长范围里,之前的信息就完全无法参考,只能从i中心扩散把,然后去维护maxRight和center的定义
|
||||||
|
//尝试中心扩散
|
||||||
|
//这里不要动center和maxRight
|
||||||
|
// center = i;
|
||||||
|
// maxRight = pl[i] + i + 1;
|
||||||
|
let right = pl[i] + i + 1;
|
||||||
|
let left = i - pl[i] - 1;
|
||||||
|
while (left >= 0 && right<ss.length && ss[left] === ss[right]) {
|
||||||
|
right++;
|
||||||
|
left--;
|
||||||
|
pl[i]++;
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
if(pl[i] + i > maxRight){
|
||||||
|
center = i;
|
||||||
|
maxRight = pl[i] + i;
|
||||||
|
}
|
||||||
|
if (pl[i] * 2 + 1 > maxLength){
|
||||||
|
maxLength = pl[i]*2+1;
|
||||||
|
index = i - pl[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ss.substr(index, maxLength).replace(/#/g,"");
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -354,44 +354,6 @@ def is_valid(strs)
|
|||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
php:
|
|
||||||
|
|
||||||
```php
|
|
||||||
function threeSum(array $nums): array
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
$length = count($nums);
|
|
||||||
if ($length < 3) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
sort($nums);
|
|
||||||
for ($i = 0; $i < $length; $i++) {
|
|
||||||
// 如果大于0结束
|
|
||||||
if ($nums[$i] > 0) break;
|
|
||||||
// 去重
|
|
||||||
if ($i > 0 && $nums[$i] == $nums[$i - 1]) continue;
|
|
||||||
$left = $i + 1;
|
|
||||||
$right = $length - 1;
|
|
||||||
// 比较
|
|
||||||
while ($left < $right) {
|
|
||||||
$sum = $nums[$i] + $nums[$left] + $nums[$right];
|
|
||||||
if ($sum < 0) {
|
|
||||||
$left++;
|
|
||||||
} elseif ($sum > 0) {
|
|
||||||
$right--;
|
|
||||||
} else {
|
|
||||||
array_push($result, [$nums[$i], $nums[$left], $nums[$right]]);
|
|
||||||
while ($left < $right && $nums[$left] == $nums[$left + 1]) $left++;
|
|
||||||
while ($left < $right && $nums[$right - 1] == $nums[$right]) $right--;
|
|
||||||
$left++;
|
|
||||||
$right--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
PHP:
|
PHP:
|
||||||
```php
|
```php
|
||||||
@ -434,9 +396,49 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
```swift
|
||||||
|
// 双指针法
|
||||||
|
func threeSum(_ nums: [Int]) -> [[Int]] {
|
||||||
|
var res = [[Int]]()
|
||||||
|
var sorted = nums
|
||||||
|
sorted.sort()
|
||||||
|
for i in 0 ..< sorted.count {
|
||||||
|
if sorted[i] > 0 {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if i > 0 && sorted[i] == sorted[i - 1] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var left = i + 1
|
||||||
|
var right = sorted.count - 1
|
||||||
|
while left < right {
|
||||||
|
let sum = sorted[i] + sorted[left] + sorted[right]
|
||||||
|
if sum < 0 {
|
||||||
|
left += 1
|
||||||
|
} else if sum > 0 {
|
||||||
|
right -= 1
|
||||||
|
} else {
|
||||||
|
res.append([sorted[i], sorted[left], sorted[right]])
|
||||||
|
|
||||||
|
while left < right && sorted[left] == sorted[left + 1] {
|
||||||
|
left += 1
|
||||||
|
}
|
||||||
|
while left < right && sorted[right] == sorted[right - 1] {
|
||||||
|
right -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
left += 1
|
||||||
|
right -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
如果输入"233"呢,那么就三层for循环,如果"2333"呢,就四层for循环.......
|
如果输入"233"呢,那么就三层for循环,如果"2333"呢,就四层for循环.......
|
||||||
|
|
||||||
大家应该感觉出和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)遇到的一样的问题,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。
|
大家应该感觉出和[77.组合](https://programmercarl.com/0077.组合.html)遇到的一样的问题,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。
|
||||||
|
|
||||||
理解本题后,要解决如下三个问题:
|
理解本题后,要解决如下三个问题:
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ const string letterMap[10] = {
|
|||||||
|
|
||||||
再来看参数,参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index。
|
再来看参数,参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index。
|
||||||
|
|
||||||
注意这个index可不是 [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中的startIndex了。
|
注意这个index可不是 [77.组合](https://programmercarl.com/0077.组合.html)和[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)中的startIndex了。
|
||||||
|
|
||||||
这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
|
这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ if (index == digits.size()) {
|
|||||||
|
|
||||||
然后for循环来处理这个字符集,代码如下:
|
然后for循环来处理这个字符集,代码如下:
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
int digit = digits[index] - '0'; // 将index指向的数字转为int
|
int digit = digits[index] - '0'; // 将index指向的数字转为int
|
||||||
string letters = letterMap[digit]; // 取数字对应的字符集
|
string letters = letterMap[digit]; // 取数字对应的字符集
|
||||||
for (int i = 0; i < letters.size(); i++) {
|
for (int i = 0; i < letters.size(); i++) {
|
||||||
@ -137,7 +137,7 @@ for (int i = 0; i < letters.size(); i++) {
|
|||||||
关键地方都讲完了,按照[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中的回溯法模板,不难写出如下C++代码:
|
关键地方都讲完了,按照[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中的回溯法模板,不难写出如下C++代码:
|
||||||
|
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
// 版本一
|
// 版本一
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
@ -183,7 +183,7 @@ public:
|
|||||||
|
|
||||||
一些写法,是把回溯的过程放在递归函数里了,例如如下代码,我可以写成这样:(注意注释中不一样的地方)
|
一些写法,是把回溯的过程放在递归函数里了,例如如下代码,我可以写成这样:(注意注释中不一样的地方)
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
// 版本二
|
// 版本二
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
@ -236,10 +236,10 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
## Java
|
||||||
```Java
|
```Java
|
||||||
class Solution {
|
class Solution {
|
||||||
|
|
||||||
@ -281,69 +281,81 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
## Python
|
||||||
|
**回溯**
|
||||||
```Python
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
ans = []
|
def __init__(self):
|
||||||
s = ''
|
self.answers: List[str] = []
|
||||||
letterMap = {
|
self.answer: str = ''
|
||||||
'2': 'abc',
|
self.letter_map = {
|
||||||
'3': 'def',
|
'2': 'abc',
|
||||||
'4': 'ghi',
|
'3': 'def',
|
||||||
'5': 'jkl',
|
'4': 'ghi',
|
||||||
'6': 'mno',
|
'5': 'jkl',
|
||||||
'7': 'pqrs',
|
'6': 'mno',
|
||||||
'8': 'tuv',
|
'7': 'pqrs',
|
||||||
'9': 'wxyz'
|
'8': 'tuv',
|
||||||
}
|
'9': 'wxyz'
|
||||||
|
}
|
||||||
|
|
||||||
def letterCombinations(self, digits):
|
|
||||||
self.ans.clear()
|
|
||||||
if digits == '':
|
|
||||||
return self.ans
|
|
||||||
self.backtracking(digits, 0)
|
|
||||||
return self.ans
|
|
||||||
|
|
||||||
def backtracking(self, digits, index):
|
|
||||||
if index == len(digits):
|
|
||||||
self.ans.append(self.s)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
letters = self.letterMap[digits[index]] # 取出数字对应的字符集
|
|
||||||
for letter in letters:
|
|
||||||
self.s = self.s + letter # 处理
|
|
||||||
self.backtracking(digits, index + 1)
|
|
||||||
self.s = self.s[:-1] # 回溯
|
|
||||||
```
|
|
||||||
|
|
||||||
python3:
|
|
||||||
|
|
||||||
```py
|
|
||||||
class Solution:
|
|
||||||
def letterCombinations(self, digits: str) -> List[str]:
|
def letterCombinations(self, digits: str) -> List[str]:
|
||||||
self.s = ""
|
self.answers.clear()
|
||||||
res = []
|
if not digits: return []
|
||||||
letterMap = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
|
self.backtracking(digits, 0)
|
||||||
if len(digits) == 0: return res
|
return self.answers
|
||||||
def backtrack(digits,index):
|
|
||||||
if index == len(digits):
|
def backtracking(self, digits: str, index: int) -> None:
|
||||||
return res.append(self.s)
|
# 回溯函数没有返回值
|
||||||
digit = int(digits[index]) #将index指向的数字转为int
|
# Base Case
|
||||||
letters = letterMap[digit] #取数字对应的字符集
|
if index == len(digits): # 当遍历穷尽后的下一层时
|
||||||
for i in range(len(letters)):
|
self.answers.append(self.answer)
|
||||||
self.s += letters[i]
|
return
|
||||||
backtrack(digits,index + 1) #递归,注意index+1,一下层要处理下一个数字
|
# 单层递归逻辑
|
||||||
self.s = self.s[:-1] #回溯
|
letters: str = self.letter_map[digits[index]]
|
||||||
backtrack(digits,0)
|
for letter in letters:
|
||||||
return res
|
self.answer += letter # 处理
|
||||||
|
self.backtracking(digits, index + 1) # 递归至下一层
|
||||||
|
self.answer = self.answer[:-1] # 回溯
|
||||||
|
```
|
||||||
|
**回溯简化**
|
||||||
|
```python3
|
||||||
|
class Solution:
|
||||||
|
def __init__(self):
|
||||||
|
self.answers: List[str] = []
|
||||||
|
self.letter_map = {
|
||||||
|
'2': 'abc',
|
||||||
|
'3': 'def',
|
||||||
|
'4': 'ghi',
|
||||||
|
'5': 'jkl',
|
||||||
|
'6': 'mno',
|
||||||
|
'7': 'pqrs',
|
||||||
|
'8': 'tuv',
|
||||||
|
'9': 'wxyz'
|
||||||
|
}
|
||||||
|
|
||||||
|
def letterCombinations(self, digits: str) -> List[str]:
|
||||||
|
self.answers.clear()
|
||||||
|
if not digits: return []
|
||||||
|
self.backtracking(digits, 0, '')
|
||||||
|
return self.answers
|
||||||
|
|
||||||
|
def backtracking(self, digits: str, index: int, answer: str) -> None:
|
||||||
|
# 回溯函数没有返回值
|
||||||
|
# Base Case
|
||||||
|
if index == len(digits): # 当遍历穷尽后的下一层时
|
||||||
|
self.answers.append(answer)
|
||||||
|
return
|
||||||
|
# 单层递归逻辑
|
||||||
|
letters: str = self.letter_map[digits[index]]
|
||||||
|
for letter in letters:
|
||||||
|
self.backtracking(digits, index + 1, answer + letter) # 递归至下一层 + 回溯
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Go:
|
## Go
|
||||||
|
|
||||||
|
主要在于递归中传递下一个数字
|
||||||
> 主要在于递归中传递下一个数字
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func letterCombinations(digits string) []string {
|
func letterCombinations(digits string) []string {
|
||||||
@ -382,7 +394,7 @@ func recursion(tempString ,digits string, Index int,digitsMap [10]string, res *[
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
javaScript:
|
## javaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var letterCombinations = function(digits) {
|
var letterCombinations = function(digits) {
|
||||||
@ -476,4 +488,4 @@ char ** letterCombinations(char * digits, int* returnSize){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -90,7 +90,8 @@ public:
|
|||||||
int left = i + 1;
|
int left = i + 1;
|
||||||
int right = nums.size() - 1;
|
int right = nums.size() - 1;
|
||||||
while (right > left) {
|
while (right > left) {
|
||||||
if (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])) {
|
||||||
right--;
|
right--;
|
||||||
} else if (nums[k] + nums[i] + nums[left] + nums[right] < target) {
|
} else if (nums[k] + nums[i] + nums[left] + nums[right] < target) {
|
||||||
left++;
|
left++;
|
||||||
@ -110,8 +111,8 @@ public:
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -354,8 +355,56 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Swift:
|
||||||
|
```swift
|
||||||
|
func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] {
|
||||||
|
var res = [[Int]]()
|
||||||
|
var sorted = nums
|
||||||
|
sorted.sort()
|
||||||
|
for k in 0 ..< sorted.count {
|
||||||
|
// 这种剪枝不行,target可能是负数
|
||||||
|
// if sorted[k] > target {
|
||||||
|
// return res
|
||||||
|
// }
|
||||||
|
// 去重
|
||||||
|
if k > 0 && sorted[k] == sorted[k - 1] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let target2 = target - sorted[k]
|
||||||
|
for i in (k + 1) ..< sorted.count {
|
||||||
|
if i > (k + 1) && sorted[i] == sorted[i - 1] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var left = i + 1
|
||||||
|
var right = sorted.count - 1
|
||||||
|
while left < right {
|
||||||
|
let sum = sorted[i] + sorted[left] + sorted[right]
|
||||||
|
if sum < target2 {
|
||||||
|
left += 1
|
||||||
|
} else if sum > target2 {
|
||||||
|
right -= 1
|
||||||
|
} else {
|
||||||
|
res.append([sorted[k], sorted[i], sorted[left], sorted[right]])
|
||||||
|
while left < right && sorted[left] == sorted[left + 1] {
|
||||||
|
left += 1
|
||||||
|
}
|
||||||
|
while left < right && sorted[right] == sorted[right - 1] {
|
||||||
|
right -= 1
|
||||||
|
}
|
||||||
|
// 找到答案 双指针同时收缩
|
||||||
|
left += 1
|
||||||
|
right -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
* fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:
|
* fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:
|
||||||
<img src='https://code-thinking.cdn.bcebos.com/pics/19.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B91.png' width=600> </img></div>
|
<img src='https://code-thinking.cdn.bcebos.com/pics/19.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B91.png' width=600> </img></div>
|
||||||
|
|
||||||
* fast和slow同时移动,之道fast指向末尾,如题:
|
* fast和slow同时移动,直到fast指向末尾,如题:
|
||||||
<img src='https://code-thinking.cdn.bcebos.com/pics/19.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B92.png' width=600> </img></div>
|
<img src='https://code-thinking.cdn.bcebos.com/pics/19.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B92.png' width=600> </img></div>
|
||||||
|
|
||||||
* 删除slow指向的下一个节点,如图:
|
* 删除slow指向的下一个节点,如图:
|
||||||
@ -233,4 +233,4 @@ func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -290,4 +290,4 @@ var isValid = function(s) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -283,4 +283,4 @@ func swapPairs(_ head: ListNode?) -> ListNode? {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -185,7 +185,7 @@ func removeElement(nums []int, val int) int {
|
|||||||
```
|
```
|
||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
```
|
```javascript
|
||||||
//时间复杂度O(n)
|
//时间复杂度O(n)
|
||||||
//空间复杂度O(1)
|
//空间复杂度O(1)
|
||||||
var removeElement = (nums, val) => {
|
var removeElement = (nums, val) => {
|
||||||
@ -290,4 +290,4 @@ int removeElement(int* nums, int numsSize, int val){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -215,7 +215,7 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减
|
|||||||
|
|
||||||
其实**这并不涉及到KMP的原理,而是具体实现,next数组即可以就是前缀表,也可以是前缀表统一减一(右移一位,初始位置为-1)。**
|
其实**这并不涉及到KMP的原理,而是具体实现,next数组即可以就是前缀表,也可以是前缀表统一减一(右移一位,初始位置为-1)。**
|
||||||
|
|
||||||
后面我会提供两种不同的实现代码,大家就明白了了。
|
后面我会提供两种不同的实现代码,大家就明白了。
|
||||||
|
|
||||||
# 使用next数组来匹配
|
# 使用next数组来匹配
|
||||||
|
|
||||||
@ -902,4 +902,4 @@ var strStr = function (haystack, needle) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -9,6 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 31.下一个排列
|
# 31.下一个排列
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/next-permutation/)
|
[力扣题目链接](https://leetcode-cn.com/problems/next-permutation/)
|
||||||
@ -132,11 +132,57 @@ class Solution {
|
|||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
//卡尔的解法(吐槽一下JavaScript的sort和其他语言的不太一样,只想到了拷贝数组去排序再替换原数组来实现nums的[i + 1, nums.length)升序排序)
|
||||||
|
var nextPermutation = function(nums) {
|
||||||
|
for(let i = nums.length - 1; i >= 0; i--){
|
||||||
|
for(let j = nums.length - 1; j > i; j--){
|
||||||
|
if(nums[j] > nums[i]){
|
||||||
|
[nums[j],nums[i]] = [nums[i],nums[j]]; // 交换
|
||||||
|
// 深拷贝[i + 1, nums.length)部分到新数组arr
|
||||||
|
let arr = nums.slice(i+1);
|
||||||
|
// arr升序排序
|
||||||
|
arr.sort((a,b) => a - b);
|
||||||
|
// arr替换nums的[i + 1, nums.length)部分
|
||||||
|
nums.splice(i+1,nums.length - i, ...arr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nums.sort((a,b) => a - b); // 不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
|
||||||
|
};
|
||||||
|
|
||||||
|
//另一种
|
||||||
|
var nextPermutation = function(nums) {
|
||||||
|
let i = nums.length - 2;
|
||||||
|
// 从右往左遍历拿到第一个左边小于右边的 i,此时 i 右边的数组是从右往左递增的
|
||||||
|
while (i >= 0 && nums[i] >= nums[i+1]){
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if (i >= 0){
|
||||||
|
let j = nums.length - 1;
|
||||||
|
// 从右往左遍历拿到第一个大于nums[i]的数,因为之前nums[i]是第一个小于他右边的数,所以他的右边一定有大于他的数
|
||||||
|
while (j >= 0 && nums[j] <= nums[i]){
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
// 交换两个数
|
||||||
|
[nums[j], nums[i]] = [nums[i], nums[j]];
|
||||||
|
}
|
||||||
|
// 对 i 右边的数进行交换
|
||||||
|
// 因为 i 右边的数原来是从右往左递增的,把一个较小的值交换过来之后,仍然维持单调递增特性
|
||||||
|
// 此时头尾交换并向中间逼近就能获得 i 右边序列的最小值
|
||||||
|
let l = i + 1;
|
||||||
|
let r = nums.length - 1;
|
||||||
|
while (l < r){
|
||||||
|
[nums[l], nums[r]] = [nums[r], nums[l]];
|
||||||
|
l++;
|
||||||
|
r--;
|
||||||
|
}
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -7,6 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
# 34. 在排序数组中查找元素的第一个和最后一个位置
|
# 34. 在排序数组中查找元素的第一个和最后一个位置
|
||||||
|
|
||||||
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
|
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
|
||||||
@ -396,11 +396,51 @@ class Solution:
|
|||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
var searchRange = function(nums, target) {
|
||||||
|
const getLeftBorder = (nums, target) => {
|
||||||
|
let left = 0, right = nums.length - 1;
|
||||||
|
let leftBorder = -2;// 记录一下leftBorder没有被赋值的情况
|
||||||
|
while(left <= right){
|
||||||
|
let middle = left + ((right - left) >> 1);
|
||||||
|
if(nums[middle] >= target){ // 寻找左边界,nums[middle] == target的时候更新right
|
||||||
|
right = middle - 1;
|
||||||
|
leftBorder = right;
|
||||||
|
} else {
|
||||||
|
left = middle + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return leftBorder;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRightBorder = (nums, target) => {
|
||||||
|
let left = 0, right = nums.length - 1;
|
||||||
|
let rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
|
||||||
|
while (left <= right) {
|
||||||
|
let middle = left + ((right - left) >> 1);
|
||||||
|
if (nums[middle] > target) {
|
||||||
|
right = middle - 1;
|
||||||
|
} else { // 寻找右边界,nums[middle] == target的时候更新left
|
||||||
|
left = middle + 1;
|
||||||
|
rightBorder = left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rightBorder;
|
||||||
|
}
|
||||||
|
|
||||||
|
let leftBorder = getLeftBorder(nums, target);
|
||||||
|
let rightBorder = getRightBorder(nums, target);
|
||||||
|
// 情况一
|
||||||
|
if(leftBorder === -2 || rightBorder === -2) return [-1,-1];
|
||||||
|
// 情况三
|
||||||
|
if (rightBorder - leftBorder > 1) return [leftBorder + 1, rightBorder - 1];
|
||||||
|
// 情况二
|
||||||
|
return [-1, -1];
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -232,7 +232,24 @@ class Solution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
Golang:
|
||||||
|
```golang
|
||||||
|
// 第一种二分法
|
||||||
|
func searchInsert(nums []int, target int) int {
|
||||||
|
l, r := 0, len(nums) - 1
|
||||||
|
for l <= r{
|
||||||
|
m := l + (r - l)/2
|
||||||
|
if nums[m] == target{
|
||||||
|
return m
|
||||||
|
}else if nums[m] > target{
|
||||||
|
r = m - 1
|
||||||
|
}else{
|
||||||
|
l = m + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r + 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python3
|
```python3
|
||||||
@ -313,4 +330,4 @@ func searchInsert(_ nums: [Int], _ target: Int) -> Int {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -293,89 +293,99 @@ class Solution:
|
|||||||
"""
|
"""
|
||||||
Do not return anything, modify board in-place instead.
|
Do not return anything, modify board in-place instead.
|
||||||
"""
|
"""
|
||||||
def backtrack(board):
|
self.backtracking(board)
|
||||||
for i in range(len(board)): #遍历行
|
|
||||||
for j in range(len(board[0])): #遍历列
|
def backtracking(self, board: List[List[str]]) -> bool:
|
||||||
if board[i][j] != ".": continue
|
# 若有解,返回True;若无解,返回False
|
||||||
for k in range(1,10): #(i, j) 这个位置放k是否合适
|
for i in range(len(board)): # 遍历行
|
||||||
if isValid(i,j,k,board):
|
for j in range(len(board[0])): # 遍历列
|
||||||
board[i][j] = str(k) #放置k
|
# 若空格内已有数字,跳过
|
||||||
if backtrack(board): return True #如果找到合适一组立刻返回
|
if board[i][j] != '.': continue
|
||||||
board[i][j] = "." #回溯,撤销k
|
for k in range(1, 10):
|
||||||
return False #9个数都试完了,都不行,那么就返回false
|
if self.is_valid(i, j, k, board):
|
||||||
return True #遍历完没有返回false,说明找到了合适棋盘位置了
|
board[i][j] = str(k)
|
||||||
def isValid(row,col,val,board):
|
if self.backtracking(board): return True
|
||||||
for i in range(9): #判断行里是否重复
|
board[i][j] = '.'
|
||||||
if board[row][i] == str(val):
|
# 若数字1-9都不能成功填入空格,返回False无解
|
||||||
|
return False
|
||||||
|
return True # 有解
|
||||||
|
|
||||||
|
def is_valid(self, row: int, col: int, val: int, board: List[List[str]]) -> bool:
|
||||||
|
# 判断同一行是否冲突
|
||||||
|
for i in range(9):
|
||||||
|
if board[row][i] == str(val):
|
||||||
|
return False
|
||||||
|
# 判断同一列是否冲突
|
||||||
|
for j in range(9):
|
||||||
|
if board[j][col] == str(val):
|
||||||
|
return False
|
||||||
|
# 判断同一九宫格是否有冲突
|
||||||
|
start_row = (row // 3) * 3
|
||||||
|
start_col = (col // 3) * 3
|
||||||
|
for i in range(start_row, start_row + 3):
|
||||||
|
for j in range(start_col, start_col + 3):
|
||||||
|
if board[i][j] == str(val):
|
||||||
return False
|
return False
|
||||||
for j in range(9): #判断列里是否重复
|
|
||||||
if board[j][col] == str(val):
|
|
||||||
return False
|
|
||||||
startRow = (row // 3) * 3
|
|
||||||
startcol = (col // 3) * 3
|
|
||||||
for i in range(startRow,startRow + 3): #判断9方格里是否重复
|
|
||||||
for j in range(startcol,startcol + 3):
|
|
||||||
if board[i][j] == str(val):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
backtrack(board)
|
|
||||||
```
|
|
||||||
|
|
||||||
Python3:
|
|
||||||
|
|
||||||
```python3
|
|
||||||
class Solution:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.board = []
|
|
||||||
|
|
||||||
def isValid(self, row: int, col: int, target: int) -> bool:
|
|
||||||
for idx in range(len(self.board)):
|
|
||||||
# 同列是否重复
|
|
||||||
if self.board[idx][col] == str(target):
|
|
||||||
return False
|
|
||||||
# 同行是否重复
|
|
||||||
if self.board[row][idx] == str(target):
|
|
||||||
return False
|
|
||||||
# 9宫格里是否重复
|
|
||||||
box_row, box_col = (row // 3) * 3 + idx // 3, (col // 3) * 3 + idx % 3
|
|
||||||
if self.board[box_row][box_col] == str(target):
|
|
||||||
return False
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def getPlace(self) -> List[int]:
|
|
||||||
for row in range(len(self.board)):
|
|
||||||
for col in range(len(self.board)):
|
|
||||||
if self.board[row][col] == ".":
|
|
||||||
return [row, col]
|
|
||||||
return [-1, -1]
|
|
||||||
|
|
||||||
def isSolved(self) -> bool:
|
|
||||||
row, col = self.getPlace() # 找个空位置
|
|
||||||
|
|
||||||
if row == -1 and col == -1: # 没有空位置,棋盘被填满的
|
|
||||||
return True
|
|
||||||
|
|
||||||
for i in range(1, 10):
|
|
||||||
if self.isValid(row, col, i): # 检查这个空位置放i,是否合适
|
|
||||||
self.board[row][col] = str(i) # 放i
|
|
||||||
if self.isSolved(): # 合适,立刻返回, 填下一个空位置。
|
|
||||||
return True
|
|
||||||
self.board[row][col] = "." # 不合适,回溯
|
|
||||||
|
|
||||||
return False # 空位置没法解决
|
|
||||||
|
|
||||||
def solveSudoku(self, board: List[List[str]]) -> None:
|
|
||||||
"""
|
|
||||||
Do not return anything, modify board in-place instead.
|
|
||||||
"""
|
|
||||||
if board is None or len(board) == 0:
|
|
||||||
return
|
|
||||||
self.board = board
|
|
||||||
self.isSolved()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func solveSudoku(board [][]byte) {
|
||||||
|
var backtracking func(board [][]byte) bool
|
||||||
|
backtracking=func(board [][]byte) bool{
|
||||||
|
for i:=0;i<9;i++{
|
||||||
|
for j:=0;j<9;j++{
|
||||||
|
//判断此位置是否适合填数字
|
||||||
|
if board[i][j]!='.'{
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//尝试填1-9
|
||||||
|
for k:='1';k<='9';k++{
|
||||||
|
if isvalid(i,j,byte(k),board)==true{//如果满足要求就填
|
||||||
|
board[i][j]=byte(k)
|
||||||
|
if backtracking(board)==true{
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
board[i][j]='.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
backtracking(board)
|
||||||
|
}
|
||||||
|
//判断填入数字是否满足要求
|
||||||
|
func isvalid(row,col int,k byte,board [][]byte)bool{
|
||||||
|
for i:=0;i<9;i++{//行
|
||||||
|
if board[row][i]==k{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i:=0;i<9;i++{//列
|
||||||
|
if board[i][col]==k{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//方格
|
||||||
|
startrow:=(row/3)*3
|
||||||
|
startcol:=(col/3)*3
|
||||||
|
for i:=startrow;i<startrow+3;i++{
|
||||||
|
for j:=startcol;j<startcol+3;j++{
|
||||||
|
if board[i][j]==k{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Javascript:
|
Javascript:
|
||||||
```Javascript
|
```Javascript
|
||||||
var solveSudoku = function(board) {
|
var solveSudoku = function(board) {
|
||||||
@ -432,9 +442,73 @@ var solveSudoku = function(board) {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
C:
|
||||||
|
|
||||||
|
```C
|
||||||
|
bool isValid(char** board, int row, int col, int k) {
|
||||||
|
/* 判断当前行是否有重复元素 */
|
||||||
|
for (int i = 0; i < 9; i++) {
|
||||||
|
if (board[i][col] == k) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 判断当前列是否有重复元素 */
|
||||||
|
for (int j = 0; j < 9; j++) {
|
||||||
|
if (board[row][j] == k) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 计算当前9宫格左上角的位置 */
|
||||||
|
int startRow = (row / 3) * 3;
|
||||||
|
int startCol = (col / 3) * 3;
|
||||||
|
/* 判断当前元素所在九宫格是否有重复元素 */
|
||||||
|
for (int i = startRow; i < startRow + 3; i++) {
|
||||||
|
for (int j = startCol; j < startCol + 3; j++) {
|
||||||
|
if (board[i][j] == k) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 满足条件,返回true */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool backtracking(char** board, int boardSize, int* boardColSize) {
|
||||||
|
/* 从上到下、从左到右依次遍历输入数组 */
|
||||||
|
for (int i = 0; i < boardSize; i++) {
|
||||||
|
for (int j = 0; j < *boardColSize; j++) {
|
||||||
|
/* 遇到数字跳过 */
|
||||||
|
if (board[i][j] != '.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* 依次将数组1到9填入当前位置 */
|
||||||
|
for (int k = '1'; k <= '9'; k++) {
|
||||||
|
/* 判断当前位置是否与满足条件,是则进入下一层 */
|
||||||
|
if (isValid(board, i, j, k)) {
|
||||||
|
board[i][j] = k;
|
||||||
|
/* 判断下一层递归之后是否找到一种解法,是则返回true */
|
||||||
|
if (backtracking(board, boardSize, boardColSize)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/* 回溯,将当前位置清零 */
|
||||||
|
board[i][j] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 若填入的9个数均不满足条件,返回false,说明此解法无效 */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 遍历完所有的棋盘,没有返回false,说明找到了解法,返回true */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void solveSudoku(char** board, int boardSize, int* boardColSize) {
|
||||||
|
bool res = backtracking(board, boardSize, boardColSize);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
## 39. 组合总和
|
# 39. 组合总和
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/combination-sum/)
|
[力扣题目链接](https://leetcode-cn.com/problems/combination-sum/)
|
||||||
|
|
||||||
@ -37,21 +37,21 @@ candidates 中的数字可以无限制重复被选取。
|
|||||||
[3,5]
|
[3,5]
|
||||||
]
|
]
|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
[B站视频讲解-组合总和](https://www.bilibili.com/video/BV1KT4y1M7HJ)
|
[B站视频讲解-组合总和](https://www.bilibili.com/video/BV1KT4y1M7HJ)
|
||||||
|
|
||||||
|
|
||||||
题目中的**无限制重复被选取,吓得我赶紧想想 出现0 可咋办**,然后看到下面提示:1 <= candidates[i] <= 200,我就放心了。
|
题目中的**无限制重复被选取,吓得我赶紧想想 出现0 可咋办**,然后看到下面提示:1 <= candidates[i] <= 200,我就放心了。
|
||||||
|
|
||||||
本题和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html),[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)和区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。
|
本题和[77.组合](https://programmercarl.com/0077.组合.html),[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)和区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。
|
||||||
|
|
||||||
本题搜索的过程抽象成树形结构如下:
|
本题搜索的过程抽象成树形结构如下:
|
||||||
|
|
||||||

|

|
||||||
注意图中叶子节点的返回条件,因为本题没有组合数量要求,仅仅是总和的限制,所以递归没有层数的限制,只要选取的元素总和超过target,就返回!
|
注意图中叶子节点的返回条件,因为本题没有组合数量要求,仅仅是总和的限制,所以递归没有层数的限制,只要选取的元素总和超过target,就返回!
|
||||||
|
|
||||||
而在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html) 中都可以知道要递归K层,因为要取k个元素的组合。
|
而在[77.组合](https://programmercarl.com/0077.组合.html)和[216.组合总和III](https://programmercarl.com/0216.组合总和III.html) 中都可以知道要递归K层,因为要取k个元素的组合。
|
||||||
|
|
||||||
## 回溯三部曲
|
## 回溯三部曲
|
||||||
|
|
||||||
@ -65,9 +65,9 @@ candidates 中的数字可以无限制重复被选取。
|
|||||||
|
|
||||||
**本题还需要startIndex来控制for循环的起始位置,对于组合问题,什么时候需要startIndex呢?**
|
**本题还需要startIndex来控制for循环的起始位置,对于组合问题,什么时候需要startIndex呢?**
|
||||||
|
|
||||||
我举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html),[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)。
|
我举过例子,如果是一个集合来求组合的话,就需要startIndex,例如:[77.组合](https://programmercarl.com/0077.组合.html),[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)。
|
||||||
|
|
||||||
如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:[回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)
|
如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:[17.电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)
|
||||||
|
|
||||||
**注意以上我只是说求组合的情况,如果是排列问题,又是另一套分析的套路,后面我再讲解排列的时候就重点介绍**。
|
**注意以上我只是说求组合的情况,如果是排列问题,又是另一套分析的套路,后面我再讲解排列的时候就重点介绍**。
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ if (sum == target) {
|
|||||||
|
|
||||||
单层for循环依然是从startIndex开始,搜索candidates集合。
|
单层for循环依然是从startIndex开始,搜索candidates集合。
|
||||||
|
|
||||||
**注意本题和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)、[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)的一个区别是:本题元素为可重复选取的**。
|
**注意本题和[77.组合](https://programmercarl.com/0077.组合.html)、[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)的一个区别是:本题元素为可重复选取的**。
|
||||||
|
|
||||||
如何重复选取呢,看代码,注释部分:
|
如何重复选取呢,看代码,注释部分:
|
||||||
|
|
||||||
@ -211,16 +211,16 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## 总结
|
# 总结
|
||||||
|
|
||||||
本题和我们之前讲过的[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)、[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)有两点不同:
|
本题和我们之前讲过的[77.组合](https://programmercarl.com/0077.组合.html)、[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)有两点不同:
|
||||||
|
|
||||||
* 组合没有数量要求
|
* 组合没有数量要求
|
||||||
* 元素可无限重复选取
|
* 元素可无限重复选取
|
||||||
|
|
||||||
针对这两个问题,我都做了详细的分析。
|
针对这两个问题,我都做了详细的分析。
|
||||||
|
|
||||||
并且给出了对于组合问题,什么时候用startIndex,什么时候不用,并用[回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)做了对比。
|
并且给出了对于组合问题,什么时候用startIndex,什么时候不用,并用[17.电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)做了对比。
|
||||||
|
|
||||||
最后还给出了本题的剪枝优化,这个优化如果是初学者的话并不容易想到。
|
最后还给出了本题的剪枝优化,这个优化如果是初学者的话并不容易想到。
|
||||||
|
|
||||||
@ -232,10 +232,10 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
## Java
|
||||||
```Java
|
```Java
|
||||||
// 剪枝优化
|
// 剪枝优化
|
||||||
class Solution {
|
class Solution {
|
||||||
@ -264,30 +264,77 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
## Python
|
||||||
|
**回溯**
|
||||||
```python3
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
|
def __init__(self):
|
||||||
|
self.path = []
|
||||||
|
self.paths = []
|
||||||
|
|
||||||
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
|
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||||
res = []
|
'''
|
||||||
path = []
|
因为本题没有组合数量限制,所以只要元素总和大于target就算结束
|
||||||
def backtrack(candidates,target,sum,startIndex):
|
'''
|
||||||
if sum > target: return
|
self.path.clear()
|
||||||
if sum == target: return res.append(path[:])
|
self.paths.clear()
|
||||||
for i in range(startIndex,len(candidates)):
|
self.backtracking(candidates, target, 0, 0)
|
||||||
if sum + candidates[i] >target: return #如果 sum + candidates[i] > target 就终止遍历
|
return self.paths
|
||||||
sum += candidates[i]
|
|
||||||
path.append(candidates[i])
|
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
|
||||||
backtrack(candidates,target,sum,i) #startIndex = i:表示可以重复读取当前的数
|
# Base Case
|
||||||
sum -= candidates[i] #回溯
|
if sum_ == target:
|
||||||
path.pop() #回溯
|
self.paths.append(self.path[:]) # 因为是shallow copy,所以不能直接传入self.path
|
||||||
candidates = sorted(candidates) #需要排序
|
return
|
||||||
backtrack(candidates,target,0,0)
|
if sum_ > target:
|
||||||
return res
|
return
|
||||||
|
|
||||||
|
# 单层递归逻辑
|
||||||
|
for i in range(start_index, len(candidates)):
|
||||||
|
sum_ += candidates[i]
|
||||||
|
self.path.append(candidates[i])
|
||||||
|
self.backtracking(candidates, target, sum_, i) # 因为无限制重复选取,所以不是i-1
|
||||||
|
sum_ -= candidates[i] # 回溯
|
||||||
|
self.path.pop() # 回溯
|
||||||
```
|
```
|
||||||
Go:
|
**剪枝回溯**
|
||||||
|
```python3
|
||||||
|
class Solution:
|
||||||
|
def __init__(self):
|
||||||
|
self.path = []
|
||||||
|
self.paths = []
|
||||||
|
|
||||||
|
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||||
|
'''
|
||||||
|
因为本题没有组合数量限制,所以只要元素总和大于target就算结束
|
||||||
|
'''
|
||||||
|
self.path.clear()
|
||||||
|
self.paths.clear()
|
||||||
|
|
||||||
> 主要在于递归中传递下一个数字
|
# 为了剪枝需要提前进行排序
|
||||||
|
candidates.sort()
|
||||||
|
self.backtracking(candidates, target, 0, 0)
|
||||||
|
return self.paths
|
||||||
|
|
||||||
|
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
|
||||||
|
# Base Case
|
||||||
|
if sum_ == target:
|
||||||
|
self.paths.append(self.path[:]) # 因为是shallow copy,所以不能直接传入self.path
|
||||||
|
return
|
||||||
|
# 单层递归逻辑
|
||||||
|
# 如果本层 sum + condidates[i] > target,就提前结束遍历,剪枝
|
||||||
|
for i in range(start_index, len(candidates)):
|
||||||
|
if sum_ + candidates[i] > target:
|
||||||
|
return
|
||||||
|
sum_ += candidates[i]
|
||||||
|
self.path.append(candidates[i])
|
||||||
|
self.backtracking(candidates, target, sum_, i) # 因为无限制重复选取,所以不是i-1
|
||||||
|
sum_ -= candidates[i] # 回溯
|
||||||
|
self.path.pop() # 回溯
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go
|
||||||
|
主要在于递归中传递下一个数字
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func combinationSum(candidates []int, target int) [][]int {
|
func combinationSum(candidates []int, target int) [][]int {
|
||||||
@ -319,7 +366,8 @@ func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int)
|
|||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
JavaScript:
|
|
||||||
|
## JavaScript:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var combinationSum = function(candidates, target) {
|
var combinationSum = function(candidates, target) {
|
||||||
@ -346,7 +394,7 @@ var combinationSum = function(candidates, target) {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
C:
|
## C
|
||||||
```c
|
```c
|
||||||
int* path;
|
int* path;
|
||||||
int pathTop;
|
int pathTop;
|
||||||
@ -405,4 +453,4 @@ int** combinationSum(int* candidates, int candidatesSize, int target, int* retur
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
> 这篇可以说是全网把组合问题如何去重,讲的最清晰的了!
|
> 这篇可以说是全网把组合问题如何去重,讲的最清晰的了!
|
||||||
|
|
||||||
## 40.组合总和II
|
# 40.组合总和II
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/combination-sum-ii/)
|
[力扣题目链接](https://leetcode-cn.com/problems/combination-sum-ii/)
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ candidates 中的每个数字在每个组合中只能使用一次。
|
|||||||
[5]
|
[5]
|
||||||
]
|
]
|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
**如果对回溯算法基础还不了解的话,我还特意录制了一期视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/)** 可以结合题解和视频一起看,希望对大家理解回溯算法有所帮助。
|
**如果对回溯算法基础还不了解的话,我还特意录制了一期视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/)** 可以结合题解和视频一起看,希望对大家理解回溯算法有所帮助。
|
||||||
|
|
||||||
@ -157,7 +157,6 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target;
|
|||||||
|
|
||||||
**注意sum + candidates[i] <= target为剪枝操作,在[39.组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)有讲解过!**
|
**注意sum + candidates[i] <= target为剪枝操作,在[39.组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)有讲解过!**
|
||||||
|
|
||||||
## C++代码
|
|
||||||
|
|
||||||
回溯三部曲分析完了,整体C++代码如下:
|
回溯三部曲分析完了,整体C++代码如下:
|
||||||
|
|
||||||
@ -242,7 +241,7 @@ public:
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 总结
|
# 总结
|
||||||
|
|
||||||
本题同样是求组合总和,但就是因为其数组candidates有重复元素,而要求不能有重复的组合,所以相对于[39.组合总和](https://programmercarl.com/0039.组合总和.html)难度提升了不少。
|
本题同样是求组合总和,但就是因为其数组candidates有重复元素,而要求不能有重复的组合,所以相对于[39.组合总和](https://programmercarl.com/0039.组合总和.html)难度提升了不少。
|
||||||
|
|
||||||
@ -254,10 +253,10 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
## Java
|
||||||
```Java
|
```Java
|
||||||
class Solution {
|
class Solution {
|
||||||
List<List<Integer>> lists = new ArrayList<>();
|
List<List<Integer>> lists = new ArrayList<>();
|
||||||
@ -295,30 +294,97 @@ class Solution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Python:
|
|
||||||
```python
|
## Python
|
||||||
|
**回溯+巧妙去重(省去使用used**
|
||||||
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
|
def __init__(self):
|
||||||
|
self.paths = []
|
||||||
|
self.path = []
|
||||||
|
|
||||||
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
|
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||||
res = []
|
'''
|
||||||
path = []
|
类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
|
||||||
def backtrack(candidates,target,sum,startIndex):
|
'''
|
||||||
if sum == target: res.append(path[:])
|
self.paths.clear()
|
||||||
for i in range(startIndex,len(candidates)): #要对同一树层使用过的元素进行跳过
|
self.path.clear()
|
||||||
if sum + candidates[i] > target: return
|
# 必须提前进行数组排序,避免重复
|
||||||
if i > startIndex and candidates[i] == candidates[i-1]: continue #直接用startIndex来去重,要对同一树层使用过的元素进行跳过
|
candidates.sort()
|
||||||
sum += candidates[i]
|
self.backtracking(candidates, target, 0, 0)
|
||||||
path.append(candidates[i])
|
return self.paths
|
||||||
backtrack(candidates,target,sum,i+1) #i+1:每个数字在每个组合中只能使用一次
|
|
||||||
sum -= candidates[i] #回溯
|
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
|
||||||
path.pop() #回溯
|
# Base Case
|
||||||
candidates = sorted(candidates) #首先把给candidates排序,让其相同的元素都挨在一起。
|
if sum_ == target:
|
||||||
backtrack(candidates,target,0,0)
|
self.paths.append(self.path[:])
|
||||||
return res
|
return
|
||||||
|
|
||||||
|
# 单层递归逻辑
|
||||||
|
for i in range(start_index, len(candidates)):
|
||||||
|
# 剪枝,同39.组合总和
|
||||||
|
if sum_ + candidates[i] > target:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 跳过同一树层使用过的元素
|
||||||
|
if i > start_index and candidates[i] == candidates[i-1]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sum_ += candidates[i]
|
||||||
|
self.path.append(candidates[i])
|
||||||
|
self.backtracking(candidates, target, sum_, i+1)
|
||||||
|
self.path.pop() # 回溯,为了下一轮for loop
|
||||||
|
sum_ -= candidates[i] # 回溯,为了下一轮for loop
|
||||||
```
|
```
|
||||||
Go:
|
**回溯+去重(使用used)**
|
||||||
|
```python3
|
||||||
|
class Solution:
|
||||||
|
def __init__(self):
|
||||||
|
self.paths = []
|
||||||
|
self.path = []
|
||||||
|
self.used = []
|
||||||
|
|
||||||
|
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||||
|
'''
|
||||||
|
类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
|
||||||
|
本题需要使用used,用来标记区别同一树层的元素使用重复情况:注意区分递归纵向遍历遇到的重复元素,和for循环遇到的重复元素,这两者的区别
|
||||||
|
'''
|
||||||
|
self.paths.clear()
|
||||||
|
self.path.clear()
|
||||||
|
self.usage_list = [False] * len(candidates)
|
||||||
|
# 必须提前进行数组排序,避免重复
|
||||||
|
candidates.sort()
|
||||||
|
self.backtracking(candidates, target, 0, 0)
|
||||||
|
return self.paths
|
||||||
|
|
||||||
> 主要在于如何在回溯中去重
|
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
|
||||||
|
# Base Case
|
||||||
|
if sum_ == target:
|
||||||
|
self.paths.append(self.path[:])
|
||||||
|
return
|
||||||
|
|
||||||
|
# 单层递归逻辑
|
||||||
|
for i in range(start_index, len(candidates)):
|
||||||
|
# 剪枝,同39.组合总和
|
||||||
|
if sum_ + candidates[i] > target:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 检查同一树层是否出现曾经使用过的相同元素
|
||||||
|
# 若数组中前后元素值相同,但前者却未被使用(used == False),说明是for loop中的同一树层的相同元素情况
|
||||||
|
if i > 0 and candidates[i] == candidates[i-1] and self.usage_list[i-1] == False:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sum_ += candidates[i]
|
||||||
|
self.path.append(candidates[i])
|
||||||
|
self.usage_list[i] = True
|
||||||
|
self.backtracking(candidates, target, sum_, i+1)
|
||||||
|
self.usage_list[i] = False # 回溯,为了下一轮for loop
|
||||||
|
self.path.pop() # 回溯,为了下一轮for loop
|
||||||
|
sum_ -= candidates[i] # 回溯,为了下一轮for loop
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go:
|
||||||
|
主要在于如何在回溯中去重
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func combinationSum2(candidates []int, target int) [][]int {
|
func combinationSum2(candidates []int, target int) [][]int {
|
||||||
@ -359,7 +425,8 @@ func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
javaScript:
|
|
||||||
|
## javaScript:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
/**
|
/**
|
||||||
@ -392,7 +459,8 @@ var combinationSum2 = function(candidates, target) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
C:
|
## C
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int* path;
|
int* path;
|
||||||
int pathTop;
|
int pathTop;
|
||||||
@ -457,4 +525,4 @@ int** combinationSum2(int* candidates, int candidatesSize, int target, int* retu
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -7,6 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
> 这个图就是大厂面试经典题目,接雨水! 最常青藤的一道题,面试官百出不厌!
|
> 这个图就是大厂面试经典题目,接雨水! 最常青藤的一道题,面试官百出不厌!
|
||||||
|
|
||||||
# 42. 接雨水
|
# 42. 接雨水
|
||||||
@ -134,13 +134,16 @@ public:
|
|||||||
因为每次遍历列的时候,还要向两边寻找最高的列,所以时间复杂度为O(n^2)。
|
因为每次遍历列的时候,还要向两边寻找最高的列,所以时间复杂度为O(n^2)。
|
||||||
空间复杂度为O(1)。
|
空间复杂度为O(1)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 动态规划解法
|
## 动态规划解法
|
||||||
|
|
||||||
在上一节的双指针解法中,我们可以看到只要记录左边柱子的最高高度 和 右边柱子的最高高度,就可以计算当前位置的雨水面积,这就是通过列来计算。
|
在上一节的双指针解法中,我们可以看到只要记录左边柱子的最高高度 和 右边柱子的最高高度,就可以计算当前位置的雨水面积,这就是通过列来计算。
|
||||||
|
|
||||||
当前列雨水面积:min(左边柱子的最高高度,记录右边柱子的最高高度) - 当前柱子高度。
|
当前列雨水面积:min(左边柱子的最高高度,记录右边柱子的最高高度) - 当前柱子高度。
|
||||||
|
|
||||||
为了的到两边的最高高度,使用了双指针来遍历,每到一个柱子都向两边遍历一遍,这其实是有重复计算的。我们把每一个位置的左边最高高度记录在一个数组上(maxLeft),右边最高高度记录在一个数组上(maxRight)。这样就避免了重复计算,这就用到了动态规划。
|
为了得到两边的最高高度,使用了双指针来遍历,每到一个柱子都向两边遍历一遍,这其实是有重复计算的。我们把每一个位置的左边最高高度记录在一个数组上(maxLeft),右边最高高度记录在一个数组上(maxRight)。这样就避免了重复计算,这就用到了动态规划。
|
||||||
|
|
||||||
当前位置,左边的最高高度是前一个位置的左边最高高度和本高度的最大值。
|
当前位置,左边的最高高度是前一个位置的左边最高高度和本高度的最大值。
|
||||||
|
|
||||||
@ -201,7 +204,7 @@ public:
|
|||||||
|
|
||||||
2. 使用单调栈内元素的顺序
|
2. 使用单调栈内元素的顺序
|
||||||
|
|
||||||
从大到小还是从小打到呢?
|
从大到小还是从小到大呢?
|
||||||
|
|
||||||
从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
|
从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
|
||||||
|
|
||||||
@ -391,6 +394,7 @@ class Solution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
动态规划法
|
动态规划法
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
@ -418,6 +422,54 @@ class Solution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
单调栈法
|
||||||
|
```java
|
||||||
|
class Solution {
|
||||||
|
public int trap(int[] height){
|
||||||
|
int size = height.length;
|
||||||
|
|
||||||
|
if (size <= 2) return 0;
|
||||||
|
|
||||||
|
// in the stack, we push the index of array
|
||||||
|
// using height[] to access the real height
|
||||||
|
Stack<Integer> stack = new Stack<Integer>();
|
||||||
|
stack.push(0);
|
||||||
|
|
||||||
|
int sum = 0;
|
||||||
|
for (int index = 1; index < size; index++){
|
||||||
|
int stackTop = stack.peek();
|
||||||
|
if (height[index] < height[stackTop]){
|
||||||
|
stack.push(index);
|
||||||
|
}else if (height[index] == height[stackTop]){
|
||||||
|
// 因为相等的相邻墙,左边一个是不可能存放雨水的,所以pop左边的index, push当前的index
|
||||||
|
stack.pop();
|
||||||
|
stack.push(index);
|
||||||
|
}else{
|
||||||
|
//pop up all lower value
|
||||||
|
int heightAtIdx = height[index];
|
||||||
|
while (!stack.isEmpty() && (heightAtIdx > height[stackTop])){
|
||||||
|
int mid = stack.pop();
|
||||||
|
|
||||||
|
if (!stack.isEmpty()){
|
||||||
|
int left = stack.peek();
|
||||||
|
|
||||||
|
int h = Math.min(height[left], height[index]) - height[mid];
|
||||||
|
int w = index - left - 1;
|
||||||
|
int hold = h * w;
|
||||||
|
if (hold > 0) sum += hold;
|
||||||
|
stackTop = stack.peek();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack.push(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
双指针法
|
双指针法
|
||||||
@ -463,29 +515,236 @@ class Solution:
|
|||||||
```python3
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
def trap(self, height: List[int]) -> int:
|
def trap(self, height: List[int]) -> int:
|
||||||
st =[0]
|
# 单调栈
|
||||||
|
'''
|
||||||
|
单调栈是按照 行 的方向来计算雨水
|
||||||
|
从栈顶到栈底的顺序:从小到大
|
||||||
|
通过三个元素来接水:栈顶,栈顶的下一个元素,以及即将入栈的元素
|
||||||
|
雨水高度是 min(凹槽左边高度, 凹槽右边高度) - 凹槽底部高度
|
||||||
|
雨水的宽度是 凹槽右边的下标 - 凹槽左边的下标 - 1(因为只求中间宽度)
|
||||||
|
'''
|
||||||
|
# stack储存index,用于计算对应的柱子高度
|
||||||
|
stack = [0]
|
||||||
result = 0
|
result = 0
|
||||||
for i in range(1,len(height)):
|
for i in range(1, len(height)):
|
||||||
while st!=[] and height[i]>height[st[-1]]:
|
# 情况一
|
||||||
midh = height[st[-1]]
|
if height[i] < height[stack[-1]]:
|
||||||
st.pop()
|
stack.append(i)
|
||||||
if st!=[]:
|
|
||||||
hright = height[i]
|
# 情况二
|
||||||
hleft = height[st[-1]]
|
# 当当前柱子高度和栈顶一致时,左边的一个是不可能存放雨水的,所以保留右侧新柱子
|
||||||
h = min(hright,hleft)-midh
|
# 需要使用最右边的柱子来计算宽度
|
||||||
w = i-st[-1]-1
|
elif height[i] == height[stack[-1]]:
|
||||||
result+=h*w
|
stack.pop()
|
||||||
st.append(i)
|
stack.append(i)
|
||||||
|
|
||||||
|
# 情况三
|
||||||
|
else:
|
||||||
|
# 抛出所有较低的柱子
|
||||||
|
while stack and height[i] > height[stack[-1]]:
|
||||||
|
# 栈顶就是中间的柱子:储水槽,就是凹槽的地步
|
||||||
|
mid_height = height[stack[-1]]
|
||||||
|
stack.pop()
|
||||||
|
if stack:
|
||||||
|
right_height = height[i]
|
||||||
|
left_height = height[stack[-1]]
|
||||||
|
# 两侧的较矮一方的高度 - 凹槽底部高度
|
||||||
|
h = min(right_height, left_height) - mid_height
|
||||||
|
# 凹槽右侧下标 - 凹槽左侧下标 - 1: 只求中间宽度
|
||||||
|
w = i - stack[-1] - 1
|
||||||
|
# 体积:高乘宽
|
||||||
|
result += h * w
|
||||||
|
stack.append(i)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
# 单调栈压缩版
|
||||||
|
class Solution:
|
||||||
|
def trap(self, height: List[int]) -> int:
|
||||||
|
stack = [0]
|
||||||
|
result = 0
|
||||||
|
for i in range(1, len(height)):
|
||||||
|
while stack and height[i] > height[stack[-1]]:
|
||||||
|
mid_height = stack.pop()
|
||||||
|
if stack:
|
||||||
|
# 雨水高度是 min(凹槽左侧高度, 凹槽右侧高度) - 凹槽底部高度
|
||||||
|
h = min(height[stack[-1]], height[i]) - height[mid_height]
|
||||||
|
# 雨水宽度是 凹槽右侧的下标 - 凹槽左侧的下标 - 1
|
||||||
|
w = i - stack[-1] - 1
|
||||||
|
# 累计总雨水体积
|
||||||
|
result += h * w
|
||||||
|
stack.append(i)
|
||||||
|
return result
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func trap(height []int) int {
|
||||||
|
var left, right, leftMax, rightMax, res int
|
||||||
|
right = len(height) - 1
|
||||||
|
for left < right {
|
||||||
|
if height[left] < height[right] {
|
||||||
|
if height[left] >= leftMax {
|
||||||
|
leftMax = height[left] // 设置左边最高柱子
|
||||||
|
} else {
|
||||||
|
res += leftMax - height[left] // //右边必定有柱子挡水,所以遇到所有值小于等于leftMax的,全部加入水池中
|
||||||
|
}
|
||||||
|
left++
|
||||||
|
} else {
|
||||||
|
if height[right] > rightMax {
|
||||||
|
rightMax = height[right] // //设置右边最高柱子
|
||||||
|
} else {
|
||||||
|
res += rightMax - height[right] // //左边必定有柱子挡水,所以,遇到所有值小于等于rightMax的,全部加入水池
|
||||||
|
}
|
||||||
|
right--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
//双指针
|
||||||
|
var trap = function(height) {
|
||||||
|
const len = height.length;
|
||||||
|
let sum = 0;
|
||||||
|
for(let i = 0; i < len; i++){
|
||||||
|
// 第一个柱子和最后一个柱子不接雨水
|
||||||
|
if(i == 0 || i == len - 1) continue;
|
||||||
|
let rHeight = height[i]; // 记录右边柱子的最高高度
|
||||||
|
let lHeight = height[i]; // 记录左边柱子的最高高度
|
||||||
|
for(let r = i + 1; r < len; r++){
|
||||||
|
if(height[r] > rHeight) rHeight = height[r];
|
||||||
|
}
|
||||||
|
for(let l = i - 1; l >= 0; l--){
|
||||||
|
if(height[l] > lHeight) lHeight = height[l];
|
||||||
|
}
|
||||||
|
let h = Math.min(lHeight, rHeight) - height[i];
|
||||||
|
if(h > 0) sum += h;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
};
|
||||||
|
|
||||||
|
//动态规划
|
||||||
|
var trap = function(height) {
|
||||||
|
const len = height.length;
|
||||||
|
if(len <= 2) return 0;
|
||||||
|
const maxLeft = new Array(len).fill(0);
|
||||||
|
const maxRight = new Array(len).fill(0);
|
||||||
|
// 记录每个柱子左边柱子最大高度
|
||||||
|
maxLeft[0] = height[0];
|
||||||
|
for(let i = 1; i < len; i++){
|
||||||
|
maxLeft[i] = Math.max(height[i], maxLeft[i - 1]);
|
||||||
|
}
|
||||||
|
// 记录每个柱子右边柱子最大高度
|
||||||
|
maxRight[len - 1] = height[len - 1];
|
||||||
|
for(let i = len - 2; i >= 0; i--){
|
||||||
|
maxRight[i] = Math.max(height[i], maxRight[i + 1]);
|
||||||
|
}
|
||||||
|
// 求和
|
||||||
|
let sum = 0;
|
||||||
|
for(let i = 0; i < len; i++){
|
||||||
|
let count = Math.min(maxLeft[i], maxRight[i]) - height[i];
|
||||||
|
if(count > 0) sum += count;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
};
|
||||||
|
|
||||||
|
//单调栈 js数组作为栈
|
||||||
|
var trap = function(height) {
|
||||||
|
const len = height.length;
|
||||||
|
if(len <= 2) return 0; // 可以不加
|
||||||
|
const st = [];// 存着下标,计算的时候用下标对应的柱子高度
|
||||||
|
st.push(0);
|
||||||
|
let sum = 0;
|
||||||
|
for(let i = 1; i < len; i++){
|
||||||
|
if(height[i] < height[st[st.length - 1]]){ // 情况一
|
||||||
|
st.push(i);
|
||||||
|
}
|
||||||
|
if (height[i] == height[st[st.length - 1]]) { // 情况二
|
||||||
|
st.pop(); // 其实这一句可以不加,效果是一样的,但处理相同的情况的思路却变了。
|
||||||
|
st.push(i);
|
||||||
|
} else { // 情况三
|
||||||
|
while (st.length !== 0 && height[i] > height[st[st.length - 1]]) { // 注意这里是while
|
||||||
|
let mid = st[st.length - 1];
|
||||||
|
st.pop();
|
||||||
|
if (st.length !== 0) {
|
||||||
|
let h = Math.min(height[st[st.length - 1]], height[i]) - height[mid];
|
||||||
|
let w = i - st[st.length - 1] - 1; // 注意减一,只求中间宽度
|
||||||
|
sum += h * w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
};
|
||||||
|
|
||||||
|
//单调栈 简洁版本 只处理情况三
|
||||||
|
var trap = function(height) {
|
||||||
|
const len = height.length;
|
||||||
|
if(len <= 2) return 0; // 可以不加
|
||||||
|
const st = [];// 存着下标,计算的时候用下标对应的柱子高度
|
||||||
|
st.push(0);
|
||||||
|
let sum = 0;
|
||||||
|
for(let i = 1; i < len; i++){ // 只处理的情况三,其实是把情况一和情况二融合了
|
||||||
|
while (st.length !== 0 && height[i] > height[st[st.length - 1]]) { // 注意这里是while
|
||||||
|
let mid = st[st.length - 1];
|
||||||
|
st.pop();
|
||||||
|
if (st.length !== 0) {
|
||||||
|
let h = Math.min(height[st[st.length - 1]], height[i]) - height[mid];
|
||||||
|
let w = i - st[st.length - 1] - 1; // 注意减一,只求中间宽度
|
||||||
|
sum += h * w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st.push(i);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
C:
|
||||||
|
|
||||||
|
一种更简便的双指针方法:
|
||||||
|
|
||||||
|
之前的双指针方法的原理是固定“底”的位置,往两边找比它高的“壁”,循环若干次求和。
|
||||||
|
|
||||||
|
我们逆向思维,把“壁”用两个初始位置在数组首末位置的指针表示,“壁”往中间推,同样可以让每个“底”都能找到最高的“壁”
|
||||||
|
|
||||||
|
本质上就是改变了运算方向,从而减少了重复运算
|
||||||
|
|
||||||
|
代码如下:
|
||||||
|
|
||||||
|
```C
|
||||||
|
int trap(int* height, int heightSize) {
|
||||||
|
int ans = 0;
|
||||||
|
int left = 0, right = heightSize - 1; //初始化两个指针到左右两边
|
||||||
|
int leftMax = 0, rightMax = 0; //这两个值用来记录左右的“壁”的最高值
|
||||||
|
while (left < right) { //两个指针重合就结束
|
||||||
|
leftMax = fmax(leftMax, height[left]);
|
||||||
|
rightMax = fmax(rightMax, height[right]);
|
||||||
|
if (leftMax < rightMax) {
|
||||||
|
ans += leftMax - height[left]; //这里考虑的是下标为left的“底”能装多少水
|
||||||
|
++left;//指针的移动次序是这个方法的关键
|
||||||
|
//这里左指针右移是因为左“墙”较矮,左边这一片实际情况下的盛水量是受制于这个矮的左“墙”的
|
||||||
|
//而较高的右边在实际情况下的限制条件可能不是当前的左“墙”,比如限制条件可能是右“墙”,就能装更高的水,
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ans += rightMax - height[right]; //同理,考虑下标为right的元素
|
||||||
|
--right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
时间复杂度 O(n)
|
||||||
|
空间复杂度 O(1)
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -236,4 +236,4 @@ var jump = function(nums) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -211,44 +211,68 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
**回溯**
|
||||||
```python3
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
def permute(self, nums: List[int]) -> List[List[int]]:
|
def __init__(self):
|
||||||
res = [] #存放符合条件结果的集合
|
self.path = []
|
||||||
path = [] #用来存放符合条件的结果
|
self.paths = []
|
||||||
used = [] #用来存放已经用过的数字
|
|
||||||
def backtrack(nums,used):
|
|
||||||
if len(path) == len(nums):
|
|
||||||
return res.append(path[:]) #此时说明找到了一组
|
|
||||||
for i in range(0,len(nums)):
|
|
||||||
if nums[i] in used:
|
|
||||||
continue #used里已经收录的元素,直接跳过
|
|
||||||
path.append(nums[i])
|
|
||||||
used.append(nums[i])
|
|
||||||
backtrack(nums,used)
|
|
||||||
used.pop()
|
|
||||||
path.pop()
|
|
||||||
backtrack(nums,used)
|
|
||||||
return res
|
|
||||||
```
|
|
||||||
|
|
||||||
Python(优化,不用used数组):
|
def permute(self, nums: List[int]) -> List[List[int]]:
|
||||||
|
'''
|
||||||
|
因为本题排列是有序的,这意味着同一层的元素可以重复使用,但同一树枝上不能重复使用(usage_list)
|
||||||
|
所以处理排列问题每层都需要从头搜索,故不再使用start_index
|
||||||
|
'''
|
||||||
|
usage_list = [False] * len(nums)
|
||||||
|
self.backtracking(nums, usage_list)
|
||||||
|
return self.paths
|
||||||
|
|
||||||
|
def backtracking(self, nums: List[int], usage_list: List[bool]) -> None:
|
||||||
|
# Base Case本题求叶子节点
|
||||||
|
if len(self.path) == len(nums):
|
||||||
|
self.paths.append(self.path[:])
|
||||||
|
return
|
||||||
|
|
||||||
|
# 单层递归逻辑
|
||||||
|
for i in range(0, len(nums)): # 从头开始搜索
|
||||||
|
# 若遇到self.path里已收录的元素,跳过
|
||||||
|
if usage_list[i] == True:
|
||||||
|
continue
|
||||||
|
usage_list[i] = True
|
||||||
|
self.path.append(nums[i])
|
||||||
|
self.backtracking(nums, usage_list) # 纵向传递使用信息,去重
|
||||||
|
self.path.pop()
|
||||||
|
usage_list[i] = False
|
||||||
|
```
|
||||||
|
**回溯+丢掉usage_list**
|
||||||
```python3
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
|
def __init__(self):
|
||||||
|
self.path = []
|
||||||
|
self.paths = []
|
||||||
|
|
||||||
def permute(self, nums: List[int]) -> List[List[int]]:
|
def permute(self, nums: List[int]) -> List[List[int]]:
|
||||||
res = [] #存放符合条件结果的集合
|
'''
|
||||||
path = [] #用来存放符合条件的结果
|
因为本题排列是有序的,这意味着同一层的元素可以重复使用,但同一树枝上不能重复使用
|
||||||
def backtrack(nums):
|
所以处理排列问题每层都需要从头搜索,故不再使用start_index
|
||||||
if len(path) == len(nums):
|
'''
|
||||||
return res.append(path[:]) #此时说明找到了一组
|
self.backtracking(nums)
|
||||||
for i in range(0,len(nums)):
|
return self.paths
|
||||||
if nums[i] in path: #path里已经收录的元素,直接跳过
|
|
||||||
continue
|
def backtracking(self, nums: List[int]) -> None:
|
||||||
path.append(nums[i])
|
# Base Case本题求叶子节点
|
||||||
backtrack(nums) #递归
|
if len(self.path) == len(nums):
|
||||||
path.pop() #回溯
|
self.paths.append(self.path[:])
|
||||||
backtrack(nums)
|
return
|
||||||
return res
|
|
||||||
|
# 单层递归逻辑
|
||||||
|
for i in range(0, len(nums)): # 从头开始搜索
|
||||||
|
# 若遇到self.path里已收录的元素,跳过
|
||||||
|
if nums[i] in self.path:
|
||||||
|
continue
|
||||||
|
self.path.append(nums[i])
|
||||||
|
self.backtracking(nums)
|
||||||
|
self.path.pop()
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
@ -381,4 +405,4 @@ int** permute(int* nums, int numsSize, int* returnSize, int** returnColumnSizes)
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -33,11 +33,11 @@
|
|||||||
**如果对回溯算法基础还不了解的话,我还特意录制了一期视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/)** 可以结合题解和视频一起看,希望对大家理解回溯算法有所帮助。
|
**如果对回溯算法基础还不了解的话,我还特意录制了一期视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/)** 可以结合题解和视频一起看,希望对大家理解回溯算法有所帮助。
|
||||||
|
|
||||||
|
|
||||||
这道题目和[回溯算法:排列问题!](https://programmercarl.com/0046.全排列.html)的区别在与**给定一个可包含重复数字的序列**,要返回**所有不重复的全排列**。
|
这道题目和[46.全排列](https://programmercarl.com/0046.全排列.html)的区别在与**给定一个可包含重复数字的序列**,要返回**所有不重复的全排列**。
|
||||||
|
|
||||||
这里又涉及到去重了。
|
这里又涉及到去重了。
|
||||||
|
|
||||||
在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html) 、[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)我们分别详细讲解了组合问题和子集问题如何去重。
|
在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html) 、[90.子集II](https://programmercarl.com/0090.子集II.html)我们分别详细讲解了组合问题和子集问题如何去重。
|
||||||
|
|
||||||
那么排列问题其实也是一样的套路。
|
那么排列问题其实也是一样的套路。
|
||||||
|
|
||||||
@ -51,11 +51,11 @@
|
|||||||
|
|
||||||
**一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果**。
|
**一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果**。
|
||||||
|
|
||||||
在[回溯算法:排列问题!](https://programmercarl.com/0046.全排列.html)中已经详解讲解了排列问题的写法,在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html) 、[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)中详细讲解的去重的写法,所以这次我就不用回溯三部曲分析了,直接给出代码,如下:
|
在[46.全排列](https://programmercarl.com/0046.全排列.html)中已经详解讲解了排列问题的写法,在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html) 、[90.子集II](https://programmercarl.com/0090.子集II.html)中详细讲解的去重的写法,所以这次我就不用回溯三部曲分析了,直接给出代码,如下:
|
||||||
|
|
||||||
## C++代码
|
## C++代码
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
vector<vector<int>> result;
|
vector<vector<int>> result;
|
||||||
@ -338,4 +338,4 @@ func backTring(nums,subRes []int,res *[][]int,used []bool){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -147,7 +147,7 @@ for (int col = 0; col < n; col++) {
|
|||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```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;
|
int count = 0;
|
||||||
// 检查列
|
// 检查列
|
||||||
@ -499,4 +499,4 @@ var solveNQueens = function(n) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -8,6 +7,7 @@
|
|||||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 52. N皇后II
|
# 52. N皇后II
|
||||||
|
|
||||||
题目链接:https://leetcode-cn.com/problems/n-queens-ii/
|
题目链接:https://leetcode-cn.com/problems/n-queens-ii/
|
||||||
@ -101,4 +101,52 @@ public:
|
|||||||
```
|
```
|
||||||
|
|
||||||
# 其他语言补充
|
# 其他语言补充
|
||||||
|
JavaScript
|
||||||
|
```javascript
|
||||||
|
var totalNQueens = function(n) {
|
||||||
|
let count = 0;
|
||||||
|
const backtracking = (n, row, chessboard) => {
|
||||||
|
if(row === n){
|
||||||
|
count++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(let col = 0; col < n; col++){
|
||||||
|
if(isValid(row, col, chessboard, n)) { // 验证合法就可以放
|
||||||
|
chessboard[row][col] = 'Q'; // 放置皇后
|
||||||
|
backtracking(n, row + 1, chessboard);
|
||||||
|
chessboard[row][col] = '.'; // 回溯
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValid = (row, col, chessboard, n) => {
|
||||||
|
// 检查列
|
||||||
|
for(let i = 0; i < row; i++){ // 这是一个剪枝
|
||||||
|
if(chessboard[i][col] === 'Q'){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 检查 45度角是否有皇后
|
||||||
|
for(let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--){
|
||||||
|
if(chessboard[i][j] === 'Q'){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 检查 135度角是否有皇后
|
||||||
|
for(let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++){
|
||||||
|
if(chessboard[i][j] === 'Q'){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const chessboard = new Array(n).fill([]).map(() => new Array(n).fill('.'));
|
||||||
|
backtracking(n, 0, chessboard);
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
-----------------------
|
||||||
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -103,6 +103,8 @@ public:
|
|||||||
|
|
||||||
当然题目没有说如果数组为空,应该返回什么,所以数组为空的话返回啥都可以了。
|
当然题目没有说如果数组为空,应该返回什么,所以数组为空的话返回啥都可以了。
|
||||||
|
|
||||||
|
不少同学认为 如果输入用例都是-1,或者 都是负数,这个贪心算法跑出来的结果是0, 这是**又一次证明脑洞模拟不靠谱的经典案例**,建议大家把代码运行一下试一试,就知道了,也会理解 为什么 result 要初始化为最小负数了。
|
||||||
|
|
||||||
## 动态规划
|
## 动态规划
|
||||||
|
|
||||||
当然本题还可以用动态规划来做,当前[「代码随想录」](https://img-blog.csdnimg.cn/20201124161234338.png)主要讲解贪心系列,后续到动态规划系列的时候会详细讲解本题的dp方法。
|
当然本题还可以用动态规划来做,当前[「代码随想录」](https://img-blog.csdnimg.cn/20201124161234338.png)主要讲解贪心系列,后续到动态规划系列的时候会详细讲解本题的dp方法。
|
||||||
@ -214,4 +216,4 @@ var maxSubArray = function(nums) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -173,7 +173,8 @@ JavaScript:
|
|||||||
```javascript
|
```javascript
|
||||||
const maxSubArray = nums => {
|
const maxSubArray = nums => {
|
||||||
// 数组长度,dp初始化
|
// 数组长度,dp初始化
|
||||||
const [len, dp] = [nums.length, [nums[0]]];
|
const len = nums.length;
|
||||||
|
let dp = new Array(len).fill(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++) {
|
||||||
@ -191,4 +192,4 @@ const maxSubArray = nums => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -161,4 +161,4 @@ var canJump = function(nums) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -241,6 +241,32 @@ var merge = function (intervals) {
|
|||||||
return result
|
return result
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
版本二:左右区间
|
||||||
|
```javascript
|
||||||
|
/**
|
||||||
|
* @param {number[][]} intervals
|
||||||
|
* @return {number[][]}
|
||||||
|
*/
|
||||||
|
var merge = function(intervals) {
|
||||||
|
let n = intervals.length;
|
||||||
|
if ( n < 2) return intervals;
|
||||||
|
intervals.sort((a, b) => a[0]- b[0]);
|
||||||
|
let res = [],
|
||||||
|
left = intervals[0][0],
|
||||||
|
right = intervals[0][1];
|
||||||
|
for (let i = 1; i < n; i++) {
|
||||||
|
if (intervals[i][0] > right) {
|
||||||
|
res.push([left, right]);
|
||||||
|
left = intervals[i][0];
|
||||||
|
right = intervals[i][1];
|
||||||
|
} else {
|
||||||
|
right = Math.max(intervals[i][1], right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.push([left, right]);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -248,4 +274,4 @@ var merge = function (intervals) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
## 59.螺旋矩阵II
|
## 59.螺旋矩阵II
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/spiral-matrix-ii/)
|
[力扣题目链接](https://leetcode-cn.com/problems/spiral-matrix-ii/)
|
||||||
给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
|
|
||||||
|
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
|
|
||||||
@ -238,45 +239,54 @@ class Solution:
|
|||||||
|
|
||||||
javaScript
|
javaScript
|
||||||
|
|
||||||
```js
|
```javascript
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} n
|
* @param {number} n
|
||||||
* @return {number[][]}
|
* @return {number[][]}
|
||||||
*/
|
*/
|
||||||
var generateMatrix = function(n) {
|
var generateMatrix = function(n) {
|
||||||
// new Array(n).fill(new Array(n))
|
let startX = startY = 0; // 起始位置
|
||||||
// 使用fill --> 填充的是同一个数组地址
|
let loop = Math.floor(n/2); // 旋转圈数
|
||||||
const res = Array.from({length: n}).map(() => new Array(n));
|
let mid = Math.floor(n/2); // 中间位置
|
||||||
let loop = n >> 1, i = 0, //循环次数
|
let offset = 1; // 控制每一层填充元素个数
|
||||||
count = 1,
|
let count = 1; // 更新填充数字
|
||||||
startX = startY = 0; // 起始位置
|
let res = new Array(n).fill(0).map(() => new Array(n).fill(0));
|
||||||
while(++i <= loop) {
|
|
||||||
// 定义行列
|
while (loop--) {
|
||||||
let row = startX, column = startY;
|
let row = startX, col = startY;
|
||||||
// [ startY, n - i)
|
// 上行从左到右(左闭右开)
|
||||||
while(column < n - i) {
|
for (; col < startY + n - offset; col++) {
|
||||||
res[row][column++] = count++;
|
res[row][col] = count++;
|
||||||
}
|
}
|
||||||
// [ startX, n - i)
|
// 右列从上到下(左闭右开)
|
||||||
while(row < n - i) {
|
for (; row < startX + n - offset; row++) {
|
||||||
res[row++][column] = count++;
|
res[row][col] = count++;
|
||||||
}
|
}
|
||||||
// [n - i , startY)
|
// 下行从右到左(左闭右开)
|
||||||
while(column > startY) {
|
for (; col > startX; col--) {
|
||||||
res[row][column--] = count++;
|
res[row][col] = count++;
|
||||||
}
|
}
|
||||||
// [n - i , startX)
|
// 左列做下到上(左闭右开)
|
||||||
while(row > startX) {
|
for (; row > startY; row--) {
|
||||||
res[row--][column] = count++;
|
res[row][col] = count++;
|
||||||
}
|
}
|
||||||
startX = ++startY;
|
|
||||||
|
// 更新起始位置
|
||||||
|
startX++;
|
||||||
|
startY++;
|
||||||
|
|
||||||
|
// 更新offset
|
||||||
|
offset += 2;
|
||||||
}
|
}
|
||||||
if(n & 1) {
|
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
|
||||||
res[startX][startY] = count;
|
if (n % 2 === 1) {
|
||||||
|
res[mid][mid] = count;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
@ -532,4 +542,4 @@ int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -327,10 +327,29 @@ var uniquePaths = function(m, n) {
|
|||||||
return dp[m - 1][n - 1]
|
return dp[m - 1][n - 1]
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
>版本二:直接将dp数值值初始化为1
|
||||||
|
```javascript
|
||||||
|
/**
|
||||||
|
* @param {number} m
|
||||||
|
* @param {number} n
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
var uniquePaths = function(m, n) {
|
||||||
|
let dp = new Array(m).fill(1).map(() => new Array(n).fill(1));
|
||||||
|
// dp[i][j] 表示到达(i,j) 点的路径数
|
||||||
|
for (let i=1; i<m; i++) {
|
||||||
|
for (let j=1; j< n;j++) {
|
||||||
|
dp[i][j]=dp[i-1][j]+dp[i][j-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[m-1][n-1];
|
||||||
|
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -341,4 +341,4 @@ var uniquePathsWithObstacles = function(obstacleGrid) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -301,4 +301,4 @@ var climbStairs = function(n) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -88,7 +88,7 @@
|
|||||||
|
|
||||||
|
|
||||||
以上分析完毕,C++代码如下:
|
以上分析完毕,C++代码如下:
|
||||||
```
|
```CPP
|
||||||
class Solution {
|
class Solution {
|
||||||
public:
|
public:
|
||||||
int climbStairs(int n) {
|
int climbStairs(int n) {
|
||||||
@ -186,10 +186,24 @@ func climbStairs(n int) int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
var climbStairs = function(n) {
|
||||||
|
const dp = new Array(n+1).fill(0);
|
||||||
|
const weight = [1,2];
|
||||||
|
dp[0] = 1;
|
||||||
|
for(let i = 0; i <= n; i++){ //先遍历背包
|
||||||
|
for(let j = 0; j < weight.length; j++){ // 再遍历物品
|
||||||
|
if(i >= weight[j]) dp[i] += dp[i-weight[j]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[n];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -51,7 +51,6 @@ exection -> execution (插入 'u')
|
|||||||
|
|
||||||
接下来我依然使用动规五部曲,对本题做一个详细的分析:
|
接下来我依然使用动规五部曲,对本题做一个详细的分析:
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
### 1. 确定dp数组(dp table)以及下标的含义
|
### 1. 确定dp数组(dp table)以及下标的含义
|
||||||
|
|
||||||
@ -61,7 +60,6 @@ exection -> execution (插入 'u')
|
|||||||
|
|
||||||
用i来表示也可以! 但我统一以下标i-1为结尾的字符串,在下面的递归公式中会容易理解一点。
|
用i来表示也可以! 但我统一以下标i-1为结尾的字符串,在下面的递归公式中会容易理解一点。
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
### 2. 确定递推公式
|
### 2. 确定递推公式
|
||||||
|
|
||||||
@ -156,7 +154,6 @@ for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
|
|||||||
for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
|
for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
|
||||||
```
|
```
|
||||||
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
### 4. 确定遍历顺序
|
### 4. 确定遍历顺序
|
||||||
|
|
||||||
@ -187,7 +184,6 @@ for (int i = 1; i <= word1.size(); i++) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
-----------------------
|
|
||||||
|
|
||||||
### 5. 举例推导dp数组
|
### 5. 举例推导dp数组
|
||||||
|
|
||||||
@ -220,7 +216,6 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
-----------------------
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
@ -338,4 +333,4 @@ const minDistance = (word1, word2) => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
也可以直接看我的B站视频:[带你学透回溯算法-组合问题(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv#reply3733925949)
|
也可以直接看我的B站视频:[带你学透回溯算法-组合问题(对应力扣题目:77.组合)](https://www.bilibili.com/video/BV1ti4y1L7cv#reply3733925949)
|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
|
|
||||||
本题这是回溯法的经典题目。
|
本题这是回溯法的经典题目。
|
||||||
@ -37,7 +37,7 @@
|
|||||||
直接的解法当然是使用for循环,例如示例中k为2,很容易想到 用两个for循环,这样就可以输出 和示例中一样的结果。
|
直接的解法当然是使用for循环,例如示例中k为2,很容易想到 用两个for循环,这样就可以输出 和示例中一样的结果。
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
```
|
```CPP
|
||||||
int n = 4;
|
int n = 4;
|
||||||
for (int i = 1; i <= n; i++) {
|
for (int i = 1; i <= n; i++) {
|
||||||
for (int j = i + 1; j <= n; j++) {
|
for (int j = i + 1; j <= n; j++) {
|
||||||
@ -49,7 +49,7 @@ for (int i = 1; i <= n; i++) {
|
|||||||
输入:n = 100, k = 3
|
输入:n = 100, k = 3
|
||||||
那么就三层for循环,代码如下:
|
那么就三层for循环,代码如下:
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
int n = 100;
|
int n = 100;
|
||||||
for (int i = 1; i <= n; i++) {
|
for (int i = 1; i <= n; i++) {
|
||||||
for (int j = i + 1; j <= n; j++) {
|
for (int j = i + 1; j <= n; j++) {
|
||||||
@ -301,7 +301,7 @@ for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜
|
|||||||
|
|
||||||
优化后整体代码如下:
|
优化后整体代码如下:
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
vector<vector<int>> result;
|
vector<vector<int>> result;
|
||||||
@ -336,10 +336,10 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
## Java:
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
List<List<Integer>> result = new ArrayList<>();
|
List<List<Integer>> result = new ArrayList<>();
|
||||||
@ -368,8 +368,54 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Python2:
|
||||||
|
```python
|
||||||
|
class Solution(object):
|
||||||
|
def combine(self, n, k):
|
||||||
|
"""
|
||||||
|
:type n: int
|
||||||
|
:type k: int
|
||||||
|
:rtype: List[List[int]]
|
||||||
|
"""
|
||||||
|
result = []
|
||||||
|
path = []
|
||||||
|
def backtracking(n, k, startidx):
|
||||||
|
if len(path) == k:
|
||||||
|
result.append(path[:])
|
||||||
|
return
|
||||||
|
|
||||||
Python:
|
# 剪枝, 最后k - len(path)个节点直接构造结果,无需递归
|
||||||
|
last_startidx = n - (k - len(path)) + 1
|
||||||
|
result.append(path + [idx for idx in range(last_startidx, n + 1)])
|
||||||
|
|
||||||
|
for x in range(startidx, last_startidx):
|
||||||
|
path.append(x)
|
||||||
|
backtracking(n, k, x + 1) # 递归
|
||||||
|
path.pop() # 回溯
|
||||||
|
|
||||||
|
backtracking(n, k, 1)
|
||||||
|
return result
|
||||||
|
```
|
||||||
|
|
||||||
|
## Python
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||||
|
res = []
|
||||||
|
path = []
|
||||||
|
def backtrack(n, k, StartIndex):
|
||||||
|
if len(path) == k:
|
||||||
|
res.append(path[:])
|
||||||
|
return
|
||||||
|
for i in range(StartIndex, n-(k-len(path)) + 2):
|
||||||
|
path.append(i)
|
||||||
|
backtrack(n, k, i+1)
|
||||||
|
path.pop()
|
||||||
|
backtrack(n, k, 1)
|
||||||
|
return res
|
||||||
|
```
|
||||||
|
|
||||||
|
剪枝:
|
||||||
```python3
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
def combine(self, n: int, k: int) -> List[List[int]]:
|
def combine(self, n: int, k: int) -> List[List[int]]:
|
||||||
@ -378,15 +424,19 @@ class Solution:
|
|||||||
def backtrack(n,k,startIndex):
|
def backtrack(n,k,startIndex):
|
||||||
if len(path) == k:
|
if len(path) == k:
|
||||||
res.append(path[:])
|
res.append(path[:])
|
||||||
return
|
return
|
||||||
for i in range(startIndex,n+1):
|
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)
|
||||||
return res
|
return res
|
||||||
```
|
```
|
||||||
javascript
|
|
||||||
|
|
||||||
|
## javascript
|
||||||
|
|
||||||
|
剪枝:
|
||||||
```javascript
|
```javascript
|
||||||
let result = []
|
let result = []
|
||||||
let path = []
|
let path = []
|
||||||
@ -406,8 +456,11 @@ const combineHelper = (n, k, startIndex) => {
|
|||||||
path.pop()
|
path.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Go:
|
|
||||||
|
|
||||||
|
|
||||||
|
## Go
|
||||||
```Go
|
```Go
|
||||||
var res [][]int
|
var res [][]int
|
||||||
func combine(n int, k int) [][]int {
|
func combine(n int, k int) [][]int {
|
||||||
@ -434,8 +487,35 @@ func backtrack(n,k,start int,track []int){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
剪枝:
|
||||||
|
```Go
|
||||||
|
var res [][]int
|
||||||
|
func combine(n int, k int) [][]int {
|
||||||
|
res=[][]int{}
|
||||||
|
if n <= 0 || k <= 0 || k > n {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
backtrack(n, k, 1, []int{})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
func backtrack(n,k,start int,track []int){
|
||||||
|
if len(track)==k{
|
||||||
|
temp:=make([]int,k)
|
||||||
|
copy(temp,track)
|
||||||
|
res=append(res,temp)
|
||||||
|
}
|
||||||
|
if len(track)+n-start+1 < k {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i:=start;i<=n;i++{
|
||||||
|
track=append(track,i)
|
||||||
|
backtrack(n,k,i+1,track)
|
||||||
|
track=track[:len(track)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
C:
|
## C
|
||||||
```c
|
```c
|
||||||
int* path;
|
int* path;
|
||||||
int pathTop;
|
int pathTop;
|
||||||
@ -489,8 +569,62 @@ int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
剪枝:
|
||||||
|
```c
|
||||||
|
int* path;
|
||||||
|
int pathTop;
|
||||||
|
int** ans;
|
||||||
|
int ansTop;
|
||||||
|
|
||||||
|
void backtracking(int n, int k,int startIndex) {
|
||||||
|
//当path中元素个数为k个时,我们需要将path数组放入ans二维数组中
|
||||||
|
if(pathTop == k) {
|
||||||
|
//path数组为我们动态申请,若直接将其地址放入二维数组,path数组中的值会随着我们回溯而逐渐变化
|
||||||
|
//因此创建新的数组存储path中的值
|
||||||
|
int* temp = (int*)malloc(sizeof(int) * k);
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < k; i++) {
|
||||||
|
temp[i] = path[i];
|
||||||
|
}
|
||||||
|
ans[ansTop++] = temp;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
int j;
|
||||||
|
for(j = startIndex; j <= n- (k - pathTop) + 1;j++) {
|
||||||
|
//将当前结点放入path数组
|
||||||
|
path[pathTop++] = j;
|
||||||
|
//进行递归
|
||||||
|
backtracking(n, k, j + 1);
|
||||||
|
//进行回溯,将数组最上层结点弹出
|
||||||
|
pathTop--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
|
||||||
|
//path数组存储符合条件的结果
|
||||||
|
path = (int*)malloc(sizeof(int) * k);
|
||||||
|
//ans二维数组存储符合条件的结果数组的集合。(数组足够大,避免极端情况)
|
||||||
|
ans = (int**)malloc(sizeof(int*) * 10000);
|
||||||
|
pathTop = ansTop = 0;
|
||||||
|
|
||||||
|
//回溯算法
|
||||||
|
backtracking(n, k, 1);
|
||||||
|
//最后的返回大小为ans数组大小
|
||||||
|
*returnSize = ansTop;
|
||||||
|
//returnColumnSizes数组存储ans二维数组对应下标中一维数组的长度(都为k)
|
||||||
|
*returnColumnSizes = (int*)malloc(sizeof(int) *(*returnSize));
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < *returnSize; i++) {
|
||||||
|
(*returnColumnSizes)[i] = k;
|
||||||
|
}
|
||||||
|
//返回ans二维数组
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
大家先回忆一下[77. 组合]给出的回溯法的代码:
|
大家先回忆一下[77. 组合]给出的回溯法的代码:
|
||||||
|
|
||||||
```
|
```c++
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
vector<vector<int>> result; // 存放符合条件结果的集合
|
vector<vector<int>> result; // 存放符合条件结果的集合
|
||||||
@ -54,7 +54,7 @@ public:
|
|||||||
|
|
||||||
在遍历的过程中有如下代码:
|
在遍历的过程中有如下代码:
|
||||||
|
|
||||||
```
|
```c++
|
||||||
for (int i = startIndex; i <= n; i++) {
|
for (int i = startIndex; i <= n; i++) {
|
||||||
path.push_back(i);
|
path.push_back(i);
|
||||||
backtracking(n, k, i + 1);
|
backtracking(n, k, i + 1);
|
||||||
@ -78,7 +78,7 @@ for (int i = startIndex; i <= n; i++) {
|
|||||||
**如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了**。
|
**如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了**。
|
||||||
|
|
||||||
注意代码中i,就是for循环里选择的起始位置。
|
注意代码中i,就是for循环里选择的起始位置。
|
||||||
```
|
```c++
|
||||||
for (int i = startIndex; i <= n; i++) {
|
for (int i = startIndex; i <= n; i++) {
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -100,13 +100,13 @@ for (int i = startIndex; i <= n; i++) {
|
|||||||
|
|
||||||
所以优化之后的for循环是:
|
所以优化之后的for循环是:
|
||||||
|
|
||||||
```
|
```c++
|
||||||
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置
|
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置
|
||||||
```
|
```
|
||||||
|
|
||||||
优化后整体代码如下:
|
优化后整体代码如下:
|
||||||
|
|
||||||
```
|
```c++
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
vector<vector<int>> result;
|
vector<vector<int>> result;
|
||||||
@ -300,4 +300,4 @@ int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
## 第78题. 子集
|
# 78.子集
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/subsets/)
|
[力扣题目链接](https://leetcode-cn.com/problems/subsets/)
|
||||||
|
|
||||||
@ -29,9 +29,9 @@
|
|||||||
[]
|
[]
|
||||||
]
|
]
|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
求子集问题和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:分割问题!](https://programmercarl.com/0131.分割回文串.html)又不一样了。
|
求子集问题和[77.组合](https://programmercarl.com/0077.组合.html)和[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)又不一样了。
|
||||||
|
|
||||||
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,**那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!**
|
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,**那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!**
|
||||||
|
|
||||||
@ -153,19 +153,19 @@ public:
|
|||||||
|
|
||||||
并不会,因为每次递归的下一层就是从i+1开始的。
|
并不会,因为每次递归的下一层就是从i+1开始的。
|
||||||
|
|
||||||
## 总结
|
# 总结
|
||||||
|
|
||||||
相信大家经过了
|
相信大家经过了
|
||||||
* 组合问题:
|
* 组合问题:
|
||||||
* [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)
|
* [77.组合](https://programmercarl.com/0077.组合.html)
|
||||||
* [回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html)
|
* [回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html)
|
||||||
* [回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)
|
* [216.组合总和III](https://programmercarl.com/0216.组合总和III.html)
|
||||||
* [回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)
|
* [17.电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)
|
||||||
* [回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)
|
* [39.组合总和](https://programmercarl.com/0039.组合总和.html)
|
||||||
* [回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)
|
* [40.组合总和II](https://programmercarl.com/0040.组合总和II.html)
|
||||||
* 分割问题:
|
* 分割问题:
|
||||||
* [回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)
|
* [131.分割回文串](https://programmercarl.com/0131.分割回文串.html)
|
||||||
* [回溯算法:复原IP地址](https://programmercarl.com/0093.复原IP地址.html)
|
* [93.复原IP地址](https://programmercarl.com/0093.复原IP地址.html)
|
||||||
|
|
||||||
洗礼之后,发现子集问题还真的有点简单了,其实这就是一道标准的模板题。
|
洗礼之后,发现子集问题还真的有点简单了,其实这就是一道标准的模板题。
|
||||||
|
|
||||||
@ -173,10 +173,10 @@ public:
|
|||||||
|
|
||||||
**而组合问题、分割问题是收集树形结构中叶子节点的结果**。
|
**而组合问题、分割问题是收集树形结构中叶子节点的结果**。
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
## Java
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
|
List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
|
||||||
@ -204,23 +204,34 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
## Python
|
||||||
```python3
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
|
def __init__(self):
|
||||||
|
self.path: List[int] = []
|
||||||
|
self.paths: List[List[int]] = []
|
||||||
|
|
||||||
def subsets(self, nums: List[int]) -> List[List[int]]:
|
def subsets(self, nums: List[int]) -> List[List[int]]:
|
||||||
res = []
|
self.paths.clear()
|
||||||
path = []
|
self.path.clear()
|
||||||
def backtrack(nums,startIndex):
|
self.backtracking(nums, 0)
|
||||||
res.append(path[:]) #收集子集,要放在终止添加的上面,否则会漏掉自己
|
return self.paths
|
||||||
for i in range(startIndex,len(nums)): #当startIndex已经大于数组的长度了,就终止了,for循环本来也结束了,所以不需要终止条件
|
|
||||||
path.append(nums[i])
|
def backtracking(self, nums: List[int], start_index: int) -> None:
|
||||||
backtrack(nums,i+1) #递归
|
# 收集子集,要先于终止判断
|
||||||
path.pop() #回溯
|
self.paths.append(self.path[:])
|
||||||
backtrack(nums,0)
|
# Base Case
|
||||||
return res
|
if start_index == len(nums):
|
||||||
|
return
|
||||||
|
|
||||||
|
# 单层递归逻辑
|
||||||
|
for i in range(start_index, len(nums)):
|
||||||
|
self.path.append(nums[i])
|
||||||
|
self.backtracking(nums, i+1)
|
||||||
|
self.path.pop() # 回溯
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
## Go
|
||||||
```Go
|
```Go
|
||||||
var res [][]int
|
var res [][]int
|
||||||
func subset(nums []int) [][]int {
|
func subset(nums []int) [][]int {
|
||||||
@ -244,7 +255,7 @@ func Dfs(temp, nums []int, start int){
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Javascript:
|
## Javascript:
|
||||||
|
|
||||||
```Javascript
|
```Javascript
|
||||||
var subsets = function(nums) {
|
var subsets = function(nums) {
|
||||||
@ -263,7 +274,7 @@ var subsets = function(nums) {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
C:
|
## C
|
||||||
```c
|
```c
|
||||||
int* path;
|
int* path;
|
||||||
int pathTop;
|
int pathTop;
|
||||||
@ -325,4 +336,4 @@ int** subsets(int* nums, int numsSize, int* returnSize, int** returnColumnSizes)
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
|
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||||
|
</p>
|
||||||
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
# 84.柱状图中最大的矩形
|
# 84.柱状图中最大的矩形
|
||||||
@ -228,53 +235,261 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
单调栈
|
||||||
|
```java
|
||||||
|
class Solution {
|
||||||
|
int largestRectangleArea(int[] heights) {
|
||||||
|
Stack<Integer> st = new Stack<Integer>();
|
||||||
|
|
||||||
|
// 数组扩容,在头和尾各加入一个元素
|
||||||
|
int [] newHeights = new int[heights.length + 2];
|
||||||
|
newHeights[0] = 0;
|
||||||
|
newHeights[newHeights.length - 1] = 0;
|
||||||
|
for (int index = 0; index < heights.length; index++){
|
||||||
|
newHeights[index + 1] = heights[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
heights = newHeights;
|
||||||
|
|
||||||
|
st.push(0);
|
||||||
|
int result = 0;
|
||||||
|
// 第一个元素已经入栈,从下表1开始
|
||||||
|
for (int i = 1; i < heights.length; i++) {
|
||||||
|
// 注意heights[i] 是和heights[st.top()] 比较 ,st.top()是下表
|
||||||
|
if (heights[i] > heights[st.peek()]) {
|
||||||
|
st.push(i);
|
||||||
|
} else if (heights[i] == heights[st.peek()]) {
|
||||||
|
st.pop(); // 这个可以加,可以不加,效果一样,思路不同
|
||||||
|
st.push(i);
|
||||||
|
} else {
|
||||||
|
while (heights[i] < heights[st.peek()]) { // 注意是while
|
||||||
|
int mid = st.peek();
|
||||||
|
st.pop();
|
||||||
|
int left = st.peek();
|
||||||
|
int right = i;
|
||||||
|
int w = right - left - 1;
|
||||||
|
int h = heights[mid];
|
||||||
|
result = Math.max(result, w * h);
|
||||||
|
}
|
||||||
|
st.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
动态规划
|
|
||||||
```python3
|
```python3
|
||||||
class Solution:
|
|
||||||
def largestRectangleArea(self, heights: List[int]) -> int:
|
|
||||||
result = 0
|
|
||||||
minleftindex, minrightindex = [0]*len(heights), [0]*len(heights)
|
|
||||||
|
|
||||||
minleftindex[0]=-1
|
|
||||||
for i in range(1,len(heights)):
|
|
||||||
t = i-1
|
|
||||||
while t>=0 and heights[t]>=heights[i]: t=minleftindex[t]
|
|
||||||
minleftindex[i]=t
|
|
||||||
|
|
||||||
minrightindex[-1]=len(heights)
|
|
||||||
for i in range(len(heights)-2,-1,-1):
|
|
||||||
t=i+1
|
|
||||||
while t<len(heights) and heights[t]>=heights[i]: t=minrightindex[t]
|
|
||||||
minrightindex[i]=t
|
|
||||||
|
|
||||||
for i in range(0,len(heights)):
|
|
||||||
left = minleftindex[i]
|
|
||||||
right = minrightindex[i]
|
|
||||||
summ = (right-left-1)*heights[i]
|
|
||||||
result = max(result,summ)
|
|
||||||
return result
|
|
||||||
```
|
|
||||||
单调栈 版本二
|
|
||||||
```python3
|
|
||||||
class Solution:
|
|
||||||
def largestRectangleArea(self, heights: List[int]) -> int:
|
|
||||||
heights.insert(0,0) # 数组头部加入元素0
|
|
||||||
heights.append(0) # 数组尾部加入元素0
|
|
||||||
st = [0]
|
|
||||||
result = 0
|
|
||||||
for i in range(1,len(heights)):
|
|
||||||
while st!=[] and heights[i]<heights[st[-1]]:
|
|
||||||
midh = heights[st[-1]]
|
|
||||||
st.pop()
|
|
||||||
if st!=[]:
|
|
||||||
minrightindex = i
|
|
||||||
minleftindex = st[-1]
|
|
||||||
summ = (minrightindex-minleftindex-1)*midh
|
|
||||||
result = max(summ,result)
|
|
||||||
st.append(i)
|
|
||||||
return result
|
|
||||||
```
|
|
||||||
|
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
# 双指针;暴力解法(leetcode超时)
|
||||||
|
class Solution:
|
||||||
|
def largestRectangleArea(self, heights: List[int]) -> int:
|
||||||
|
# 从左向右遍历:以每一根柱子为主心骨(当前轮最高的参照物),迭代直到找到左侧和右侧各第一个矮一级的柱子
|
||||||
|
res = 0
|
||||||
|
|
||||||
|
for i in range(len(heights)):
|
||||||
|
left = i
|
||||||
|
right = i
|
||||||
|
# 向左侧遍历:寻找第一个矮一级的柱子
|
||||||
|
for _ in range(left, -1, -1):
|
||||||
|
if heights[left] < heights[i]:
|
||||||
|
break
|
||||||
|
left -= 1
|
||||||
|
# 向右侧遍历:寻找第一个矮一级的柱子
|
||||||
|
for _ in range(right, len(heights)):
|
||||||
|
if heights[right] < heights[i]:
|
||||||
|
break
|
||||||
|
right += 1
|
||||||
|
|
||||||
|
width = right - left - 1
|
||||||
|
height = heights[i]
|
||||||
|
res = max(res, width * height)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
# DP动态规划
|
||||||
|
class Solution:
|
||||||
|
def largestRectangleArea(self, heights: List[int]) -> int:
|
||||||
|
size = len(heights)
|
||||||
|
# 两个DP数列储存的均是下标index
|
||||||
|
min_left_index = [0] * size
|
||||||
|
min_right_index = [0] * size
|
||||||
|
result = 0
|
||||||
|
|
||||||
|
# 记录每个柱子的左侧第一个矮一级的柱子的下标
|
||||||
|
min_left_index[0] = -1 # 初始化防止while死循环
|
||||||
|
for i in range(1, size):
|
||||||
|
# 以当前柱子为主心骨,向左迭代寻找次级柱子
|
||||||
|
temp = i - 1
|
||||||
|
while temp >= 0 and heights[temp] >= heights[i]:
|
||||||
|
# 当左侧的柱子持续较高时,尝试这个高柱子自己的次级柱子(DP
|
||||||
|
temp = min_left_index[temp]
|
||||||
|
# 当找到左侧矮一级的目标柱子时
|
||||||
|
min_left_index[i] = temp
|
||||||
|
|
||||||
|
# 记录每个柱子的右侧第一个矮一级的柱子的下标
|
||||||
|
min_right_index[size-1] = size # 初始化防止while死循环
|
||||||
|
for i in range(size-2, -1, -1):
|
||||||
|
# 以当前柱子为主心骨,向右迭代寻找次级柱子
|
||||||
|
temp = i + 1
|
||||||
|
while temp < size and heights[temp] >= heights[i]:
|
||||||
|
# 当右侧的柱子持续较高时,尝试这个高柱子自己的次级柱子(DP
|
||||||
|
temp = min_right_index[temp]
|
||||||
|
# 当找到右侧矮一级的目标柱子时
|
||||||
|
min_right_index[i] = temp
|
||||||
|
|
||||||
|
for i in range(size):
|
||||||
|
area = heights[i] * (min_right_index[i] - min_left_index[i] - 1)
|
||||||
|
result = max(area, result)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 单调栈
|
||||||
|
class Solution:
|
||||||
|
def largestRectangleArea(self, heights: List[int]) -> int:
|
||||||
|
# Monotonic Stack
|
||||||
|
'''
|
||||||
|
找每个柱子左右侧的第一个高度值小于该柱子的柱子
|
||||||
|
单调栈:栈顶到栈底:从大到小(每插入一个新的小数值时,都要弹出先前的大数值)
|
||||||
|
栈顶,栈顶的下一个元素,即将入栈的元素:这三个元素组成了最大面积的高度和宽度
|
||||||
|
情况一:当前遍历的元素heights[i]大于栈顶元素的情况
|
||||||
|
情况二:当前遍历的元素heights[i]等于栈顶元素的情况
|
||||||
|
情况三:当前遍历的元素heights[i]小于栈顶元素的情况
|
||||||
|
'''
|
||||||
|
|
||||||
|
# 输入数组首尾各补上一个0(与42.接雨水不同的是,本题原首尾的两个柱子可以作为核心柱进行最大面积尝试
|
||||||
|
heights.insert(0, 0)
|
||||||
|
heights.append(0)
|
||||||
|
stack = [0]
|
||||||
|
result = 0
|
||||||
|
for i in range(1, len(heights)):
|
||||||
|
# 情况一
|
||||||
|
if heights[i] > heights[stack[-1]]:
|
||||||
|
stack.append(i)
|
||||||
|
# 情况二
|
||||||
|
elif heights[i] == heights[stack[-1]]:
|
||||||
|
stack.pop()
|
||||||
|
stack.append(i)
|
||||||
|
# 情况三
|
||||||
|
else:
|
||||||
|
# 抛出所有较高的柱子
|
||||||
|
while stack and heights[i] < heights[stack[-1]]:
|
||||||
|
# 栈顶就是中间的柱子,主心骨
|
||||||
|
mid_index = stack[-1]
|
||||||
|
stack.pop()
|
||||||
|
if stack:
|
||||||
|
left_index = stack[-1]
|
||||||
|
right_index = i
|
||||||
|
width = right_index - left_index - 1
|
||||||
|
height = heights[mid_index]
|
||||||
|
result = max(result, width * height)
|
||||||
|
stack.append(i)
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 单调栈精简
|
||||||
|
class Solution:
|
||||||
|
def largestRectangleArea(self, heights: List[int]) -> int:
|
||||||
|
heights.insert(0, 0)
|
||||||
|
heights.append(0)
|
||||||
|
stack = [0]
|
||||||
|
result = 0
|
||||||
|
for i in range(1, len(heights)):
|
||||||
|
while stack and heights[i] < heights[stack[-1]]:
|
||||||
|
mid_height = heights[stack[-1]]
|
||||||
|
stack.pop()
|
||||||
|
if stack:
|
||||||
|
# area = width * height
|
||||||
|
area = (i - stack[-1] - 1) * mid_height
|
||||||
|
result = max(area, result)
|
||||||
|
stack.append(i)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
*****
|
||||||
|
|
||||||
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
//动态规划 js中运行速度最快
|
||||||
|
var largestRectangleArea = function(heights) {
|
||||||
|
const len = heights.length;
|
||||||
|
const minLeftIndex = new Array(len);
|
||||||
|
const maxRigthIndex = new Array(len);
|
||||||
|
// 记录每个柱子 左边第一个小于该柱子的下标
|
||||||
|
minLeftIndex[0] = -1; // 注意这里初始化,防止下面while死循环
|
||||||
|
for(let i = 1; i < len; i++) {
|
||||||
|
let t = i - 1;
|
||||||
|
// 这里不是用if,而是不断向左寻找的过程
|
||||||
|
while(t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
|
||||||
|
minLeftIndex[i] = t;
|
||||||
|
}
|
||||||
|
// 记录每个柱子 右边第一个小于该柱子的下标
|
||||||
|
maxRigthIndex[len - 1] = len; // 注意这里初始化,防止下面while死循环
|
||||||
|
for(let i = len - 2; i >= 0; i--){
|
||||||
|
let t = i + 1;
|
||||||
|
// 这里不是用if,而是不断向右寻找的过程
|
||||||
|
while(t < len && heights[t] >= heights[i]) t = maxRigthIndex[t];
|
||||||
|
maxRigthIndex[i] = t;
|
||||||
|
}
|
||||||
|
// 求和
|
||||||
|
let maxArea = 0;
|
||||||
|
for(let i = 0; i < len; i++){
|
||||||
|
let sum = heights[i] * (maxRigthIndex[i] - minLeftIndex[i] - 1);
|
||||||
|
maxArea = Math.max(maxArea , sum);
|
||||||
|
}
|
||||||
|
return maxArea;
|
||||||
|
};
|
||||||
|
|
||||||
|
//单调栈
|
||||||
|
var largestRectangleArea = function(heights) {
|
||||||
|
let maxArea = 0;
|
||||||
|
const stack = [];
|
||||||
|
heights = [0,...heights,0]; // 数组头部加入元素0 数组尾部加入元素0
|
||||||
|
for(let i = 0; i < heights.length; i++){
|
||||||
|
if(heights[i] > heights[stack[stack.length-1]]){ // 情况三
|
||||||
|
stack.push(i);
|
||||||
|
} else if(heights[i] === heights[stack[stack.length-1]]){ // 情况二
|
||||||
|
stack.pop(); // 这个可以加,可以不加,效果一样,思路不同
|
||||||
|
stack.push(i);
|
||||||
|
} else { // 情况一
|
||||||
|
while(heights[i] < heights[stack[stack.length-1]]){// 当前bar比栈顶bar矮
|
||||||
|
const stackTopIndex = stack.pop();// 栈顶元素出栈,并保存栈顶bar的索引
|
||||||
|
let w = i - stack[stack.length -1] - 1;
|
||||||
|
let h = heights[stackTopIndex]
|
||||||
|
// 计算面积,并取最大面积
|
||||||
|
maxArea = Math.max(maxArea, w * h);
|
||||||
|
}
|
||||||
|
stack.push(i);// 当前bar比栈顶bar高了,入栈
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxArea;
|
||||||
|
};
|
||||||
|
|
||||||
|
//单调栈 简洁
|
||||||
|
var largestRectangleArea = function(heights) {
|
||||||
|
let maxArea = 0;
|
||||||
|
const stack = [];
|
||||||
|
heights = [0,...heights,0]; // 数组头部加入元素0 数组尾部加入元素0
|
||||||
|
for(let i = 0; i < heights.length; i++){ // 只用考虑情况一 当前遍历的元素heights[i]小于栈顶元素heights[stack[stack.length-1]]]的情况
|
||||||
|
while(heights[i] < heights[stack[stack.length-1]]){// 当前bar比栈顶bar矮
|
||||||
|
const stackTopIndex = stack.pop();// 栈顶元素出栈,并保存栈顶bar的索引
|
||||||
|
let w = i - stack[stack.length -1] - 1;
|
||||||
|
let h = heights[stackTopIndex]
|
||||||
|
// 计算面积,并取最大面积
|
||||||
|
maxArea = Math.max(maxArea, w * h);
|
||||||
|
}
|
||||||
|
stack.push(i);// 当前bar比栈顶bar高了,入栈
|
||||||
|
}
|
||||||
|
return maxArea;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
-----------------------
|
||||||
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
做本题之前一定要先做[78.子集](https://programmercarl.com/0078.子集.html)。
|
做本题之前一定要先做[78.子集](https://programmercarl.com/0078.子集.html)。
|
||||||
|
|
||||||
这道题目和[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)区别就是集合里有重复元素了,而且求取的子集要去重。
|
这道题目和[78.子集](https://programmercarl.com/0078.子集.html)区别就是集合里有重复元素了,而且求取的子集要去重。
|
||||||
|
|
||||||
那么关于回溯算法中的去重问题,**在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html)中已经详细讲解过了,和本题是一个套路**。
|
那么关于回溯算法中的去重问题,**在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html)中已经详细讲解过了,和本题是一个套路**。
|
||||||
|
|
||||||
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
## C++代码
|
## C++代码
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
vector<vector<int>> result;
|
vector<vector<int>> result;
|
||||||
@ -83,7 +83,7 @@ public:
|
|||||||
```
|
```
|
||||||
|
|
||||||
使用set去重的版本。
|
使用set去重的版本。
|
||||||
```c++
|
```CPP
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
vector<vector<int>> result;
|
vector<vector<int>> result;
|
||||||
@ -207,20 +207,30 @@ class Solution {
|
|||||||
Python:
|
Python:
|
||||||
```python3
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
|
def __init__(self):
|
||||||
|
self.paths = []
|
||||||
|
self.path = []
|
||||||
|
|
||||||
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
|
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
|
||||||
res = [] #存放符合条件结果的集合
|
nums.sort()
|
||||||
path = [] #用来存放符合条件结果
|
self.backtracking(nums, 0)
|
||||||
def backtrack(nums,startIndex):
|
return self.paths
|
||||||
res.append(path[:])
|
|
||||||
for i in range(startIndex,len(nums)):
|
def backtracking(self, nums: List[int], start_index: int) -> None:
|
||||||
if i > startIndex and nums[i] == nums[i - 1]: #我们要对同一树层使用过的元素进行跳过
|
# ps.空集合仍符合要求
|
||||||
continue
|
self.paths.append(self.path[:])
|
||||||
path.append(nums[i])
|
# Base Case
|
||||||
backtrack(nums,i+1) #递归
|
if start_index == len(nums):
|
||||||
path.pop() #回溯
|
return
|
||||||
nums = sorted(nums) #去重需要排序
|
|
||||||
backtrack(nums,0)
|
# 单层递归逻辑
|
||||||
return res
|
for i in range(start_index, len(nums)):
|
||||||
|
if i > start_index and nums[i] == nums[i-1]:
|
||||||
|
# 当前后元素值相同时,跳入下一个循环,去重
|
||||||
|
continue
|
||||||
|
self.path.append(nums[i])
|
||||||
|
self.backtracking(nums, i+1)
|
||||||
|
self.path.pop()
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
@ -353,4 +363,4 @@ int** subsetsWithDup(int* nums, int numsSize, int* returnSize, int** returnColum
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 93.复原IP地址
|
# 93.复原IP地址
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/restore-ip-addresses/)
|
[力扣题目链接](https://leetcode-cn.com/problems/restore-ip-addresses/)
|
||||||
|
|
||||||
@ -19,37 +19,37 @@
|
|||||||
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效的 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效的 IP 地址。
|
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效的 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效的 IP 地址。
|
||||||
|
|
||||||
示例 1:
|
示例 1:
|
||||||
输入:s = "25525511135"
|
* 输入:s = "25525511135"
|
||||||
输出:["255.255.11.135","255.255.111.35"]
|
* 输出:["255.255.11.135","255.255.111.35"]
|
||||||
|
|
||||||
示例 2:
|
示例 2:
|
||||||
输入:s = "0000"
|
* 输入:s = "0000"
|
||||||
输出:["0.0.0.0"]
|
* 输出:["0.0.0.0"]
|
||||||
|
|
||||||
示例 3:
|
示例 3:
|
||||||
输入:s = "1111"
|
* 输入:s = "1111"
|
||||||
输出:["1.1.1.1"]
|
* 输出:["1.1.1.1"]
|
||||||
|
|
||||||
示例 4:
|
示例 4:
|
||||||
输入:s = "010010"
|
* 输入:s = "010010"
|
||||||
输出:["0.10.0.10","0.100.1.0"]
|
* 输出:["0.10.0.10","0.100.1.0"]
|
||||||
|
|
||||||
示例 5:
|
示例 5:
|
||||||
输入:s = "101023"
|
* 输入:s = "101023"
|
||||||
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
|
* 输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
|
||||||
|
|
||||||
提示:
|
提示:
|
||||||
0 <= s.length <= 3000
|
* 0 <= s.length <= 3000
|
||||||
s 仅由数字组成
|
* s 仅由数字组成
|
||||||
|
|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
做这道题目之前,最好先把[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)这个做了。
|
做这道题目之前,最好先把[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)这个做了。
|
||||||
|
|
||||||
这道题目相信大家刚看的时候,应该会一脸茫然。
|
这道题目相信大家刚看的时候,应该会一脸茫然。
|
||||||
|
|
||||||
其实只要意识到这是切割问题,**切割问题就可以使用回溯搜索法把所有可能性搜出来**,和刚做过的[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)就十分类似了。
|
其实只要意识到这是切割问题,**切割问题就可以使用回溯搜索法把所有可能性搜出来**,和刚做过的[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)就十分类似了。
|
||||||
|
|
||||||
切割问题可以抽象为树型结构,如图:
|
切割问题可以抽象为树型结构,如图:
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ s 仅由数字组成
|
|||||||
|
|
||||||
* 递归参数
|
* 递归参数
|
||||||
|
|
||||||
在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中我们就提到切割问题类似组合问题。
|
在[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)中我们就提到切割问题类似组合问题。
|
||||||
|
|
||||||
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
|
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ startIndex一定是需要的,因为不能重复分割,记录下一层递归
|
|||||||
|
|
||||||
* 递归终止条件
|
* 递归终止条件
|
||||||
|
|
||||||
终止条件和[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
|
终止条件和[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
|
||||||
|
|
||||||
pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
|
pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ if (pointNum == 3) { // 逗点数量为3时,分隔结束
|
|||||||
|
|
||||||
* 单层搜索的逻辑
|
* 单层搜索的逻辑
|
||||||
|
|
||||||
在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中已经讲过在循环遍历中如何截取子串。
|
在[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)中已经讲过在循环遍历中如何截取子串。
|
||||||
|
|
||||||
在`for (int i = startIndex; i < s.size(); i++)`循环中 [startIndex, i]这个区间就是截取的子串,需要判断这个子串是否合法。
|
在`for (int i = startIndex; i < s.size(); i++)`循环中 [startIndex, i]这个区间就是截取的子串,需要判断这个子串是否合法。
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ if (pointNum == 3) { // 逗点数量为3时,分隔结束
|
|||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
for (int i = startIndex; i < s.size(); i++) {
|
for (int i = startIndex; i < s.size(); i++) {
|
||||||
if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的子串是否合法
|
if (isValid(s, startIndex, i)) { // 判断 [startIndex,i] 这个区间的子串是否合法
|
||||||
s.insert(s.begin() + i + 1 , '.'); // 在i的后面插入一个逗点
|
s.insert(s.begin() + i + 1 , '.'); // 在i的后面插入一个逗点
|
||||||
@ -138,7 +138,7 @@ for (int i = startIndex; i < s.size(); i++) {
|
|||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
// 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法
|
// 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法
|
||||||
bool isValid(const string& s, int start, int end) {
|
bool isValid(const string& s, int start, int end) {
|
||||||
if (start > end) {
|
if (start > end) {
|
||||||
@ -237,21 +237,21 @@ public:
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 总结
|
# 总结
|
||||||
|
|
||||||
在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中我列举的分割字符串的难点,本题都覆盖了。
|
在[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)中我列举的分割字符串的难点,本题都覆盖了。
|
||||||
|
|
||||||
而且本题还需要操作字符串添加逗号作为分隔符,并验证区间的合法性。
|
而且本题还需要操作字符串添加逗号作为分隔符,并验证区间的合法性。
|
||||||
|
|
||||||
可以说是[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)的加强版。
|
可以说是[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)的加强版。
|
||||||
|
|
||||||
在本文的树形结构图中,我已经把详细的分析思路都画了出来,相信大家看了之后一定会思路清晰不少!
|
在本文的树形结构图中,我已经把详细的分析思路都画了出来,相信大家看了之后一定会思路清晰不少!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
java 版本:
|
## java
|
||||||
|
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
@ -308,7 +308,9 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
python版本:
|
## python
|
||||||
|
|
||||||
|
python2:
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def restoreIpAddresses(self, s: str) -> List[str]:
|
def restoreIpAddresses(self, s: str) -> List[str]:
|
||||||
@ -338,75 +340,53 @@ class Solution:
|
|||||||
backtrack(s, 0)
|
backtrack(s, 0)
|
||||||
return res
|
return res
|
||||||
```
|
```
|
||||||
```python
|
|
||||||
class Solution(object):
|
|
||||||
def restoreIpAddresses(self, s):
|
|
||||||
"""
|
|
||||||
:type s: str
|
|
||||||
:rtype: List[str]
|
|
||||||
"""
|
|
||||||
ans = []
|
|
||||||
path = []
|
|
||||||
def backtrack(path, startIndex):
|
|
||||||
if len(path) == 4:
|
|
||||||
if startIndex == len(s):
|
|
||||||
ans.append(".".join(path[:]))
|
|
||||||
return
|
|
||||||
for i in range(startIndex+1, min(startIndex+4, len(s)+1)): # 剪枝
|
|
||||||
string = s[startIndex:i]
|
|
||||||
if not 0 <= int(string) <= 255:
|
|
||||||
continue
|
|
||||||
if not string == "0" and not string.lstrip('0') == string:
|
|
||||||
continue
|
|
||||||
path.append(string)
|
|
||||||
backtrack(path, i)
|
|
||||||
path.pop()
|
|
||||||
|
|
||||||
backtrack([], 0)
|
|
||||||
return ans```
|
|
||||||
```
|
|
||||||
|
|
||||||
|
python3:
|
||||||
```python3
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
def __init__(self) -> None:
|
def __init__(self):
|
||||||
self.s = ""
|
self.result = []
|
||||||
self.res = []
|
|
||||||
|
|
||||||
def isVaild(self, s: str) -> bool:
|
|
||||||
if len(s) > 1 and s[0] == "0":
|
|
||||||
return False
|
|
||||||
|
|
||||||
if 0 <= int(s) <= 255:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def backTrack(self, path: List[str], start: int) -> None:
|
|
||||||
if start == len(self.s) and len(path) == 4:
|
|
||||||
self.res.append(".".join(path))
|
|
||||||
return
|
|
||||||
|
|
||||||
for end in range(start + 1, len(self.s) + 1):
|
|
||||||
# 剪枝
|
|
||||||
# 保证切割完,s没有剩余的字符。
|
|
||||||
if len(self.s) - end > 3 * (4 - len(path) - 1):
|
|
||||||
continue
|
|
||||||
if self.isVaild(self.s[start:end]):
|
|
||||||
# 在参数处,更新状态,实则创建一个新的变量
|
|
||||||
# 不会影响当前的状态,当前的path变量没有改变
|
|
||||||
# 因此递归完不用path.pop()
|
|
||||||
self.backTrack(path + [self.s[start:end]], end)
|
|
||||||
|
|
||||||
def restoreIpAddresses(self, s: str) -> List[str]:
|
def restoreIpAddresses(self, s: str) -> List[str]:
|
||||||
# prune
|
'''
|
||||||
if len(s) > 3 * 4:
|
本质切割问题使用回溯搜索法,本题只能切割三次,所以纵向递归总共四层
|
||||||
return []
|
因为不能重复分割,所以需要start_index来记录下一层递归分割的起始位置
|
||||||
self.s = s
|
添加变量point_num来记录逗号的数量[0,3]
|
||||||
self.backTrack([], 0)
|
'''
|
||||||
return self.res
|
self.result.clear()
|
||||||
|
if len(s) > 12: return []
|
||||||
|
self.backtracking(s, 0, 0)
|
||||||
|
return self.result
|
||||||
|
|
||||||
|
def backtracking(self, s: str, start_index: int, point_num: int) -> None:
|
||||||
|
# Base Case
|
||||||
|
if point_num == 3:
|
||||||
|
if self.is_valid(s, start_index, len(s)-1):
|
||||||
|
self.result.append(s[:])
|
||||||
|
return
|
||||||
|
# 单层递归逻辑
|
||||||
|
for i in range(start_index, len(s)):
|
||||||
|
# [start_index, i]就是被截取的子串
|
||||||
|
if self.is_valid(s, start_index, i):
|
||||||
|
s = s[:i+1] + '.' + s[i+1:]
|
||||||
|
self.backtracking(s, i+2, point_num+1) # 在填入.后,下一子串起始后移2位
|
||||||
|
s = s[:i+1] + s[i+2:] # 回溯
|
||||||
|
else:
|
||||||
|
# 若当前被截取的子串大于255或者大于三位数,直接结束本层循环
|
||||||
|
break
|
||||||
|
|
||||||
|
def is_valid(self, s: str, start: int, end: int) -> bool:
|
||||||
|
if start > end: return False
|
||||||
|
# 若数字是0开头,不合法
|
||||||
|
if s[start] == '0' and start != end:
|
||||||
|
return False
|
||||||
|
if not 0 <= int(s[start:end+1]) <= 255:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
```
|
```
|
||||||
|
|
||||||
JavaScript:
|
|
||||||
|
## JavaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
/**
|
/**
|
||||||
@ -435,8 +415,10 @@ var restoreIpAddresses = function(s) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
Go:
|
|
||||||
> 回溯(对于前导 0的IP(特别注意s[startIndex]=='0'的判断,不应该写成s[startIndex]==0,因为s截取出来不是数字))
|
## Go
|
||||||
|
|
||||||
|
回溯(对于前导 0的IP(特别注意s[startIndex]=='0'的判断,不应该写成s[startIndex]==0,因为s截取出来不是数字))
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func restoreIpAddresses(s string) []string {
|
func restoreIpAddresses(s string) []string {
|
||||||
@ -476,7 +458,7 @@ func isNormalIp(s string,startIndex,end int)bool{
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
C:
|
## C
|
||||||
```c
|
```c
|
||||||
//记录结果
|
//记录结果
|
||||||
char** result;
|
char** result;
|
||||||
@ -557,4 +539,4 @@ char ** restoreIpAddresses(char * s, int* returnSize){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -234,4 +234,4 @@ const numTrees =(n) => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -529,4 +529,4 @@ var isValidBST = function (root) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -8,6 +7,7 @@
|
|||||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 100. 相同的树
|
# 100. 相同的树
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/same-tree/)
|
[力扣题目链接](https://leetcode-cn.com/problems/same-tree/)
|
||||||
@ -242,9 +242,9 @@ Go:
|
|||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -185,7 +185,8 @@ public:
|
|||||||
queue<TreeNode*> que;
|
queue<TreeNode*> que;
|
||||||
que.push(root->left); // 将左子树头结点加入队列
|
que.push(root->left); // 将左子树头结点加入队列
|
||||||
que.push(root->right); // 将右子树头结点加入队列
|
que.push(root->right); // 将右子树头结点加入队列
|
||||||
while (!que.empty()) { // 接下来就要判断这这两个树是否相互翻转
|
|
||||||
|
while (!que.empty()) { // 接下来就要判断这两个树是否相互翻转
|
||||||
TreeNode* leftNode = que.front(); que.pop();
|
TreeNode* leftNode = que.front(); que.pop();
|
||||||
TreeNode* rightNode = que.front(); que.pop();
|
TreeNode* rightNode = que.front(); que.pop();
|
||||||
if (!leftNode && !rightNode) { // 左节点为空、右节点为空,此时说明是对称的
|
if (!leftNode && !rightNode) { // 左节点为空、右节点为空,此时说明是对称的
|
||||||
@ -581,4 +582,4 @@ var isSymmetric = function(root) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
|
# 二叉树层序遍历登场!
|
||||||
|
|
||||||
学会二叉树的层序遍历,可以一口气打完以下十题:
|
学会二叉树的层序遍历,可以一口气打完以下十题:
|
||||||
|
|
||||||
@ -20,7 +21,6 @@
|
|||||||
* 104.二叉树的最大深度
|
* 104.二叉树的最大深度
|
||||||
* 111.二叉树的最小深度
|
* 111.二叉树的最小深度
|
||||||
|
|
||||||
在之前写过这篇文章 [二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html),可惜当时只打了5个,还不够,再给我一次机会,我打十个!
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -87,7 +87,9 @@ public:
|
|||||||
|
|
||||||
python代码:
|
python代码:
|
||||||
|
|
||||||
|
|
||||||
```python3
|
```python3
|
||||||
|
|
||||||
class Solution:
|
class Solution:
|
||||||
"""二叉树层序遍历迭代解法"""
|
"""二叉树层序遍历迭代解法"""
|
||||||
|
|
||||||
@ -113,7 +115,20 @@ class Solution:
|
|||||||
|
|
||||||
return results
|
return results
|
||||||
```
|
```
|
||||||
|
```python
|
||||||
|
# 递归法
|
||||||
|
class Solution:
|
||||||
|
def levelOrder(self, root: TreeNode) -> List[List[int]]:
|
||||||
|
res = []
|
||||||
|
def helper(root, depth):
|
||||||
|
if not root: return []
|
||||||
|
if len(res) == depth: res.append([]) # start the current depth
|
||||||
|
res[depth].append(root.val) # fulfil the current depth
|
||||||
|
if root.left: helper(root.left, depth + 1) # process child nodes for the next depth
|
||||||
|
if root.right: helper(root.right, depth + 1)
|
||||||
|
helper(root, 0)
|
||||||
|
return res
|
||||||
|
```
|
||||||
java:
|
java:
|
||||||
|
|
||||||
```Java
|
```Java
|
||||||
@ -406,9 +421,10 @@ var levelOrderBottom = function(root) {
|
|||||||
node.left&&queue.push(node.left);
|
node.left&&queue.push(node.left);
|
||||||
node.right&&queue.push(node.right);
|
node.right&&queue.push(node.right);
|
||||||
}
|
}
|
||||||
res.push(curLevel);
|
// 从数组前头插入值,避免最后反转数组,减少运算时间
|
||||||
|
res.unshift(curLevel);
|
||||||
}
|
}
|
||||||
return res.reverse();
|
return res;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1158,7 +1174,7 @@ public:
|
|||||||
if (root != NULL) que.push(root);
|
if (root != NULL) que.push(root);
|
||||||
while (!que.empty()) {
|
while (!que.empty()) {
|
||||||
int size = que.size();
|
int size = que.size();
|
||||||
vector<int> vec;
|
// vector<int> vec;
|
||||||
Node* nodePre;
|
Node* nodePre;
|
||||||
Node* node;
|
Node* node;
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
@ -1248,7 +1264,41 @@ class Solution:
|
|||||||
first = first.left # 从本层扩展到下一层
|
first = first.left # 从本层扩展到下一层
|
||||||
return root
|
return root
|
||||||
```
|
```
|
||||||
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
|
||||||
|
/**
|
||||||
|
* // Definition for a Node.
|
||||||
|
* function Node(val, left, right, next) {
|
||||||
|
* this.val = val === undefined ? null : val;
|
||||||
|
* this.left = left === undefined ? null : left;
|
||||||
|
* this.right = right === undefined ? null : right;
|
||||||
|
* this.next = next === undefined ? null : next;
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Node} root
|
||||||
|
* @return {Node}
|
||||||
|
*/
|
||||||
|
var connect = function(root) {
|
||||||
|
if (root === null) return root;
|
||||||
|
let queue = [root];
|
||||||
|
while (queue.length) {
|
||||||
|
let n = queue.length;
|
||||||
|
for (let i=0; i<n; i++) {
|
||||||
|
let node = queue.shift();
|
||||||
|
if (i < n-1) {
|
||||||
|
node.next = queue[0];
|
||||||
|
}
|
||||||
|
node.left && queue.push(node.left);
|
||||||
|
node.right && queue.push(node.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
go:
|
go:
|
||||||
|
|
||||||
```GO
|
```GO
|
||||||
@ -1411,7 +1461,39 @@ class Solution:
|
|||||||
first = dummyHead.next # 此处为换行操作,更新到下一行
|
first = dummyHead.next # 此处为换行操作,更新到下一行
|
||||||
return root
|
return root
|
||||||
```
|
```
|
||||||
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
/**
|
||||||
|
* // Definition for a Node.
|
||||||
|
* function Node(val, left, right, next) {
|
||||||
|
* this.val = val === undefined ? null : val;
|
||||||
|
* this.left = left === undefined ? null : left;
|
||||||
|
* this.right = right === undefined ? null : right;
|
||||||
|
* this.next = next === undefined ? null : next;
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Node} root
|
||||||
|
* @return {Node}
|
||||||
|
*/
|
||||||
|
var connect = function(root) {
|
||||||
|
if (root === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let queue = [root];
|
||||||
|
while (queue.length > 0) {
|
||||||
|
let n = queue.length;
|
||||||
|
for (let i=0; i<n; i++) {
|
||||||
|
let node = queue.shift();
|
||||||
|
if (i < n-1) node.next = queue[0];
|
||||||
|
if (node.left != null) queue.push(node.left);
|
||||||
|
if (node.right != null) queue.push(node.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
```
|
||||||
go:
|
go:
|
||||||
|
|
||||||
```GO
|
```GO
|
||||||
@ -1555,10 +1637,74 @@ class Solution:
|
|||||||
return len(result)
|
return len(result)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
```go
|
||||||
|
/**
|
||||||
|
* Definition for a binary tree node.
|
||||||
|
* type TreeNode struct {
|
||||||
|
* Val int
|
||||||
|
* Left *TreeNode
|
||||||
|
* Right *TreeNode
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
func maxDepth(root *TreeNode) int {
|
||||||
|
ans:=0
|
||||||
|
if root==nil{
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
queue:=list.New()
|
||||||
|
queue.PushBack(root)
|
||||||
|
for queue.Len()>0{
|
||||||
|
length:=queue.Len()
|
||||||
|
for i:=0;i<length;i++{
|
||||||
|
node:=queue.Remove(queue.Front()).(*TreeNode)
|
||||||
|
if node.Left!=nil{
|
||||||
|
queue.PushBack(node.Left)
|
||||||
|
}
|
||||||
|
if node.Right!=nil{
|
||||||
|
queue.PushBack(node.Right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ans++//记录深度,其他的是层序遍历的板子
|
||||||
|
}
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
/**
|
||||||
|
* Definition for a binary tree node.
|
||||||
|
* function TreeNode(val, left, right) {
|
||||||
|
* this.val = (val===undefined ? 0 : val)
|
||||||
|
* this.left = (left===undefined ? null : left)
|
||||||
|
* this.right = (right===undefined ? null : right)
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @param {TreeNode} root
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
var maxDepth = function(root) {
|
||||||
|
// 最大的深度就是二叉树的层数
|
||||||
|
if (root === null) return 0;
|
||||||
|
let queue = [root];
|
||||||
|
let height = 0;
|
||||||
|
while (queue.length) {
|
||||||
|
let n = queue.length;
|
||||||
|
height++;
|
||||||
|
for (let i=0; i<n; i++) {
|
||||||
|
let node = queue.shift();
|
||||||
|
node.left && queue.push(node.left);
|
||||||
|
node.right && queue.push(node.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return height;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
# 111.二叉树的最小深度
|
# 111.二叉树的最小深度
|
||||||
|
|
||||||
@ -1659,7 +1805,78 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
```go
|
||||||
|
/**
|
||||||
|
* Definition for a binary tree node.
|
||||||
|
* type TreeNode struct {
|
||||||
|
* Val int
|
||||||
|
* Left *TreeNode
|
||||||
|
* Right *TreeNode
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
func minDepth(root *TreeNode) int {
|
||||||
|
ans:=0
|
||||||
|
if root==nil{
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
queue:=list.New()
|
||||||
|
queue.PushBack(root)
|
||||||
|
for queue.Len()>0{
|
||||||
|
length:=queue.Len()
|
||||||
|
for i:=0;i<length;i++{
|
||||||
|
node:=queue.Remove(queue.Front()).(*TreeNode)
|
||||||
|
if node.Left==nil&&node.Right==nil{//当前节点没有左右节点,则代表此层是最小层
|
||||||
|
return ans+1//返回当前层 ans代表是上一层
|
||||||
|
}
|
||||||
|
if node.Left!=nil{
|
||||||
|
queue.PushBack(node.Left)
|
||||||
|
}
|
||||||
|
if node.Right!=nil{
|
||||||
|
queue.PushBack(node.Right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ans++//记录层数
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
return ans+1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
/**
|
||||||
|
* Definition for a binary tree node.
|
||||||
|
* function TreeNode(val, left, right) {
|
||||||
|
* this.val = (val===undefined ? 0 : val)
|
||||||
|
* this.left = (left===undefined ? null : left)
|
||||||
|
* this.right = (right===undefined ? null : right)
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @param {TreeNode} root
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
var minDepth = function(root) {
|
||||||
|
if (root === null) return 0;
|
||||||
|
let queue = [root];
|
||||||
|
let deepth = 0;
|
||||||
|
while (queue.length) {
|
||||||
|
let n = queue.length;
|
||||||
|
deepth++;
|
||||||
|
for (let i=0; i<n; i++) {
|
||||||
|
let node = queue.shift();
|
||||||
|
// 如果左右节点都是null,则该节点深度最小
|
||||||
|
if (node.left === null && node.right === null) {
|
||||||
|
return deepth;
|
||||||
|
}
|
||||||
|
node.left && queue.push(node.left);;
|
||||||
|
node.right && queue.push (node.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deepth;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1689,4 +1906,4 @@ JavaScript:
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -42,14 +42,14 @@
|
|||||||
1. 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回这棵树的深度,所以返回值为int类型。
|
1. 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回这棵树的深度,所以返回值为int类型。
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
```c++
|
```CPP
|
||||||
int getdepth(treenode* node)
|
int getdepth(treenode* node)
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 确定终止条件:如果为空节点的话,就返回0,表示高度为0。
|
2. 确定终止条件:如果为空节点的话,就返回0,表示高度为0。
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
```c++
|
```CPP
|
||||||
if (node == null) return 0;
|
if (node == null) return 0;
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ if (node == null) return 0;
|
|||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
int leftdepth = getdepth(node->left); // 左
|
int leftdepth = getdepth(node->left); // 左
|
||||||
int rightdepth = getdepth(node->right); // 右
|
int rightdepth = getdepth(node->right); // 右
|
||||||
int depth = 1 + max(leftdepth, rightdepth); // 中
|
int depth = 1 + max(leftdepth, rightdepth); // 中
|
||||||
@ -66,7 +66,7 @@ return depth;
|
|||||||
|
|
||||||
所以整体c++代码如下:
|
所以整体c++代码如下:
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
class solution {
|
class solution {
|
||||||
public:
|
public:
|
||||||
int getdepth(treenode* node) {
|
int getdepth(treenode* node) {
|
||||||
@ -83,7 +83,7 @@ public:
|
|||||||
```
|
```
|
||||||
|
|
||||||
代码精简之后c++代码如下:
|
代码精简之后c++代码如下:
|
||||||
```c++
|
```CPP
|
||||||
class solution {
|
class solution {
|
||||||
public:
|
public:
|
||||||
int maxdepth(treenode* root) {
|
int maxdepth(treenode* root) {
|
||||||
@ -99,7 +99,7 @@ public:
|
|||||||
|
|
||||||
本题当然也可以使用前序,代码如下:(**充分表现出求深度回溯的过程**)
|
本题当然也可以使用前序,代码如下:(**充分表现出求深度回溯的过程**)
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
class solution {
|
class solution {
|
||||||
public:
|
public:
|
||||||
int result;
|
int result;
|
||||||
@ -122,7 +122,7 @@ public:
|
|||||||
}
|
}
|
||||||
int maxdepth(treenode* root) {
|
int maxdepth(treenode* root) {
|
||||||
result = 0;
|
result = 0;
|
||||||
if (root == 0) return result;
|
if (root == NULL) return result;
|
||||||
getdepth(root, 1);
|
getdepth(root, 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ public:
|
|||||||
|
|
||||||
注意以上代码是为了把细节体现出来,简化一下代码如下:
|
注意以上代码是为了把细节体现出来,简化一下代码如下:
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
class solution {
|
class solution {
|
||||||
public:
|
public:
|
||||||
int result;
|
int result;
|
||||||
@ -171,7 +171,7 @@ public:
|
|||||||
|
|
||||||
c++代码如下:
|
c++代码如下:
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
class solution {
|
class solution {
|
||||||
public:
|
public:
|
||||||
int maxdepth(treenode* root) {
|
int maxdepth(treenode* root) {
|
||||||
@ -218,7 +218,7 @@ public:
|
|||||||
|
|
||||||
c++代码:
|
c++代码:
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
class solution {
|
class solution {
|
||||||
public:
|
public:
|
||||||
int maxdepth(node* root) {
|
int maxdepth(node* root) {
|
||||||
@ -235,7 +235,7 @@ public:
|
|||||||
|
|
||||||
依然是层序遍历,代码如下:
|
依然是层序遍历,代码如下:
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
class solution {
|
class solution {
|
||||||
public:
|
public:
|
||||||
int maxdepth(node* root) {
|
int maxdepth(node* root) {
|
||||||
@ -586,4 +586,4 @@ var maxDepth = function(root) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -607,6 +607,7 @@ class Solution {
|
|||||||
for (int i = inLeft; i < inRight; i++) {
|
for (int i = inLeft; i < inRight; i++) {
|
||||||
if (inorder[i] == rootVal) {
|
if (inorder[i] == rootVal) {
|
||||||
rootIndex = i;
|
rootIndex = i;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 根据rootIndex划分左右子树
|
// 根据rootIndex划分左右子树
|
||||||
@ -897,4 +898,4 @@ struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int in
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
> 构造二叉搜索树,一不小心就平衡了
|
> 构造二叉搜索树,一不小心就平衡了
|
||||||
|
|
||||||
## 108.将有序数组转换为二叉搜索树
|
# 108.将有序数组转换为二叉搜索树
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/)
|
[力扣题目链接](https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/)
|
||||||
|
|
||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
做这道题目之前大家可以了解一下这几道:
|
做这道题目之前大家可以了解一下这几道:
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## 总结
|
# 总结
|
||||||
|
|
||||||
**在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) 和 [二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)之后,我们顺理成章的应该构造一下二叉搜索树了,一不小心还是一棵平衡二叉搜索树**。
|
**在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) 和 [二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)之后,我们顺理成章的应该构造一下二叉搜索树了,一不小心还是一棵平衡二叉搜索树**。
|
||||||
|
|
||||||
@ -205,10 +205,10 @@ public:
|
|||||||
最后依然给出迭代的方法,其实就是模拟取中间元素,然后不断分割去构造二叉树的过程。
|
最后依然给出迭代的方法,其实就是模拟取中间元素,然后不断分割去构造二叉树的过程。
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
## Java
|
||||||
|
|
||||||
递归: 左闭右开 [left,right)
|
递归: 左闭右开 [left,right)
|
||||||
```Java
|
```Java
|
||||||
@ -253,7 +253,8 @@ class Solution {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
迭代: 左闭右闭 [left,right]
|
迭代: 左闭右闭 [left,right]
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
@ -303,7 +304,9 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
## Python
|
||||||
|
**递归**
|
||||||
|
|
||||||
```python3
|
```python3
|
||||||
# Definition for a binary tree node.
|
# Definition for a binary tree node.
|
||||||
# class TreeNode:
|
# class TreeNode:
|
||||||
@ -311,36 +314,39 @@ Python:
|
|||||||
# self.val = val
|
# self.val = val
|
||||||
# self.left = left
|
# self.left = left
|
||||||
# self.right = right
|
# self.right = right
|
||||||
#递归法
|
|
||||||
class Solution:
|
class Solution:
|
||||||
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
|
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
|
||||||
def buildaTree(left,right):
|
'''
|
||||||
if left > right: return None #左闭右闭的区间,当区间 left > right的时候,就是空节点,当left = right的时候,不为空
|
构造二叉树:重点是选取数组最中间元素为分割点,左侧是递归左区间;右侧是递归右区间
|
||||||
mid = left + (right - left) // 2 #保证数据不会越界
|
必然是平衡树
|
||||||
val = nums[mid]
|
左闭右闭区间
|
||||||
root = TreeNode(val)
|
'''
|
||||||
root.left = buildaTree(left,mid - 1)
|
# 返回根节点
|
||||||
root.right = buildaTree(mid + 1,right)
|
root = self.traversal(nums, 0, len(nums)-1)
|
||||||
return root
|
|
||||||
root = buildaTree(0,len(nums) - 1) #左闭右闭区间
|
|
||||||
return root
|
return root
|
||||||
|
|
||||||
|
def traversal(self, nums: List[int], left: int, right: int) -> TreeNode:
|
||||||
|
# Base Case
|
||||||
|
if left > right:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 确定左右界的中心,防越界
|
||||||
|
mid = left + (right - left) // 2
|
||||||
|
# 构建根节点
|
||||||
|
mid_root = TreeNode(nums[mid])
|
||||||
|
# 构建以左右界的中心为分割点的左右子树
|
||||||
|
mid_root.left = self.traversal(nums, left, mid-1)
|
||||||
|
mid_root.right = self.traversal(nums, mid+1, right)
|
||||||
|
|
||||||
|
# 返回由被传入的左右界定义的某子树的根节点
|
||||||
|
return mid_root
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
## Go
|
||||||
|
|
||||||
|
递归(隐含回溯)
|
||||||
> 递归(隐含回溯)
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
/**
|
|
||||||
* Definition for a binary tree node.
|
|
||||||
* type TreeNode struct {
|
|
||||||
* Val int
|
|
||||||
* Left *TreeNode
|
|
||||||
* Right *TreeNode
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
//递归(隐含回溯)
|
|
||||||
func sortedArrayToBST(nums []int) *TreeNode {
|
func sortedArrayToBST(nums []int) *TreeNode {
|
||||||
if len(nums)==0{return nil}//终止条件,最后数组为空则可以返回
|
if len(nums)==0{return nil}//终止条件,最后数组为空则可以返回
|
||||||
root:=&TreeNode{nums[len(nums)/2],nil,nil}//按照BSL的特点,从中间构造节点
|
root:=&TreeNode{nums[len(nums)/2],nil,nil}//按照BSL的特点,从中间构造节点
|
||||||
@ -350,21 +356,9 @@ func sortedArrayToBST(nums []int) *TreeNode {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
JavaScript版本
|
## JavaScript
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
/**
|
|
||||||
* Definition for a binary tree node.
|
|
||||||
* function TreeNode(val, left, right) {
|
|
||||||
* this.val = (val===undefined ? 0 : val)
|
|
||||||
* this.left = (left===undefined ? null : left)
|
|
||||||
* this.right = (right===undefined ? null : right)
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @param {number[]} nums
|
|
||||||
* @return {TreeNode}
|
|
||||||
*/
|
|
||||||
var sortedArrayToBST = function (nums) {
|
var sortedArrayToBST = function (nums) {
|
||||||
const buildTree = (Arr, left, right) => {
|
const buildTree = (Arr, left, right) => {
|
||||||
if (left > right)
|
if (left > right)
|
||||||
@ -388,4 +382,4 @@ var sortedArrayToBST = function (nums) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -125,9 +125,10 @@ public:
|
|||||||
|
|
||||||
1. 明确递归函数的参数和返回值
|
1. 明确递归函数的参数和返回值
|
||||||
|
|
||||||
参数的话为传入的节点指针,就没有其他参数需要传递了,返回值要返回传入节点为根节点树的深度。
|
参数:当前传入节点。
|
||||||
|
返回值:以当前传入节点为根节点的树的高度。
|
||||||
|
|
||||||
那么如何标记左右子树是否差值大于1呢。
|
那么如何标记左右子树是否差值大于1呢?
|
||||||
|
|
||||||
如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。
|
如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。
|
||||||
|
|
||||||
@ -136,9 +137,9 @@ public:
|
|||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
// -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
|
// -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
|
||||||
int getDepth(TreeNode* node)
|
int getHeight(TreeNode* node)
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 明确终止条件
|
2. 明确终止条件
|
||||||
@ -147,7 +148,7 @@ int getDepth(TreeNode* node)
|
|||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -155,23 +156,23 @@ if (node == NULL) {
|
|||||||
|
|
||||||
3. 明确单层递归的逻辑
|
3. 明确单层递归的逻辑
|
||||||
|
|
||||||
如何判断当前传入节点为根节点的二叉树是否是平衡二叉树呢,当然是左子树高度和右子树高度相差。
|
如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值。
|
||||||
|
|
||||||
分别求出左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则则返回-1,表示已经不是二叉树了。
|
分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则则返回-1,表示已经不是二叉平衡树了。
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```CPP
|
```CPP
|
||||||
int leftDepth = depth(node->left); // 左
|
int leftHeight = getHeight(node->left); // 左
|
||||||
if (leftDepth == -1) return -1;
|
if (leftHeight == -1) return -1;
|
||||||
int rightDepth = depth(node->right); // 右
|
int rightHeight = getHeight(node->right); // 右
|
||||||
if (rightDepth == -1) return -1;
|
if (rightHeight == -1) return -1;
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
if (abs(leftDepth - rightDepth) > 1) { // 中
|
if (abs(leftHeight - rightHeight) > 1) { // 中
|
||||||
result = -1;
|
result = -1;
|
||||||
} else {
|
} else {
|
||||||
result = 1 + max(leftDepth, rightDepth); // 以当前节点为根节点的最大高度
|
result = 1 + max(leftHeight, rightHeight); // 以当前节点为根节点的树的最大高度
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -180,27 +181,27 @@ return result;
|
|||||||
代码精简之后如下:
|
代码精简之后如下:
|
||||||
|
|
||||||
```CPP
|
```CPP
|
||||||
int leftDepth = getDepth(node->left);
|
int leftHeight = getHeight(node->left);
|
||||||
if (leftDepth == -1) return -1;
|
if (leftHeight == -1) return -1;
|
||||||
int rightDepth = getDepth(node->right);
|
int rightHeight = getHeight(node->right);
|
||||||
if (rightDepth == -1) return -1;
|
if (rightHeight == -1) return -1;
|
||||||
return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth);
|
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
|
||||||
```
|
```
|
||||||
|
|
||||||
此时递归的函数就已经写出来了,这个递归的函数传入节点指针,返回以该节点为根节点的二叉树的高度,如果不是二叉平衡树,则返回-1。
|
此时递归的函数就已经写出来了,这个递归的函数传入节点指针,返回以该节点为根节点的二叉树的高度,如果不是二叉平衡树,则返回-1。
|
||||||
|
|
||||||
getDepth整体代码如下:
|
getHeight整体代码如下:
|
||||||
|
|
||||||
```CPP
|
```CPP
|
||||||
int getDepth(TreeNode* node) {
|
int getHeight(TreeNode* node) {
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int leftDepth = getDepth(node->left);
|
int leftHeight = getHeight(node->left);
|
||||||
if (leftDepth == -1) return -1;
|
if (leftHeight == -1) return -1;
|
||||||
int rightDepth = getDepth(node->right);
|
int rightHeight = getHeight(node->right);
|
||||||
if (rightDepth == -1) return -1;
|
if (rightHeight == -1) return -1;
|
||||||
return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth);
|
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -210,18 +211,18 @@ int getDepth(TreeNode* node) {
|
|||||||
class Solution {
|
class Solution {
|
||||||
public:
|
public:
|
||||||
// 返回以该节点为根节点的二叉树的高度,如果不是二叉搜索树了则返回-1
|
// 返回以该节点为根节点的二叉树的高度,如果不是二叉搜索树了则返回-1
|
||||||
int getDepth(TreeNode* node) {
|
int getHeight(TreeNode* node) {
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int leftDepth = getDepth(node->left);
|
int leftHeight = getHeight(node->left);
|
||||||
if (leftDepth == -1) return -1; // 说明左子树已经不是二叉平衡树
|
if (leftHeight == -1) return -1;
|
||||||
int rightDepth = getDepth(node->right);
|
int rightHeight = getHeight(node->right);
|
||||||
if (rightDepth == -1) return -1; // 说明右子树已经不是二叉平衡树
|
if (rightHeight == -1) return -1;
|
||||||
return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth);
|
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
|
||||||
}
|
}
|
||||||
bool isBalanced(TreeNode* root) {
|
bool isBalanced(TreeNode* root) {
|
||||||
return getDepth(root) == -1 ? false : true;
|
return getHeight(root) == -1 ? false : true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@ -498,20 +499,35 @@ class Solution {
|
|||||||
## Python
|
## Python
|
||||||
|
|
||||||
递归法:
|
递归法:
|
||||||
```python
|
```python3
|
||||||
|
# Definition for a binary tree node.
|
||||||
|
# class TreeNode:
|
||||||
|
# def __init__(self, val=0, left=None, right=None):
|
||||||
|
# self.val = val
|
||||||
|
# self.left = left
|
||||||
|
# self.right = right
|
||||||
class Solution:
|
class Solution:
|
||||||
def isBalanced(self, root: TreeNode) -> bool:
|
def isBalanced(self, root: TreeNode) -> bool:
|
||||||
return True if self.getDepth(root) != -1 else False
|
if self.get_height(root) != -1:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
#返回以该节点为根节点的二叉树的高度,如果不是二叉搜索树了则返回-1
|
def get_height(self, root: TreeNode) -> int:
|
||||||
def getDepth(self, node):
|
# Base Case
|
||||||
if not node:
|
if not root:
|
||||||
return 0
|
return 0
|
||||||
leftDepth = self.getDepth(node.left)
|
# 左
|
||||||
if leftDepth == -1: return -1 #说明左子树已经不是二叉平衡树
|
if (left_height := self.get_height(root.left)) == -1:
|
||||||
rightDepth = self.getDepth(node.right)
|
return -1
|
||||||
if rightDepth == -1: return -1 #说明右子树已经不是二叉平衡树
|
# 右
|
||||||
return -1 if abs(leftDepth - rightDepth)>1 else 1 + max(leftDepth, rightDepth)
|
if (right_height := self.get_height(root.right)) == -1:
|
||||||
|
return -1
|
||||||
|
# 中
|
||||||
|
if abs(left_height - right_height) > 1:
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
return 1 + max(left_height, right_height)
|
||||||
```
|
```
|
||||||
|
|
||||||
迭代法:
|
迭代法:
|
||||||
@ -624,4 +640,4 @@ var isBalanced = function(root) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -413,4 +413,4 @@ var minDepth = function(root) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -411,6 +411,31 @@ class solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 解法2
|
||||||
|
class Solution {
|
||||||
|
List<List<Integer>> result;
|
||||||
|
LinkedList<Integer> path;
|
||||||
|
public List<List<Integer>> pathSum (TreeNode root,int targetSum) {
|
||||||
|
result = new LinkedList<>();
|
||||||
|
path = new LinkedList<>();
|
||||||
|
travesal(root, targetSum);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private void travesal(TreeNode root, int count) {
|
||||||
|
if (root == null) return;
|
||||||
|
path.offer(root.val);
|
||||||
|
count -= root.val;
|
||||||
|
if (root.left == null && root.right == null && count == 0) {
|
||||||
|
result.add(new LinkedList<>(path));
|
||||||
|
}
|
||||||
|
travesal(root.left, count);
|
||||||
|
travesal(root.right, count);
|
||||||
|
path.removeLast(); // 回溯
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## python
|
## python
|
||||||
|
|
||||||
0112.路径总和
|
0112.路径总和
|
||||||
@ -686,4 +711,4 @@ var pathsum = function(root, targetsum) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -274,4 +274,4 @@ const numDistinct = (s, t) => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -7,6 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
# 116. 填充每个节点的下一个右侧节点指针
|
# 116. 填充每个节点的下一个右侧节点指针
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/)
|
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/)
|
||||||
@ -255,9 +255,9 @@ const connect = root => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -214,6 +214,26 @@ class Solution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
// 解法1
|
||||||
|
class Solution {
|
||||||
|
public int maxProfit(int[] prices) {
|
||||||
|
if (prices == null || prices.length == 0) return 0;
|
||||||
|
int length = prices.length;
|
||||||
|
// dp[i][0]代表第i天持有股票的最大收益
|
||||||
|
// dp[i][1]代表第i天不持有股票的最大收益
|
||||||
|
int[][] dp = new int[length][2];
|
||||||
|
int result = 0;
|
||||||
|
dp[0][0] = -prices[0];
|
||||||
|
dp[0][1] = 0;
|
||||||
|
for (int i = 1; i < length; i++) {
|
||||||
|
dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);
|
||||||
|
dp[i][1] = Math.max(dp[i - 1][0] + prices[i], dp[i - 1][1]);
|
||||||
|
}
|
||||||
|
return dp[length - 1][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
``` java
|
``` java
|
||||||
class Solution { // 动态规划解法
|
class Solution { // 动态规划解法
|
||||||
@ -315,6 +335,8 @@ func max(a,b int)int {
|
|||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
|
||||||
|
> 动态规划
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const maxProfit = prices => {
|
const maxProfit = prices => {
|
||||||
const len = prices.length;
|
const len = prices.length;
|
||||||
@ -333,11 +355,23 @@ const maxProfit = prices => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 贪心法
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var maxProfit = function(prices) {
|
||||||
|
let lowerPrice = prices[0];// 重点是维护这个最小值(贪心的思想)
|
||||||
|
let profit = 0;
|
||||||
|
for(let i = 0; i < prices.length; i++){
|
||||||
|
lowerPrice = Math.min(lowerPrice, prices[i]);// 贪心地选择左面的最小价格
|
||||||
|
profit = Math.max(profit, prices[i] - lowerPrice);// 遍历一趟就可以获得最大利润
|
||||||
|
}
|
||||||
|
return profit;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
**如果想到其实最终利润是可以分解的,那么本题就很容易了!**
|
**如果想到其实最终利润是可以分解的,那么本题就很容易了!**
|
||||||
|
|
||||||
如果分解呢?
|
如何分解呢?
|
||||||
|
|
||||||
假如第0天买入,第3天卖出,那么利润为:prices[3] - prices[0]。
|
假如第0天买入,第3天卖出,那么利润为:prices[3] - prices[0]。
|
||||||
|
|
||||||
@ -131,9 +131,9 @@ public:
|
|||||||
|
|
||||||
一旦想到这里了,很自然就会想到贪心了,即:只收集每天的正利润,最后稳稳的就是最大利润了。
|
一旦想到这里了,很自然就会想到贪心了,即:只收集每天的正利润,最后稳稳的就是最大利润了。
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
Java:
|
## Java
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// 贪心思路
|
// 贪心思路
|
||||||
@ -171,7 +171,7 @@ class Solution { // 动态规划
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Python:
|
## Python
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def maxProfit(self, prices: List[int]) -> int:
|
def maxProfit(self, prices: List[int]) -> int:
|
||||||
@ -181,7 +181,21 @@ class Solution:
|
|||||||
return result
|
return result
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
python动态规划
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
def maxProfit(self, prices: List[int]) -> int:
|
||||||
|
length = len(prices)
|
||||||
|
dp = [[0] * 2 for _ in range(length)]
|
||||||
|
dp[0][0] = -prices[0]
|
||||||
|
dp[0][1] = 0
|
||||||
|
for i in range(1, length):
|
||||||
|
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) #注意这里是和121. 买卖股票的最佳时机唯一不同的地方
|
||||||
|
dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])
|
||||||
|
return dp[-1][1]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go
|
||||||
```golang
|
```golang
|
||||||
//贪心算法
|
//贪心算法
|
||||||
func maxProfit(prices []int) int {
|
func maxProfit(prices []int) int {
|
||||||
@ -217,9 +231,9 @@ func maxProfit(prices []int) int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Javascript:
|
## Javascript
|
||||||
|
贪心
|
||||||
```Javascript
|
```Javascript
|
||||||
// 贪心
|
|
||||||
var maxProfit = function(prices) {
|
var maxProfit = function(prices) {
|
||||||
let result = 0
|
let result = 0
|
||||||
for(let i = 1; i < prices.length; i++) {
|
for(let i = 1; i < prices.length; i++) {
|
||||||
@ -229,7 +243,31 @@ var maxProfit = function(prices) {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
C:
|
动态规划
|
||||||
|
```javascript
|
||||||
|
const maxProfit = (prices) => {
|
||||||
|
let dp = Array.from(Array(prices.length), () => Array(2).fill(0));
|
||||||
|
// dp[i][0] 表示第i天持有股票所得现金。
|
||||||
|
// dp[i][1] 表示第i天不持有股票所得最多现金
|
||||||
|
dp[0][0] = 0 - prices[0];
|
||||||
|
dp[0][1] = 0;
|
||||||
|
for(let i = 1; i < prices.length; i++) {
|
||||||
|
// 如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来
|
||||||
|
// 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]
|
||||||
|
// 第i天买入股票,所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即:dp[i - 1][1] - prices[i]
|
||||||
|
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] - prices[i]);
|
||||||
|
|
||||||
|
// 在来看看如果第i天不持有股票即dp[i][1]的情况, 依然可以由两个状态推出来
|
||||||
|
// 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]
|
||||||
|
// 第i天卖出股票,所得现金就是按照今天股票佳价格卖出后所得现金即:prices[i] + dp[i - 1][0]
|
||||||
|
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[prices.length -1][0];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## C
|
||||||
```c
|
```c
|
||||||
int maxProfit(int* prices, int pricesSize){
|
int maxProfit(int* prices, int pricesSize){
|
||||||
int result = 0;
|
int result = 0;
|
||||||
@ -248,4 +286,4 @@ int maxProfit(int* prices, int pricesSize){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -202,6 +202,7 @@ Go:
|
|||||||
|
|
||||||
Javascript:
|
Javascript:
|
||||||
```javascript
|
```javascript
|
||||||
|
// 方法一:动态规划(dp 数组)
|
||||||
const maxProfit = (prices) => {
|
const maxProfit = (prices) => {
|
||||||
let dp = Array.from(Array(prices.length), () => Array(2).fill(0));
|
let dp = Array.from(Array(prices.length), () => Array(2).fill(0));
|
||||||
// dp[i][0] 表示第i天持有股票所得现金。
|
// dp[i][0] 表示第i天持有股票所得现金。
|
||||||
@ -222,6 +223,21 @@ const maxProfit = (prices) => {
|
|||||||
|
|
||||||
return dp[prices.length -1][0];
|
return dp[prices.length -1][0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 方法二:动态规划(滚动数组)
|
||||||
|
const maxProfit = (prices) => {
|
||||||
|
// 滚动数组
|
||||||
|
// have: 第i天持有股票最大收益; notHave: 第i天不持有股票最大收益
|
||||||
|
let n = prices.length,
|
||||||
|
have = -prices[0],
|
||||||
|
notHave = 0;
|
||||||
|
for (let i = 1; i < n; i++) {
|
||||||
|
have = Math.max(have, notHave - prices[i]);
|
||||||
|
notHave = Math.max(notHave, have + prices[i]);
|
||||||
|
}
|
||||||
|
// 最终手里不持有股票才能保证收益最大化
|
||||||
|
return notHave;
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -230,4 +246,4 @@ const maxProfit = (prices) => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -324,4 +324,4 @@ const maxProfit = prices => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -7,6 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
# 127. 单词接龙
|
# 127. 单词接龙
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/word-ladder/)
|
[力扣题目链接](https://leetcode-cn.com/problems/word-ladder/)
|
||||||
@ -141,10 +141,44 @@ public int ladderLength(String beginWord, String endWord, List<String> wordList)
|
|||||||
## Go
|
## Go
|
||||||
|
|
||||||
## JavaScript
|
## JavaScript
|
||||||
|
```javascript
|
||||||
|
var ladderLength = function(beginWord, endWord, wordList) {
|
||||||
|
// 将wordList转成Set,提高查询速度
|
||||||
|
const wordSet = new Set(wordList);
|
||||||
|
// Set元素个数为0 或者 endWord没有在wordSet出现,直接返回0
|
||||||
|
if (wordSet.size === 0 || !wordSet.has(endWord)) return 0;
|
||||||
|
// 记录word是否访问过
|
||||||
|
const visitMap = new Map();// <word, 查询到这个word路径长度>
|
||||||
|
// 初始化队列
|
||||||
|
const queue = [];
|
||||||
|
queue.push(beginWord);
|
||||||
|
// 初始化visitMap
|
||||||
|
visitMap.set(beginWord, 1);
|
||||||
|
|
||||||
|
while(queue.length !== 0){
|
||||||
|
let word = queue.shift(); // 删除队首元素,将它的值存放在word
|
||||||
|
let path = visitMap.get(word); // 这个word的路径长度
|
||||||
|
for(let i = 0; i < word.length; i++){ // 遍历单词的每个字符
|
||||||
|
for (let c = 97; c <= 122; c++) { // 对应26个字母ASCII值 从'a' 到 'z' 遍历替换
|
||||||
|
// 拼串得到新的字符串
|
||||||
|
let newWord = word.slice(0, i) + String.fromCharCode(c) + word.slice(i + 1);
|
||||||
|
if(newWord === endWord) return path + 1; // 找到了end,返回path+1
|
||||||
|
// wordSet出现了newWord,并且newWord没有被访问过
|
||||||
|
if(wordSet.has(newWord) && !visitMap.has(newWord)) {
|
||||||
|
// 添加访问信息
|
||||||
|
visitMap.set(newWord, path + 1);
|
||||||
|
queue.push(newWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
## 链接
|
<p align="center">
|
||||||
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
|
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||||
|
</p>
|
||||||
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
# 129. 求根节点到叶节点数字之和
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/)
|
[力扣题目链接](https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/)
|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
本题和[113.路径总和II](https://programmercarl.com/0112.路径总和.html#_113-路径总和ii)是类似的思路,做完这道题,可以顺便把[113.路径总和II](https://programmercarl.com/0112.路径总和.html#_113-路径总和ii) 和 [112.路径总和](https://programmercarl.com/0112.路径总和.html#_112-路径总和) 做了。
|
本题和[113.路径总和II](https://programmercarl.com/0112.路径总和.html#_113-路径总和ii)是类似的思路,做完这道题,可以顺便把[113.路径总和II](https://programmercarl.com/0112.路径总和.html#_113-路径总和ii) 和 [112.路径总和](https://programmercarl.com/0112.路径总和.html#_112-路径总和) 做了。
|
||||||
|
|
||||||
@ -15,7 +23,7 @@
|
|||||||
|
|
||||||
那么先按递归三部曲来分析:
|
那么先按递归三部曲来分析:
|
||||||
|
|
||||||
### 递归三部曲
|
## 递归三部曲
|
||||||
|
|
||||||
如果对递归三部曲不了解的话,可以看这里:[二叉树:前中后递归详解](https://programmercarl.com/二叉树的递归遍历.html)
|
如果对递归三部曲不了解的话,可以看这里:[二叉树:前中后递归详解](https://programmercarl.com/二叉树的递归遍历.html)
|
||||||
|
|
||||||
@ -107,7 +115,7 @@ path.pop_back(); // 回溯
|
|||||||
```
|
```
|
||||||
**把回溯放在花括号外面了,世界上最遥远的距离,是你在花括号里,而我在花括号外!** 这就不对了。
|
**把回溯放在花括号外面了,世界上最遥远的距离,是你在花括号里,而我在花括号外!** 这就不对了。
|
||||||
|
|
||||||
### 整体C++代码
|
## 整体C++代码
|
||||||
|
|
||||||
关键逻辑分析完了,整体C++代码如下:
|
关键逻辑分析完了,整体C++代码如下:
|
||||||
|
|
||||||
@ -160,10 +168,56 @@ public:
|
|||||||
**我这里提供的代码把整个回溯过程充分体现出来,希望可以帮助大家看的明明白白!**
|
**我这里提供的代码把整个回溯过程充分体现出来,希望可以帮助大家看的明明白白!**
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
|
|
||||||
|
```java
|
||||||
|
class Solution {
|
||||||
|
List<Integer> path = new ArrayList<>();
|
||||||
|
int res = 0;
|
||||||
|
public int sumNumbers(TreeNode root) {
|
||||||
|
// 如果节点为0,那么就返回0
|
||||||
|
if (root == null) return 0;
|
||||||
|
// 首先将根节点放到集合中
|
||||||
|
path.add(root.val);
|
||||||
|
// 开始递归
|
||||||
|
recur(root);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recur(TreeNode root){
|
||||||
|
if (root.left == null && root.right == null) {
|
||||||
|
// 当是叶子节点的时候,开始处理
|
||||||
|
res += listToInt(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.left != null){
|
||||||
|
// 注意有回溯
|
||||||
|
path.add(root.left.val);
|
||||||
|
recur(root.left);
|
||||||
|
path.remove(path.size() - 1);
|
||||||
|
}
|
||||||
|
if (root.right != null){
|
||||||
|
// 注意有回溯
|
||||||
|
path.add(root.right.val);
|
||||||
|
recur(root.right);
|
||||||
|
path.remove(path.size() - 1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
public int listToInt(List<Integer> path){
|
||||||
|
int sum = 0;
|
||||||
|
for (Integer num:path){
|
||||||
|
// sum * 10 表示进位
|
||||||
|
sum = sum * 10 + num;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python3
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
@ -194,6 +248,48 @@ class Solution:
|
|||||||
Go:
|
Go:
|
||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
var sumNumbers = function(root) {
|
||||||
|
const listToInt = path => {
|
||||||
|
let sum = 0;
|
||||||
|
for(let num of path){
|
||||||
|
// sum * 10 表示进位
|
||||||
|
sum = sum * 10 + num;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
const recur = root =>{
|
||||||
|
if (root.left == null && root.right == null) {
|
||||||
|
// 当是叶子节点的时候,开始处理
|
||||||
|
res += listToInt(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.left != null){
|
||||||
|
// 注意有回溯
|
||||||
|
path.push(root.left.val);
|
||||||
|
recur(root.left);
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
if (root.right != null){
|
||||||
|
// 注意有回溯
|
||||||
|
path.push(root.right.val);
|
||||||
|
recur(root.right);
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
const path = new Array();
|
||||||
|
let res = 0;
|
||||||
|
// 如果节点为0,那么就返回0
|
||||||
|
if (root == null) return 0;
|
||||||
|
// 首先将根节点放到集合中
|
||||||
|
path.push(root.val);
|
||||||
|
// 开始递归
|
||||||
|
recur(root);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -201,4 +297,4 @@ JavaScript:
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
> 切割问题其实是一种组合问题!
|
> 切割问题其实是一种组合问题!
|
||||||
|
|
||||||
## 131.分割回文串
|
# 131.分割回文串
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/palindrome-partitioning/)
|
[力扣题目链接](https://leetcode-cn.com/problems/palindrome-partitioning/)
|
||||||
|
|
||||||
@ -26,7 +26,7 @@
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
关于本题,大家也可以看我在B站的视频讲解:[131.分割回文串(B站视频)](https://www.bilibili.com/video/BV1c54y1e7k6)
|
关于本题,大家也可以看我在B站的视频讲解:[131.分割回文串(B站视频)](https://www.bilibili.com/video/BV1c54y1e7k6)
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## 总结
|
# 总结
|
||||||
|
|
||||||
这道题目在leetcode上是中等,但可以说是hard的题目了,但是代码其实就是按照模板的样子来的。
|
这道题目在leetcode上是中等,但可以说是hard的题目了,但是代码其实就是按照模板的样子来的。
|
||||||
|
|
||||||
@ -244,12 +244,10 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
## Java
|
||||||
|
|
||||||
|
|
||||||
Java:
|
|
||||||
```Java
|
```Java
|
||||||
class Solution {
|
class Solution {
|
||||||
List<List<String>> lists = new ArrayList<>();
|
List<List<String>> lists = new ArrayList<>();
|
||||||
@ -291,59 +289,93 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
## Python
|
||||||
```python
|
**回溯+正反序判断回文串**
|
||||||
# 版本一
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
def partition(self, s: str) -> List[List[str]]:
|
def __init__(self):
|
||||||
res = []
|
self.paths = []
|
||||||
path = [] #放已经回文的子串
|
self.path = []
|
||||||
def backtrack(s,startIndex):
|
|
||||||
if startIndex >= len(s): #如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
|
|
||||||
return res.append(path[:])
|
|
||||||
for i in range(startIndex,len(s)):
|
|
||||||
p = s[startIndex:i+1] #获取[startIndex,i+1]在s中的子串
|
|
||||||
if p == p[::-1]: path.append(p) #是回文子串
|
|
||||||
else: continue #不是回文,跳过
|
|
||||||
backtrack(s,i+1) #寻找i+1为起始位置的子串
|
|
||||||
path.pop() #回溯过程,弹出本次已经填在path的子串
|
|
||||||
backtrack(s,0)
|
|
||||||
return res
|
|
||||||
|
|
||||||
```
|
|
||||||
```python
|
|
||||||
# 版本二
|
|
||||||
class Solution:
|
|
||||||
def partition(self, s: str) -> List[List[str]]:
|
|
||||||
res = []
|
|
||||||
path = [] #放已经回文的子串
|
|
||||||
# 双指针法判断是否是回文串
|
|
||||||
def isPalindrome(s):
|
|
||||||
n = len(s)
|
|
||||||
i, j = 0, n - 1
|
|
||||||
while i < j:
|
|
||||||
if s[i] != s[j]:return False
|
|
||||||
i += 1
|
|
||||||
j -= 1
|
|
||||||
return True
|
|
||||||
|
|
||||||
def backtrack(s, startIndex):
|
|
||||||
if startIndex >= len(s): # 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
|
|
||||||
res.append(path[:])
|
|
||||||
return
|
|
||||||
for i in range(startIndex, len(s)):
|
|
||||||
p = s[startIndex:i+1] # 获取[startIndex,i+1]在s中的子串
|
|
||||||
if isPalindrome(p): # 是回文子串
|
|
||||||
path.append(p)
|
|
||||||
else: continue #不是回文,跳过
|
|
||||||
backtrack(s, i + 1)
|
|
||||||
path.pop() #回溯过程,弹出本次已经填在path的子串
|
|
||||||
backtrack(s, 0)
|
|
||||||
return res
|
|
||||||
```
|
|
||||||
Go:
|
|
||||||
> 注意切片(go切片是披着值类型外衣的引用类型)
|
|
||||||
|
|
||||||
|
def partition(self, s: str) -> List[List[str]]:
|
||||||
|
'''
|
||||||
|
递归用于纵向遍历
|
||||||
|
for循环用于横向遍历
|
||||||
|
当切割线迭代至字符串末尾,说明找到一种方法
|
||||||
|
类似组合问题,为了不重复切割同一位置,需要start_index来做标记下一轮递归的起始位置(切割线)
|
||||||
|
'''
|
||||||
|
self.path.clear()
|
||||||
|
self.paths.clear()
|
||||||
|
self.backtracking(s, 0)
|
||||||
|
return self.paths
|
||||||
|
|
||||||
|
def backtracking(self, s: str, start_index: int) -> None:
|
||||||
|
# Base Case
|
||||||
|
if start_index >= len(s):
|
||||||
|
self.paths.append(self.path[:])
|
||||||
|
return
|
||||||
|
|
||||||
|
# 单层递归逻辑
|
||||||
|
for i in range(start_index, len(s)):
|
||||||
|
# 此次比其他组合题目多了一步判断:
|
||||||
|
# 判断被截取的这一段子串([start_index, i])是否为回文串
|
||||||
|
temp = s[start_index:i+1]
|
||||||
|
if temp == temp[::-1]: # 若反序和正序相同,意味着这是回文串
|
||||||
|
self.path.append(temp)
|
||||||
|
self.backtracking(s, i+1) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
|
||||||
|
self.path.pop()
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
```
|
||||||
|
**回溯+函数判断回文串**
|
||||||
|
```python3
|
||||||
|
class Solution:
|
||||||
|
def __init__(self):
|
||||||
|
self.paths = []
|
||||||
|
self.path = []
|
||||||
|
|
||||||
|
def partition(self, s: str) -> List[List[str]]:
|
||||||
|
'''
|
||||||
|
递归用于纵向遍历
|
||||||
|
for循环用于横向遍历
|
||||||
|
当切割线迭代至字符串末尾,说明找到一种方法
|
||||||
|
类似组合问题,为了不重复切割同一位置,需要start_index来做标记下一轮递归的起始位置(切割线)
|
||||||
|
'''
|
||||||
|
self.path.clear()
|
||||||
|
self.paths.clear()
|
||||||
|
self.backtracking(s, 0)
|
||||||
|
return self.paths
|
||||||
|
|
||||||
|
def backtracking(self, s: str, start_index: int) -> None:
|
||||||
|
# Base Case
|
||||||
|
if start_index >= len(s):
|
||||||
|
self.paths.append(self.path[:])
|
||||||
|
return
|
||||||
|
|
||||||
|
# 单层递归逻辑
|
||||||
|
for i in range(start_index, len(s)):
|
||||||
|
# 此次比其他组合题目多了一步判断:
|
||||||
|
# 判断被截取的这一段子串([start_index, i])是否为回文串
|
||||||
|
if self.is_palindrome(s, start_index, i):
|
||||||
|
self.path.append(s[start_index:i+1])
|
||||||
|
self.backtracking(s, i+1) # 递归纵向遍历:从下一处进行切割,判断其余是否仍为回文串
|
||||||
|
self.path.pop() # 回溯
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
def is_palindrome(self, s: str, start: int, end: int) -> bool:
|
||||||
|
i: int = start
|
||||||
|
j: int = end
|
||||||
|
while i < j:
|
||||||
|
if s[i] != s[j]:
|
||||||
|
return False
|
||||||
|
i += 1
|
||||||
|
j -= 1
|
||||||
|
return True
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go
|
||||||
|
**注意切片(go切片是披着值类型外衣的引用类型)**
|
||||||
```go
|
```go
|
||||||
func partition(s string) [][]string {
|
func partition(s string) [][]string {
|
||||||
var tmpString []string//切割字符串集合
|
var tmpString []string//切割字符串集合
|
||||||
@ -387,7 +419,7 @@ func isPartition(s string,startIndex,end int)bool{
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
javaScript:
|
## javaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
/**
|
/**
|
||||||
@ -425,4 +457,4 @@ var partition = function(s) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -8,6 +7,7 @@
|
|||||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 132. 分割回文串 II
|
# 132. 分割回文串 II
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/palindrome-partitioning-ii/)
|
[力扣题目链接](https://leetcode-cn.com/problems/palindrome-partitioning-ii/)
|
||||||
@ -142,7 +142,8 @@ for (int i = 1; i < s.size(); i++) {
|
|||||||
|
|
||||||
就是其实这两道题目的代码:
|
就是其实这两道题目的代码:
|
||||||
|
|
||||||
* 647.回文子串
|
|
||||||
|
* [647. 回文子串](https://programmercarl.com/0647.回文子串.html)
|
||||||
* 5.最长回文子串
|
* 5.最长回文子串
|
||||||
|
|
||||||
所以先用一个二维数组来保存整个字符串的回文情况。
|
所以先用一个二维数组来保存整个字符串的回文情况。
|
||||||
@ -246,11 +247,47 @@ class Solution:
|
|||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
var minCut = function(s) {
|
||||||
|
const len = s.length;
|
||||||
|
// 二维数组isPalindromic来保存整个字符串的回文情况
|
||||||
|
const isPalindromic = new Array(len).fill(false).map(() => new Array(len).fill(false));
|
||||||
|
for(let i = len - 1; i >= 0; i--){
|
||||||
|
for(let j = i; j < len; j++){
|
||||||
|
if(s[i] === s[j] && (j - i <= 1 || isPalindromic[i + 1][j - 1])){
|
||||||
|
isPalindromic[i][j] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dp[i]:范围是[0, i]的回文子串,最少分割次数是dp[i]
|
||||||
|
const dp = new Array(len).fill(0);
|
||||||
|
for(let i = 0; i < len; i++) dp[i] = i; // 初始化 dp[i]的最大值其实就是i,也就是把每个字符分割出来
|
||||||
|
for(let i = 1; i < len; i++){
|
||||||
|
if(isPalindromic[0][i]){ // 判断是不是回文子串
|
||||||
|
dp[i] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
如果要对长度为[0, i]的子串进行分割,分割点为j。
|
||||||
|
那么如果分割后,区间[j + 1, i]是回文子串,那么dp[i] 就等于 dp[j] + 1。
|
||||||
|
这里可能有同学就不明白了,为什么只看[j + 1, i]区间,不看[0, j]区间是不是回文子串呢?
|
||||||
|
那么在回顾一下dp[i]的定义: 范围是[0, i]的回文子串,最少分割次数是dp[i]。
|
||||||
|
[0, j]区间的最小切割数量,我们已经知道了就是dp[j]。
|
||||||
|
此时就找到了递推关系,当切割点j在[0, i] 之间时候,dp[i] = dp[j] + 1;
|
||||||
|
本题是要找到最少分割次数,所以遍历j的时候要取最小的dp[i]。dp[i] = Math.min(dp[i], dp[j] + 1);
|
||||||
|
*/
|
||||||
|
for(let j = 0; j < i; j++){
|
||||||
|
if(isPalindromic[j + 1][i]){
|
||||||
|
dp[i] = Math.min(dp[i], dp[j] + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[len - 1];
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -281,6 +281,48 @@ func canCompleteCircuit(gas []int, cost []int) int {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Javascript:
|
Javascript:
|
||||||
|
暴力:
|
||||||
|
```js
|
||||||
|
var canCompleteCircuit = function(gas, cost) {
|
||||||
|
for(let i = 0; i < cost.length; i++) {
|
||||||
|
let rest = gas[i] - cost[i] //记录剩余油量
|
||||||
|
// 以i为起点行驶一圈,index为下一个目的地
|
||||||
|
let index = (i + 1) % cost.length
|
||||||
|
while(rest > 0 && index !== i) {
|
||||||
|
rest += gas[index] - cost[index]
|
||||||
|
index = (index + 1) % cost.length
|
||||||
|
}
|
||||||
|
if(rest >= 0 && index === i) return i
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
};
|
||||||
|
```
|
||||||
|
解法一:
|
||||||
|
```js
|
||||||
|
var canCompleteCircuit = function(gas, cost) {
|
||||||
|
let curSum = 0
|
||||||
|
let min = Infinity
|
||||||
|
for(let i = 0; i < gas.length; i++) {
|
||||||
|
let rest = gas[i] - cost[i]
|
||||||
|
curSum += rest
|
||||||
|
if(curSum < min) {
|
||||||
|
min = curSum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(curSum < 0) return -1 //1.总油量 小于 总消耗量
|
||||||
|
if(min >= 0) return 0 //2. 说明油箱里油没断过
|
||||||
|
//3. 从后向前,看哪个节点能这个负数填平,能把这个负数填平的节点就是出发节点
|
||||||
|
for(let i = gas.length -1; i >= 0; i--) {
|
||||||
|
let rest = gas[i] - cost[i]
|
||||||
|
min += rest
|
||||||
|
if(min >= 0) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
解法二:
|
||||||
```Javascript
|
```Javascript
|
||||||
var canCompleteCircuit = function(gas, cost) {
|
var canCompleteCircuit = function(gas, cost) {
|
||||||
const gasLen = gas.length
|
const gasLen = gas.length
|
||||||
@ -337,4 +379,4 @@ int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -132,30 +132,33 @@ public:
|
|||||||
Java:
|
Java:
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
|
/**
|
||||||
|
分两个阶段
|
||||||
|
1、起点下标1 从左往右,只要 右边 比 左边 大,右边的糖果=左边 + 1
|
||||||
|
2、起点下标 ratings.length - 2 从右往左, 只要左边 比 右边 大,此时 左边的糖果应该 取本身的糖果数(符合比它左边大) 和 右边糖果数 + 1 二者的最大值,这样才符合 它比它左边的大,也比它右边大
|
||||||
|
*/
|
||||||
public int candy(int[] ratings) {
|
public int candy(int[] ratings) {
|
||||||
int[] candy = new int[ratings.length];
|
int[] candyVec = new int[ratings.length];
|
||||||
for (int i = 0; i < candy.length; i++) {
|
candyVec[0] = 1;
|
||||||
candy[i] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i < ratings.length; i++) {
|
for (int i = 1; i < ratings.length; i++) {
|
||||||
if (ratings[i] > ratings[i - 1]) {
|
if (ratings[i] > ratings[i - 1]) {
|
||||||
candy[i] = candy[i - 1] + 1;
|
candyVec[i] = candyVec[i - 1] + 1;
|
||||||
|
} else {
|
||||||
|
candyVec[i] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = ratings.length - 2; i >= 0; i--) {
|
for (int i = ratings.length - 2; i >= 0; i--) {
|
||||||
if (ratings[i] > ratings[i + 1]) {
|
if (ratings[i] > ratings[i + 1]) {
|
||||||
candy[i] = Math.max(candy[i],candy[i + 1] + 1);
|
candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = 0;
|
int ans = 0;
|
||||||
for (int i = 0; i < candy.length; i++) {
|
for (int s : candyVec) {
|
||||||
count += candy[i];
|
ans += s;
|
||||||
}
|
}
|
||||||
|
return ans;
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -242,4 +245,4 @@ var candy = function(ratings) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -319,4 +319,4 @@ const wordBreak = (s, wordDict) => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -7,6 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
# 141. 环形链表
|
# 141. 环形链表
|
||||||
|
|
||||||
给定一个链表,判断链表中是否有环。
|
给定一个链表,判断链表中是否有环。
|
||||||
@ -114,11 +114,22 @@ class Solution:
|
|||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
var hasCycle = function(head) {
|
||||||
|
let fast = head;
|
||||||
|
let slow = head;
|
||||||
|
// 空链表、单节点链表一定不会有环
|
||||||
|
while(fast != null && fast.next != null){
|
||||||
|
fast = fast.next.next; // 快指针,一次移动两步
|
||||||
|
slow = slow.next; // 慢指针,一次移动一步
|
||||||
|
if(fast === slow) return true; // 快慢指针相遇,表明有环
|
||||||
|
}
|
||||||
|
return false; // 正常走到链表末尾,表明没有环
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -334,4 +334,4 @@ extension ListNode: Equatable {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -50,10 +50,6 @@ public:
|
|||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (vec.size() % 2 == 0) { // 如果是偶数,还要多处理中间的一个
|
|
||||||
cur->next = vec[i];
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
cur->next = nullptr; // 注意结尾
|
cur->next = nullptr; // 注意结尾
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -177,6 +173,7 @@ public:
|
|||||||
Java:
|
Java:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
// 方法三
|
||||||
public class ReorderList {
|
public class ReorderList {
|
||||||
public void reorderList(ListNode head) {
|
public void reorderList(ListNode head) {
|
||||||
ListNode fast = head, slow = head;
|
ListNode fast = head, slow = head;
|
||||||
@ -219,6 +216,68 @@ public class ReorderList {
|
|||||||
return headNode.next;
|
return headNode.next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 方法一 Java实现,使用数组存储节点
|
||||||
|
class Solution {
|
||||||
|
public void reorderList(ListNode head) {
|
||||||
|
// 双指针的做法
|
||||||
|
ListNode cur = head;
|
||||||
|
// ArrayList底层是数组,可以使用下标随机访问
|
||||||
|
List<ListNode> list = new ArrayList<>();
|
||||||
|
while (cur != null){
|
||||||
|
list.add(cur);
|
||||||
|
cur = cur.next;
|
||||||
|
}
|
||||||
|
cur = head; // 重新回到头部
|
||||||
|
int l = 1, r = list.size() - 1; // 注意左边是从1开始
|
||||||
|
int count = 0;
|
||||||
|
while (l <= r){
|
||||||
|
if (count % 2 == 0){
|
||||||
|
// 偶数
|
||||||
|
cur.next = list.get(r);
|
||||||
|
r--;
|
||||||
|
}else {
|
||||||
|
// 奇数
|
||||||
|
cur.next = list.get(l);
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
// 每一次指针都需要移动
|
||||||
|
cur = cur.next;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
// 注意结尾要结束一波
|
||||||
|
cur.next = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 方法二:使用双端队列,简化了数组的操作,代码相对于前者更简洁(避免一些边界条件)
|
||||||
|
class Solution {
|
||||||
|
public void reorderList(ListNode head) {
|
||||||
|
// 使用双端队列的方法来解决
|
||||||
|
Deque<ListNode> de = new LinkedList<>();
|
||||||
|
// 这里是取head的下一个节点,head不需要再入队了,避免造成重复
|
||||||
|
ListNode cur = head.next;
|
||||||
|
while (cur != null){
|
||||||
|
de.offer(cur);
|
||||||
|
cur = cur.next;
|
||||||
|
}
|
||||||
|
cur = head; // 回到头部
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (!de.isEmpty()){
|
||||||
|
if (count % 2 == 0){
|
||||||
|
// 偶数,取出队列右边尾部的值
|
||||||
|
cur.next = de.pollLast();
|
||||||
|
}else {
|
||||||
|
// 奇数,取出队列左边头部的值
|
||||||
|
cur.next = de.poll();
|
||||||
|
}
|
||||||
|
cur = cur.next;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
cur.next = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
@ -280,12 +339,111 @@ class Solution:
|
|||||||
Go:
|
Go:
|
||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
// 方法一 使用数组存储节点
|
||||||
|
var reorderList = function(head, s = [], tmp) {
|
||||||
|
let cur = head;
|
||||||
|
// list是数组,可以使用下标随机访问
|
||||||
|
const list = [];
|
||||||
|
while(cur != null){
|
||||||
|
list.push(cur);
|
||||||
|
cur = cur.next;
|
||||||
|
}
|
||||||
|
cur = head; // 重新回到头部
|
||||||
|
let l = 1, r = list.length - 1; // 注意左边是从1开始
|
||||||
|
let count = 0;
|
||||||
|
while(l <= r){
|
||||||
|
if(count % 2 == 0){
|
||||||
|
// even
|
||||||
|
cur.next = list[r];
|
||||||
|
r--;
|
||||||
|
} else {
|
||||||
|
// odd
|
||||||
|
cur.next = list[l];
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
// 每一次指针都需要移动
|
||||||
|
cur = cur.next;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
// 注意结尾要结束一波
|
||||||
|
cur.next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法二 使用双端队列的方法来解决 js中运行很慢
|
||||||
|
var reorderList = function(head, s = [], tmp) {
|
||||||
|
// js数组作为双端队列
|
||||||
|
const deque = [];
|
||||||
|
// 这里是取head的下一个节点,head不需要再入队了,避免造成重复
|
||||||
|
let cur = head.next;
|
||||||
|
while(cur != null){
|
||||||
|
deque.push(cur);
|
||||||
|
cur = cur.next;
|
||||||
|
}
|
||||||
|
cur = head; // 回到头部
|
||||||
|
let count = 0;
|
||||||
|
while(deque.length !== 0){
|
||||||
|
if(count % 2 == 0){
|
||||||
|
// even,取出队列右边尾部的值
|
||||||
|
cur.next = deque.pop();
|
||||||
|
} else {
|
||||||
|
// odd, 取出队列左边头部的值
|
||||||
|
cur.next = deque.shift();
|
||||||
|
}
|
||||||
|
cur = cur.next;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
cur.next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//方法三 将链表分割成两个链表,然后把第二个链表反转,之后在通过两个链表拼接成新的链表
|
||||||
|
var reorderList = function(head, s = [], tmp) {
|
||||||
|
const reverseList = head => {
|
||||||
|
let headNode = new ListNode(0);
|
||||||
|
let cur = head;
|
||||||
|
let next = null;
|
||||||
|
while(cur != null){
|
||||||
|
next = cur.next;
|
||||||
|
cur.next = headNode.next;
|
||||||
|
headNode.next = cur;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
return headNode.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fast = head, slow = head;
|
||||||
|
//求出中点
|
||||||
|
while(fast.next != null && fast.next.next != null){
|
||||||
|
slow = slow.next;
|
||||||
|
fast = fast.next.next;
|
||||||
|
}
|
||||||
|
//right就是右半部分 12345 就是45 1234 就是34
|
||||||
|
let right = slow.next;
|
||||||
|
//断开左部分和右部分
|
||||||
|
slow.next = null;
|
||||||
|
//反转右部分 right就是反转后右部分的起点
|
||||||
|
right = reverseList(right);
|
||||||
|
//左部分的起点
|
||||||
|
let left = head;
|
||||||
|
//进行左右部分来回连接
|
||||||
|
//这里左部分的节点个数一定大于等于右部分的节点个数 因此只判断right即可
|
||||||
|
while (right != null) {
|
||||||
|
let curLeft = left.next;
|
||||||
|
left.next = right;
|
||||||
|
left = curLeft;
|
||||||
|
|
||||||
|
let curRight = right.next;
|
||||||
|
right.next = left;
|
||||||
|
right = curRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -248,4 +248,4 @@ class Solution:
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -553,4 +553,4 @@ func reverseWord(_ s: inout [Character]) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
|
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
|
||||||
|
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||||
|
</p>
|
||||||
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
同:[链表:链表相交](https://programmercarl.com/面试题02.07.链表相交.html)
|
同:[链表:链表相交](https://programmercarl.com/面试题02.07.链表相交.html)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
-----------------------
|
||||||
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -280,6 +280,7 @@ Go:
|
|||||||
Javascript:
|
Javascript:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
// 方法一:动态规划
|
||||||
const maxProfit = (k,prices) => {
|
const maxProfit = (k,prices) => {
|
||||||
if (prices == null || prices.length < 2 || k == 0) {
|
if (prices == null || prices.length < 2 || k == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -300,10 +301,34 @@ const maxProfit = (k,prices) => {
|
|||||||
|
|
||||||
return dp[prices.length - 1][2 * k];
|
return dp[prices.length - 1][2 * k];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 方法二:动态规划+空间优化
|
||||||
|
var maxProfit = function(k, prices) {
|
||||||
|
let n = prices.length;
|
||||||
|
let dp = new Array(2*k+1).fill(0);
|
||||||
|
// dp 买入状态初始化
|
||||||
|
for (let i = 1; i <= 2*k; i += 2) {
|
||||||
|
dp[i] = - prices[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i < n; i++) {
|
||||||
|
for (let j = 1; j < 2*k+1; j++) {
|
||||||
|
// j 为奇数:买入状态
|
||||||
|
if (j % 2) {
|
||||||
|
dp[j] = Math.max(dp[j], dp[j-1] - prices[i]);
|
||||||
|
} else {
|
||||||
|
// j为偶数:卖出状态
|
||||||
|
dp[j] = Math.max(dp[j], dp[j-1] + prices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[2*k];
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -7,6 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
# 189. 旋转数组
|
# 189. 旋转数组
|
||||||
|
|
||||||
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
|
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
|
||||||
@ -149,10 +149,10 @@ var rotate = function (nums, k) {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -198,4 +198,4 @@ const rob = nums => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -159,26 +159,28 @@ func getSum(n int) int {
|
|||||||
javaScript:
|
javaScript:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function getN(n) {
|
var isHappy = function (n) {
|
||||||
if (n == 1 || n == 0) return n;
|
let m = new Map()
|
||||||
let res = 0;
|
|
||||||
while (n) {
|
const getSum = (num) => {
|
||||||
res += (n % 10) * (n % 10);
|
let sum = 0
|
||||||
n = parseInt(n / 10);
|
while (n) {
|
||||||
|
sum += (n % 10) ** 2
|
||||||
|
n = Math.floor(n / 10)
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// n出现过,证明已陷入无限循环
|
||||||
|
if (m.has(n)) return false
|
||||||
|
if (n === 1) return true
|
||||||
|
m.set(n, 1)
|
||||||
|
n = getSum(n)
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var isHappy = function(n) {
|
// 方法二:使用环形链表的思想 说明出现闭环 退出循环
|
||||||
const sumSet = new Set();
|
|
||||||
while (n != 1 && !sumSet.has(n)) {
|
|
||||||
sumSet.add(n);
|
|
||||||
n = getN(n);
|
|
||||||
}
|
|
||||||
return n == 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 使用环形链表的思想 说明出现闭环 退出循环
|
|
||||||
var isHappy = function(n) {
|
var isHappy = function(n) {
|
||||||
if (getN(n) == 1) return true;
|
if (getN(n) == 1) return true;
|
||||||
let a = getN(n), b = getN(getN(n));
|
let a = getN(n), b = getN(getN(n));
|
||||||
@ -189,6 +191,30 @@ var isHappy = function(n) {
|
|||||||
}
|
}
|
||||||
return b === 1 || getN(b) === 1 ;
|
return b === 1 || getN(b) === 1 ;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 方法三:使用Set()更简洁
|
||||||
|
/**
|
||||||
|
* @param {number} n
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
var getSum = function (n) {
|
||||||
|
let sum = 0;
|
||||||
|
while (n) {
|
||||||
|
sum += (n % 10) ** 2;
|
||||||
|
n = Math.floor(n/10);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
var isHappy = function(n) {
|
||||||
|
let set = new Set(); // Set() 里的数是惟一的
|
||||||
|
// 如果在循环中某个值重复出现,说明此时陷入死循环,也就说明这个值不是快乐数
|
||||||
|
while (n !== 1 && !set.has(n)) {
|
||||||
|
set.add(n);
|
||||||
|
n = getSum(n);
|
||||||
|
}
|
||||||
|
return n === 1;
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Swift:
|
Swift:
|
||||||
@ -258,4 +284,4 @@ class Solution {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
**当然如果使用java ,python的话就不用手动管理内存了。**
|
**当然如果使用java ,python的话就不用手动管理内存了。**
|
||||||
|
|
||||||
还要说明一下,就算使用C++来做leetcode,如果移除一个节点之后,没有手动在内存中删除这个节点,leetcode依然也是可以通过的,只不过,内存使用的空间大一些而已,但建议依然要养生手动清理内存的习惯。
|
还要说明一下,就算使用C++来做leetcode,如果移除一个节点之后,没有手动在内存中删除这个节点,leetcode依然也是可以通过的,只不过,内存使用的空间大一些而已,但建议依然要养成手动清理内存的习惯。
|
||||||
|
|
||||||
这种情况下的移除操作,就是让节点next指针直接指向下下一个节点就可以了,
|
这种情况下的移除操作,就是让节点next指针直接指向下下一个节点就可以了,
|
||||||
|
|
||||||
@ -362,4 +362,4 @@ func removeElements(head *ListNode, val int) *ListNode {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -7,6 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
# 205. 同构字符串
|
# 205. 同构字符串
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/isomorphic-strings/)
|
[力扣题目链接](https://leetcode-cn.com/problems/isomorphic-strings/)
|
||||||
@ -119,11 +119,30 @@ func isIsomorphic(s string, t string) bool {
|
|||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
var isIsomorphic = function(s, t) {
|
||||||
|
let len = s.length;
|
||||||
|
if(len === 0) return true;
|
||||||
|
let maps = new Map();
|
||||||
|
let mapt = new Map();
|
||||||
|
for(let i = 0, j = 0; i < len; i++, j++){
|
||||||
|
if(!maps.has(s[i])){
|
||||||
|
maps.set(s[i],t[j]);// maps保存 s[i] 到 t[j]的映射
|
||||||
|
}
|
||||||
|
if(!mapt.has(t[j])){
|
||||||
|
mapt.set(t[j],s[i]);// mapt保存 t[j] 到 s[i]的映射
|
||||||
|
}
|
||||||
|
// 无法映射,返回 false
|
||||||
|
if(maps.get(s[i]) !== t[j] || mapt.get(t[j]) !== s[i]){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -27,9 +27,9 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
之前链表的头节点是元素1, 反转之后头结点就是元素5 ,这里并没有添加或者删除节点,仅仅是改表next指针的方向。
|
之前链表的头节点是元素1, 反转之后头结点就是元素5 ,这里并没有添加或者删除节点,仅仅是改变next指针的方向。
|
||||||
|
|
||||||
那么接下来看一看是如何反转呢?
|
那么接下来看一看是如何反转的呢?
|
||||||
|
|
||||||
我们拿有示例中的链表来举例,如动画所示:
|
我们拿有示例中的链表来举例,如动画所示:
|
||||||
|
|
||||||
@ -96,6 +96,28 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
我们可以发现,上面的递归写法和双指针法实质上都是从前往后翻转指针指向,其实还有另外一种与双指针法不同思路的递归写法:从后往前翻转指针指向。
|
||||||
|
|
||||||
|
具体代码如下(带详细注释):
|
||||||
|
|
||||||
|
```CPP
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
ListNode* reverseList(ListNode* head) {
|
||||||
|
// 边缘条件判断
|
||||||
|
if(head == NULL) return NULL;
|
||||||
|
if (head->next == NULL) return head;
|
||||||
|
|
||||||
|
// 递归调用,翻转第二个节点开始往后的链表
|
||||||
|
ListNode *last = reverseList(head->next);
|
||||||
|
// 翻转头节点与第二个节点的指向
|
||||||
|
head->next->next = head;
|
||||||
|
// 此时的 head 节点为尾节点,next 需要指向 NULL
|
||||||
|
head->next = NULL;
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
@ -135,13 +157,32 @@ class Solution {
|
|||||||
temp = cur.next;// 先保存下一个节点
|
temp = cur.next;// 先保存下一个节点
|
||||||
cur.next = prev;// 反转
|
cur.next = prev;// 反转
|
||||||
// 更新prev、cur位置
|
// 更新prev、cur位置
|
||||||
prev = cur;
|
// prev = cur;
|
||||||
cur = temp;
|
// cur = temp;
|
||||||
return reverse(prev, cur);
|
return reverse(cur, temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// 从后向前递归
|
||||||
|
class Solution {
|
||||||
|
ListNode reverseList(ListNode head) {
|
||||||
|
// 边缘条件判断
|
||||||
|
if(head == null) return null;
|
||||||
|
if (head.next == null) return head;
|
||||||
|
|
||||||
|
// 递归调用,翻转第二个节点开始往后的链表
|
||||||
|
ListNode last = reverseList(head.next);
|
||||||
|
// 翻转头节点与第二个节点的指向
|
||||||
|
head.next.next = head;
|
||||||
|
// 此时的 head 节点为尾节点,next 需要指向 NULL
|
||||||
|
head.next = null;
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Python迭代法:
|
Python迭代法:
|
||||||
```python
|
```python
|
||||||
#双指针
|
#双指针
|
||||||
@ -414,4 +455,4 @@ struct ListNode* reverseList(struct ListNode* head){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -297,4 +297,4 @@ class Solution {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -174,4 +174,4 @@ Go:
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
输出: [[1,2,6], [1,3,5], [2,3,4]]
|
输出: [[1,2,6], [1,3,5], [2,3,4]]
|
||||||
|
|
||||||
|
|
||||||
## 思路
|
# 思路
|
||||||
|
|
||||||
本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。
|
本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ if (sum > targetSum) { // 剪枝操作
|
|||||||
|
|
||||||
最后C++代码如下:
|
最后C++代码如下:
|
||||||
|
|
||||||
```c++
|
```CPP
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
vector<vector<int>> result; // 存放结果集
|
vector<vector<int>> result; // 存放结果集
|
||||||
@ -223,10 +223,10 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
# 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
## Java
|
||||||
|
|
||||||
模板方法
|
模板方法
|
||||||
```java
|
```java
|
||||||
@ -299,7 +299,8 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
## Python
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class Solution:
|
class Solution:
|
||||||
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
|
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
|
||||||
@ -320,10 +321,9 @@ class Solution:
|
|||||||
return res
|
return res
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
## Go:
|
||||||
|
|
||||||
|
回溯+减枝
|
||||||
> 回溯+减枝
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func combinationSum3(k int, n int) [][]int {
|
func combinationSum3(k int, n int) [][]int {
|
||||||
@ -353,7 +353,7 @@ func backTree(n,k,startIndex int,track *[]int,result *[][]int){
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
javaScript:
|
## javaScript:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// 等差数列
|
// 等差数列
|
||||||
@ -454,4 +454,4 @@ int** combinationSum3(int k, int n, int* returnSize, int** returnColumnSizes){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -204,7 +204,27 @@ class Solution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
|
class Solution {
|
||||||
|
// 迭代法
|
||||||
|
public int countNodes(TreeNode root) {
|
||||||
|
if (root == null) return 0;
|
||||||
|
Queue<TreeNode> queue = new LinkedList<>();
|
||||||
|
queue.offer(root);
|
||||||
|
int result = 0;
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
int size = queue.size();
|
||||||
|
while (size -- > 0) {
|
||||||
|
TreeNode cur = queue.poll();
|
||||||
|
result++;
|
||||||
|
if (cur.left != null) queue.offer(cur.left);
|
||||||
|
if (cur.right != null) queue.offer(cur.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
```java
|
```java
|
||||||
class Solution {
|
class Solution {
|
||||||
/**
|
/**
|
||||||
@ -435,4 +455,4 @@ var countNodes = function(root) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -112,7 +112,7 @@ public:
|
|||||||
|
|
||||||
# 优化
|
# 优化
|
||||||
|
|
||||||
其实这道题目就是用一个队里就够了。
|
其实这道题目就是用一个队列就够了。
|
||||||
|
|
||||||
**一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。**
|
**一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。**
|
||||||
|
|
||||||
@ -538,4 +538,4 @@ MyStack.prototype.empty = function() {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -363,7 +363,9 @@ class Solution:
|
|||||||
return root
|
return root
|
||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
|
递归版本的前序遍历
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
func invertTree(root *TreeNode) *TreeNode {
|
func invertTree(root *TreeNode) *TreeNode {
|
||||||
@ -381,6 +383,96 @@ func invertTree(root *TreeNode) *TreeNode {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
递归版本的后序遍历
|
||||||
|
|
||||||
|
```go
|
||||||
|
func invertTree(root *TreeNode) *TreeNode {
|
||||||
|
if root==nil{
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
invertTree(root.Left)//遍历左节点
|
||||||
|
invertTree(root.Right)//遍历右节点
|
||||||
|
root.Left,root.Right=root.Right,root.Left//交换
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
迭代版本的前序遍历
|
||||||
|
|
||||||
|
```go
|
||||||
|
func invertTree(root *TreeNode) *TreeNode {
|
||||||
|
stack:=[]*TreeNode{}
|
||||||
|
node:=root
|
||||||
|
for node!=nil||len(stack)>0{
|
||||||
|
for node!=nil{
|
||||||
|
node.Left,node.Right=node.Right,node.Left//交换
|
||||||
|
stack=append(stack,node)
|
||||||
|
node=node.Left
|
||||||
|
}
|
||||||
|
node=stack[len(stack)-1]
|
||||||
|
stack=stack[:len(stack)-1]
|
||||||
|
node=node.Right
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
迭代版本的后序遍历
|
||||||
|
|
||||||
|
```go
|
||||||
|
func invertTree(root *TreeNode) *TreeNode {
|
||||||
|
stack:=[]*TreeNode{}
|
||||||
|
node:=root
|
||||||
|
var prev *TreeNode
|
||||||
|
for node!=nil||len(stack)>0{
|
||||||
|
for node!=nil{
|
||||||
|
stack=append(stack,node)
|
||||||
|
node=node.Left
|
||||||
|
}
|
||||||
|
node=stack[len(stack)-1]
|
||||||
|
stack=stack[:len(stack)-1]
|
||||||
|
if node.Right==nil||node.Right==prev{
|
||||||
|
node.Left,node.Right=node.Right,node.Left//交换
|
||||||
|
prev=node
|
||||||
|
node=nil
|
||||||
|
}else {
|
||||||
|
stack=append(stack,node)
|
||||||
|
node=node.Right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
层序遍历
|
||||||
|
|
||||||
|
```go
|
||||||
|
func invertTree(root *TreeNode) *TreeNode {
|
||||||
|
if root==nil{
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
queue:=list.New()
|
||||||
|
node:=root
|
||||||
|
queue.PushBack(node)
|
||||||
|
for queue.Len()>0{
|
||||||
|
length:=queue.Len()
|
||||||
|
for i:=0;i<length;i++{
|
||||||
|
e:=queue.Remove(queue.Front()).(*TreeNode)
|
||||||
|
e.Left,e.Right=e.Right,e.Left//交换
|
||||||
|
if e.Left!=nil{
|
||||||
|
queue.PushBack(e.Left)
|
||||||
|
}
|
||||||
|
if e.Right!=nil{
|
||||||
|
queue.PushBack(e.Right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### JavaScript
|
### JavaScript
|
||||||
|
|
||||||
使用递归版本的前序遍历
|
使用递归版本的前序遍历
|
||||||
@ -522,4 +614,4 @@ struct TreeNode* invertTree(struct TreeNode* root){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -356,4 +356,4 @@ MyQueue.prototype.empty = function() {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -7,6 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
# 234.回文链表
|
# 234.回文链表
|
||||||
|
|
||||||
[力扣题目链接](https://leetcode-cn.com/problems/palindrome-linked-list/)
|
[力扣题目链接](https://leetcode-cn.com/problems/palindrome-linked-list/)
|
||||||
@ -284,13 +284,47 @@ class Solution:
|
|||||||
## JavaScript
|
## JavaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
var isPalindrome = function(head) {
|
||||||
|
const reverseList = head => {// 反转链表
|
||||||
|
let temp = null;
|
||||||
|
let pre = null;
|
||||||
|
while(head != null){
|
||||||
|
temp = head.next;
|
||||||
|
head.next = pre;
|
||||||
|
pre = head;
|
||||||
|
head = temp;
|
||||||
|
}
|
||||||
|
return pre;
|
||||||
|
}
|
||||||
|
// 如果为空或者仅有一个节点,返回true
|
||||||
|
if(!head && !head.next) return true;
|
||||||
|
let slow = head;
|
||||||
|
let fast = head;
|
||||||
|
let pre = head;
|
||||||
|
while(fast != null && fast.next != null){
|
||||||
|
pre = slow; // 记录slow的前一个结点
|
||||||
|
slow = slow.next;
|
||||||
|
fast = fast.next.next;
|
||||||
|
}
|
||||||
|
pre.next = null; // 分割两个链表
|
||||||
|
// 前半部分
|
||||||
|
let cur1 = head;
|
||||||
|
// 后半部分。这里使用了反转链表
|
||||||
|
let cur2 = reverseList(slow);
|
||||||
|
while(cur1 != null){
|
||||||
|
if(cur1.val != cur2.val) return false;
|
||||||
|
// 注意要移动两个结点
|
||||||
|
cur1 = cur1.next;
|
||||||
|
cur2 = cur2.next;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -234,7 +234,15 @@ public:
|
|||||||
## Java
|
## Java
|
||||||
|
|
||||||
递归法:
|
递归法:
|
||||||
|
```java
|
||||||
|
class Solution {
|
||||||
|
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
迭代法:
|
迭代法:
|
||||||
```java
|
```java
|
||||||
@ -260,17 +268,30 @@ class Solution {
|
|||||||
递归法:
|
递归法:
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
|
"""二叉搜索树的最近公共祖先 递归法"""
|
||||||
|
|
||||||
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
|
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
|
||||||
if not root: return root //中
|
if root.val > p.val and root.val > q.val:
|
||||||
if root.val >p.val and root.val > q.val:
|
return self.lowestCommonAncestor(root.left, p, q)
|
||||||
return self.lowestCommonAncestor(root.left,p,q) //左
|
if root.val < p.val and root.val < q.val:
|
||||||
elif root.val < p.val and root.val < q.val:
|
return self.lowestCommonAncestor(root.right, p, q)
|
||||||
return self.lowestCommonAncestor(root.right,p,q) //右
|
return root
|
||||||
else: return root
|
|
||||||
```
|
```
|
||||||
|
|
||||||
迭代法:
|
迭代法:
|
||||||
|
```python
|
||||||
|
class Solution:
|
||||||
|
"""二叉搜索树的最近公共祖先 迭代法"""
|
||||||
|
|
||||||
|
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
|
||||||
|
while True:
|
||||||
|
if root.val > p.val and root.val > q.val:
|
||||||
|
root = root.left
|
||||||
|
elif root.val < p.val and root.val < q.val:
|
||||||
|
root = root.right
|
||||||
|
else:
|
||||||
|
return root
|
||||||
|
```
|
||||||
|
|
||||||
## Go
|
## Go
|
||||||
|
|
||||||
@ -336,4 +357,4 @@ var lowestCommonAncestor = function(root, p, q) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -264,16 +264,21 @@ class Solution {
|
|||||||
## Python
|
## Python
|
||||||
|
|
||||||
```python
|
```python
|
||||||
//递归
|
|
||||||
class Solution:
|
class Solution:
|
||||||
|
"""二叉树的最近公共祖先 递归法"""
|
||||||
|
|
||||||
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
|
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
|
||||||
if not root or root == p or root == q: return root //找到了节点p或者q,或者遇到空节点
|
if not root or root == p or root == q:
|
||||||
left = self.lowestCommonAncestor(root.left,p,q) //左
|
return root
|
||||||
right = self.lowestCommonAncestor(root.right,p,q) //右
|
|
||||||
if left and right: return root //中: left和right不为空,root就是最近公共节点
|
left = self.lowestCommonAncestor(root.left, p, q)
|
||||||
elif left and not right: return left //目标节点是通过left返回的
|
right = self.lowestCommonAncestor(root.right, p, q)
|
||||||
elif not left and right: return right //目标节点是通过right返回的
|
|
||||||
else: return None //没找到
|
if left and right:
|
||||||
|
return root
|
||||||
|
if left:
|
||||||
|
return left
|
||||||
|
return right
|
||||||
```
|
```
|
||||||
|
|
||||||
## Go
|
## Go
|
||||||
@ -340,4 +345,4 @@ var lowestCommonAncestor = function(root, p, q) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -425,4 +425,4 @@ var maxSlidingWindow = function (nums, k) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -256,6 +256,25 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Rust:
|
||||||
|
```rust
|
||||||
|
impl Solution {
|
||||||
|
pub fn is_anagram(s: String, t: String) -> bool {
|
||||||
|
let mut record = vec![0; 26];
|
||||||
|
|
||||||
|
let baseChar = 'a';
|
||||||
|
|
||||||
|
for byte in s.bytes() {
|
||||||
|
record[byte as usize - baseChar as usize] += 1;
|
||||||
|
}
|
||||||
|
for byte in t.bytes() {
|
||||||
|
record[byte as usize - baseChar as usize] -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
record.iter().filter(|x| **x != 0).count() == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
## 相关题目
|
## 相关题目
|
||||||
|
|
||||||
* 383.赎金信
|
* 383.赎金信
|
||||||
@ -267,4 +286,4 @@ class Solution {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -367,28 +367,106 @@ class Solution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
```java
|
||||||
Python:
|
// 解法2
|
||||||
```Python
|
class Solution {
|
||||||
|
/**
|
||||||
|
* 迭代法
|
||||||
|
*/
|
||||||
|
public List<String> binaryTreePaths(TreeNode root) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (root == null)
|
||||||
|
return result;
|
||||||
|
Stack<Object> stack = new Stack<>();
|
||||||
|
// 节点和路径同时入栈
|
||||||
|
stack.push(root);
|
||||||
|
stack.push(root.val + "");
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
// 节点和路径同时出栈
|
||||||
|
String path = (String) stack.pop();
|
||||||
|
TreeNode node = (TreeNode) stack.pop();
|
||||||
|
// 若找到叶子节点
|
||||||
|
if (node.left == null && node.right == null) {
|
||||||
|
result.add(path);
|
||||||
|
}
|
||||||
|
//右子节点不为空
|
||||||
|
if (node.right != null) {
|
||||||
|
stack.push(node.right);
|
||||||
|
stack.push(path + "->" + node.right.val);
|
||||||
|
}
|
||||||
|
//左子节点不为空
|
||||||
|
if (node.left != null) {
|
||||||
|
stack.push(node.left);
|
||||||
|
stack.push(path + "->" + node.left.val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
Python:
|
||||||
|
递归法+隐形回溯
|
||||||
|
```Python3
|
||||||
|
# Definition for a binary tree node.
|
||||||
|
# class TreeNode:
|
||||||
|
# def __init__(self, val=0, left=None, right=None):
|
||||||
|
# self.val = val
|
||||||
|
# self.left = left
|
||||||
|
# self.right = right
|
||||||
class Solution:
|
class Solution:
|
||||||
def binaryTreePaths(self, root: TreeNode) -> List[str]:
|
def binaryTreePaths(self, root: TreeNode) -> List[str]:
|
||||||
path=[]
|
path = ''
|
||||||
res=[]
|
result = []
|
||||||
def backtrace(root, path):
|
if not root: return result
|
||||||
if not root:return
|
self.traversal(root, path, result)
|
||||||
path.append(root.val)
|
return result
|
||||||
if (not root.left)and (not root.right):
|
|
||||||
res.append(path[:])
|
def traversal(self, cur: TreeNode, path: str, result: List[str]) -> None:
|
||||||
ways=[]
|
path += str(cur.val)
|
||||||
if root.left:ways.append(root.left)
|
# 若当前节点为leave,直接输出
|
||||||
if root.right:ways.append(root.right)
|
if not cur.left and not cur.right:
|
||||||
for way in ways:
|
result.append(path)
|
||||||
backtrace(way,path)
|
|
||||||
path.pop()
|
|
||||||
backtrace(root,path)
|
|
||||||
return ["->".join(list(map(str,i))) for i in res]
|
|
||||||
|
|
||||||
|
if cur.left:
|
||||||
|
# + '->' 是隐藏回溯
|
||||||
|
self.traversal(cur.left, path + '->', result)
|
||||||
|
|
||||||
|
if cur.right:
|
||||||
|
self.traversal(cur.right, path + '->', result)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
迭代法:
|
||||||
|
|
||||||
|
```python3
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
|
||||||
|
class Solution:
|
||||||
|
"""二叉树的所有路径 迭代法"""
|
||||||
|
|
||||||
|
def binaryTreePaths(self, root: TreeNode) -> List[str]:
|
||||||
|
# 题目中节点数至少为1
|
||||||
|
stack, path_st, result = deque([root]), deque(), []
|
||||||
|
path_st.append(str(root.val))
|
||||||
|
|
||||||
|
while stack:
|
||||||
|
cur = stack.pop()
|
||||||
|
path = path_st.pop()
|
||||||
|
# 如果当前节点为叶子节点,添加路径到结果中
|
||||||
|
if not (cur.left or cur.right):
|
||||||
|
result.append(path)
|
||||||
|
if cur.right:
|
||||||
|
stack.append(cur.right)
|
||||||
|
path_st.append(path + '->' + str(cur.right.val))
|
||||||
|
if cur.left:
|
||||||
|
stack.append(cur.left)
|
||||||
|
path_st.append(path + '->' + str(cur.left.val))
|
||||||
|
|
||||||
|
return result
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
```go
|
```go
|
||||||
@ -413,7 +491,7 @@ func binaryTreePaths(root *TreeNode) []string {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
---
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
|
||||||
1.递归版本
|
1.递归版本
|
||||||
@ -447,4 +525,4 @@ var binaryTreePaths = function(root) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -334,8 +334,8 @@ var numSquares1 = function(n) {
|
|||||||
let dp = new Array(n + 1).fill(Infinity)
|
let dp = new Array(n + 1).fill(Infinity)
|
||||||
dp[0] = 0
|
dp[0] = 0
|
||||||
|
|
||||||
for(let i = 0; i <= n; i++) {
|
for(let i = 1; i**2 <= n; i++) {
|
||||||
let val = i * i
|
let val = i**2
|
||||||
for(let j = val; j <= n; j++) {
|
for(let j = val; j <= n; j++) {
|
||||||
dp[j] = Math.min(dp[j], dp[j - val] + 1)
|
dp[j] = Math.min(dp[j], dp[j - val] + 1)
|
||||||
}
|
}
|
||||||
@ -361,4 +361,4 @@ var numSquares2 = function(n) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||||
@ -6,6 +5,7 @@
|
|||||||
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
|
|
||||||
# 动态规划:一样的套路,再求一次完全平方数
|
# 动态规划:一样的套路,再求一次完全平方数
|
||||||
|
|
||||||
# 283. 移动零
|
# 283. 移动零
|
||||||
@ -95,10 +95,25 @@ Python:
|
|||||||
Go:
|
Go:
|
||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
```javascript
|
||||||
|
var moveZeroes = function(nums) {
|
||||||
|
let slow = 0;
|
||||||
|
for(let fast = 0; fast < nums.length; fast++){
|
||||||
|
if(nums[fast] != 0){//找到非0的元素
|
||||||
|
nums[slow] = nums[fast];//把非0的元素赋值给数组慢指针指向的索引处的值
|
||||||
|
slow++;//慢指针向右移动
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 后面的元素全变成 0
|
||||||
|
for(let j = slow; j < nums.length; j++){
|
||||||
|
nums[j] = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
|
<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=450> </img></div>
|
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
1. dp[i]的定义
|
1. dp[i]的定义
|
||||||
|
|
||||||
**dp[i]表示i之前包括i的最长上升子序列**。
|
**dp[i]表示i之前包括i的最长上升子序列的长度**。
|
||||||
|
|
||||||
2. 状态转移方程
|
2. 状态转移方程
|
||||||
|
|
||||||
@ -202,4 +202,4 @@ const lengthOfLIS = (nums) => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
|
|
||||||
## 思路
|
## 思路
|
||||||
|
|
||||||
> 之前我们在[动态规划:最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html)讲过一次这道题目,讲解的过程感觉不是很严谨,和录友们也聊过这个问题,本着对大家负责的态度,有问题的地方我都会及时纠正,所以重新发文讲解一下。
|
|
||||||
|
|
||||||
相对于[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html),本题加上了一个冷冻期
|
相对于[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html),本题加上了一个冷冻期
|
||||||
|
|
||||||
@ -238,4 +237,4 @@ const maxProfit = (prices) => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -330,4 +330,4 @@ const coinChange = (coins, amount) => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -450,4 +450,4 @@ var findItinerary = function(tickets) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -368,6 +368,41 @@ class Solution:
|
|||||||
return (val1, val2)
|
return (val1, val2)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Go:
|
||||||
|
|
||||||
|
动态规划
|
||||||
|
|
||||||
|
```go
|
||||||
|
func rob(root *TreeNode) int {
|
||||||
|
res := robTree(root)
|
||||||
|
return max(res[0], res[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func robTree(cur *TreeNode) []int {
|
||||||
|
if cur == nil {
|
||||||
|
return []int{0, 0}
|
||||||
|
}
|
||||||
|
// 后序遍历
|
||||||
|
left := robTree(cur.Left)
|
||||||
|
right := robTree(cur.Right)
|
||||||
|
|
||||||
|
// 考虑去偷当前的屋子
|
||||||
|
robCur := cur.Val + left[0] + right[0]
|
||||||
|
// 考虑不去偷当前的屋子
|
||||||
|
notRobCur := max(left[0], left[1]) + max(right[0], right[1])
|
||||||
|
|
||||||
|
// 注意顺序:0:不偷,1:去偷
|
||||||
|
return []int{notRobCur, robCur}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
JavaScript:
|
JavaScript:
|
||||||
|
|
||||||
> 动态规划
|
> 动态规划
|
||||||
@ -402,4 +437,4 @@ const rob = root => {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -276,4 +276,4 @@ var integerBreak = function(n) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -206,6 +206,7 @@ var reverseString = function(s) {
|
|||||||
Swift:
|
Swift:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
|
// 双指针 - 元组
|
||||||
func reverseString(_ s: inout [Character]) {
|
func reverseString(_ s: inout [Character]) {
|
||||||
var l = 0
|
var l = 0
|
||||||
var r = s.count - 1
|
var r = s.count - 1
|
||||||
@ -216,6 +217,7 @@ func reverseString(_ s: inout [Character]) {
|
|||||||
r -= 1
|
r -= 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
C:
|
C:
|
||||||
@ -228,6 +230,7 @@ void reverseString(char* s, int sSize){
|
|||||||
char temp = s[left];
|
char temp = s[left];
|
||||||
s[left++] = s[right];
|
s[left++] = s[right];
|
||||||
s[right--] = temp;
|
s[right--] = temp;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -237,4 +240,4 @@ void reverseString(char* s, int sSize){
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -189,6 +189,79 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
```go
|
||||||
|
//方法一:小顶堆
|
||||||
|
func topKFrequent(nums []int, k int) []int {
|
||||||
|
map_num:=map[int]int{}
|
||||||
|
//记录每个元素出现的次数
|
||||||
|
for _,item:=range nums{
|
||||||
|
map_num[item]++
|
||||||
|
}
|
||||||
|
h:=&IHeap{}
|
||||||
|
heap.Init(h)
|
||||||
|
//所有元素入堆,堆的长度为k
|
||||||
|
for key,value:=range map_num{
|
||||||
|
heap.Push(h,[2]int{key,value})
|
||||||
|
if h.Len()>k{
|
||||||
|
heap.Pop(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res:=make([]int,k)
|
||||||
|
//按顺序返回堆中的元素
|
||||||
|
for i:=0;i<k;i++{
|
||||||
|
res[k-i-1]=heap.Pop(h).([2]int)[0]
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建小顶堆
|
||||||
|
type IHeap [][2]int
|
||||||
|
|
||||||
|
func (h IHeap) Len()int {
|
||||||
|
return len(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h IHeap) Less (i,j int) bool {
|
||||||
|
return h[i][1]<h[j][1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h IHeap) Swap(i,j int) {
|
||||||
|
h[i],h[j]=h[j],h[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *IHeap) Push(x interface{}){
|
||||||
|
*h=append(*h,x.([2]int))
|
||||||
|
}
|
||||||
|
func (h *IHeap) Pop() interface{}{
|
||||||
|
old:=*h
|
||||||
|
n:=len(old)
|
||||||
|
x:=old[n-1]
|
||||||
|
*h=old[0:n-1]
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//方法二:利用O(logn)排序
|
||||||
|
func topKFrequent(nums []int, k int) []int {
|
||||||
|
ans:=[]int{}
|
||||||
|
map_num:=map[int]int{}
|
||||||
|
for _,item:=range nums {
|
||||||
|
map_num[item]++
|
||||||
|
}
|
||||||
|
for key,_:=range map_num{
|
||||||
|
ans=append(ans,key)
|
||||||
|
}
|
||||||
|
//核心思想:排序
|
||||||
|
//可以不用包函数,自己实现快排
|
||||||
|
sort.Slice(ans,func (a,b int)bool{
|
||||||
|
return map_num[ans[a]]>map_num[ans[b]]
|
||||||
|
})
|
||||||
|
return ans[:k]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
javaScript:
|
javaScript:
|
||||||
```js
|
```js
|
||||||
@ -291,4 +364,4 @@ PriorityQueue.prototype.compare = function(index1, index2) {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -117,7 +117,7 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python3:
|
||||||
```python
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
|
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
|
||||||
@ -238,6 +238,25 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Rust:
|
||||||
|
```rust
|
||||||
|
use std::collections::HashSet;
|
||||||
|
impl Solution {
|
||||||
|
pub fn intersection(nums1: Vec<i32>, nums2: Vec<i32>) -> Vec<i32> {
|
||||||
|
let mut resultSet: HashSet<i32> = HashSet::with_capacity(1000);
|
||||||
|
let nums1Set: HashSet<i32> = nums1.into_iter().collect();
|
||||||
|
|
||||||
|
for num in nums2.iter() {
|
||||||
|
if nums1Set.contains(num) {
|
||||||
|
resultSet.insert(*num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret: Vec<i32> = resultSet.into_iter().collect();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
## 相关题目
|
## 相关题目
|
||||||
|
|
||||||
* 350.两个数组的交集 II
|
* 350.两个数组的交集 II
|
||||||
@ -247,4 +266,4 @@ class Solution {
|
|||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user