update content

This commit is contained in:
labuladong 2024-03-19 18:20:32 +08:00
parent 0b4b9dd696
commit d17d0cde75
73 changed files with 1102 additions and 1710 deletions

View File

@ -129,32 +129,30 @@ PDF 共两本一本《labuladong 的算法秘籍》类似教材,帮你系
### [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
### [准备工作:安装刷题全家桶](https://labuladong.github.io/article/fname.html?fname=全家桶简介)
* [算法可视化功能简介(必读)](https://labuladong.github.io/article/fname.html?fname=可视化简介)
* [配套 Chrome 刷题插件(必装)](https://labuladong.github.io/article/fname.html?fname=chrome插件简介)
* [算法可视化面板简介(必读)](https://labuladong.github.io/article/fname.html?fname=可视化简介)
* [配套 Chrome 刷题插件](https://labuladong.github.io/article/fname.html?fname=chrome插件简介)
* [配套 vscode 刷题插件](https://labuladong.github.io/article/fname.html?fname=vscode插件简介)
* [配套 JetBrains 刷题插件](https://labuladong.github.io/article/fname.html?fname=jb插件简介)
* [数据结构精品课](https://labuladong.github.io/article/fname.html?fname=ds课程简介)
* [二叉树递归专题课](https://labuladong.github.io/article/fname.html?fname=tree课程简介)
* [30 天刷题打卡挑战(升级版)](https://labuladong.github.io/article/fname.html?fname=打卡挑战简介)
* [30 天刷题打卡挑战](https://labuladong.github.io/article/fname.html?fname=打卡挑战简介)
* [使用可视化面板的 JavaScript 基础](https://labuladong.github.io/article/fname.html?fname=面板js基础)
* [学习本站所需的 Java 基础](https://labuladong.github.io/article/fname.html?fname=网站Java基础)
### [第零章、核心框架汇总](https://labuladong.github.io/algo/)
* [学习算法和刷题的框架思维](https://labuladong.github.io/article/fname.html?fname=学习数据结构和算法的高效方法)
* [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
* [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
* [双指针技巧秒杀七道链表题目](https://labuladong.github.io/article/fname.html?fname=链表技巧)
* [双指针技巧秒杀七道数组题目](https://labuladong.github.io/article/fname.html?fname=双指针技巧)
* [东哥带你刷二叉树(纲领篇)](https://labuladong.github.io/article/fname.html?fname=二叉树总结)
* [动态规划解题套路框架](https://labuladong.github.io/article/fname.html?fname=动态规划详解进阶)
* [回溯算法解题套路框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版)
* [回溯算法秒杀所有排列/组合/子集问题](https://labuladong.github.io/article/fname.html?fname=子集排列组合)
* [球盒模型:回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分)
* [BFS 算法解题套路框架](https://labuladong.github.io/article/fname.html?fname=BFS框架)
* [我写了首诗,把二分搜索算法变成了默写题](https://labuladong.github.io/article/fname.html?fname=二分查找详解)
* [我写了首诗,把滑动窗口算法变成了默写题](https://labuladong.github.io/article/fname.html?fname=滑动窗口技巧进阶)
* [一个方法团灭 LeetCode 股票买卖问题](https://labuladong.github.io/article/fname.html?fname=团灭股票问题)
* [一个方法团灭 LeetCode 打家劫舍问题](https://labuladong.github.io/article/fname.html?fname=抢房子)
* [一个方法团灭 nSum 问题](https://labuladong.github.io/article/fname.html?fname=nSum)
* [算法时空复杂度分析实用指南](https://labuladong.github.io/article/fname.html?fname=时间复杂度)
* [算法笔试「骗分」套路](https://labuladong.github.io/article/fname.html?fname=刷题技巧)
### [第一章、手把手刷数据结构](https://labuladong.github.io/algo/)
@ -166,6 +164,7 @@ PDF 共两本一本《labuladong 的算法秘籍》类似教材,帮你系
* [手把手刷数组算法](https://labuladong.github.io/algo/)
* [双指针技巧秒杀七道数组题目](https://labuladong.github.io/article/fname.html?fname=双指针技巧)
* [一个方法团灭 nSum 问题](https://labuladong.github.io/article/fname.html?fname=nSum)
* [小而美的算法技巧:前缀和数组](https://labuladong.github.io/article/fname.html?fname=前缀和技巧)
* [小而美的算法技巧:差分数组](https://labuladong.github.io/article/fname.html?fname=差分技巧)
* [二维数组的花式遍历技巧](https://labuladong.github.io/article/fname.html?fname=花式遍历)
@ -251,6 +250,7 @@ PDF 共两本一本《labuladong 的算法秘籍》类似教材,帮你系
* [一个方法团灭 LeetCode 股票买卖问题](https://labuladong.github.io/article/fname.html?fname=团灭股票问题)
* [贪心类型问题](https://labuladong.github.io/algo/)
* [老司机加油算法](https://labuladong.github.io/article/fname.html?fname=老司机)
* [贪心算法之区间调度问题](https://labuladong.github.io/article/fname.html?fname=贪心算法之区间调度问题)
* [扫描线技巧:安排会议室](https://labuladong.github.io/article/fname.html?fname=安排会议室)
* [剪视频剪出一个贪心算法](https://labuladong.github.io/article/fname.html?fname=剪视频)
@ -260,7 +260,7 @@ PDF 共两本一本《labuladong 的算法秘籍》类似教材,帮你系
* [暴力搜索算法](https://labuladong.github.io/algo/)
* [回溯算法解题套路框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版)
* [回溯算法秒杀所有排列/组合/子集问题](https://labuladong.github.io/article/fname.html?fname=子集排列组合)
* [回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分)
* [球盒模型:回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分)
* [一文秒杀所有岛屿题目](https://labuladong.github.io/article/fname.html?fname=岛屿题目)
* [回溯算法最佳实践:解数独](https://labuladong.github.io/article/fname.html?fname=sudoku)
* [回溯算法最佳实践:括号生成](https://labuladong.github.io/article/fname.html?fname=合法括号生成)
@ -278,6 +278,8 @@ PDF 共两本一本《labuladong 的算法秘籍》类似教材,帮你系
* [如何同时寻找缺失和重复的元素](https://labuladong.github.io/article/fname.html?fname=缺失和重复的元素)
* [经典面试题](https://labuladong.github.io/algo/)
* [算法笔试「骗分」套路](https://labuladong.github.io/article/fname.html?fname=刷题技巧)
* [一文秒杀所有丑数系列问题](https://labuladong.github.io/article/fname.html?fname=丑数)
* [分治算法详解:运算优先级](https://labuladong.github.io/article/fname.html?fname=分治算法)
* [一个方法解决三道区间问题](https://labuladong.github.io/article/fname.html?fname=区间问题合集)
* [谁能想到,斗地主也能玩出算法](https://labuladong.github.io/article/fname.html?fname=斗地主)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -81,6 +81,6 @@ int longestCommonSubsequence(String s1, String s2);
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_6298793ae4b09dda12708be8/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=LCS) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -21,7 +21,11 @@
**-----------**
> tip阅读本文之前建议你先学习一下另一种字符串匹配算法[Rabin Karp 字符匹配算法](https://labuladong.github.io/article/fname.html?fname=rabinkarp)。
::: tip
阅读本文之前,建议你先学习一下另一种字符串匹配算法:[Rabin Karp 字符匹配算法](https://labuladong.github.io/article/fname.html?fname=rabinkarp)。
:::
KMP 算法Knuth-Morris-Pratt 算法)是一个著名的字符串匹配算法,效率很高,但是确实有点复杂。
@ -33,7 +37,11 @@ KMP 算法Knuth-Morris-Pratt 算法)是一个著名的字符串匹配算法
读者见过的 KMP 算法应该是,一波诡异的操作处理 `pat` 后形成一个一维的数组 `next`,然后根据这个数组经过又一波复杂操作去匹配 `txt`。时间复杂度 O(N),空间复杂度 O(M)。其实它这个 `next` 数组就相当于 `dp` 数组,其中元素的含义跟 `pat` 的前缀和后缀有关,判定规则比较复杂,不好理解。**本文则用一个二维的 `dp` 数组(但空间复杂度还是 O(M)),重新定义其中元素的含义,使得代码长度大大减少,可解释性大大提高**。
> note本文的代码参考《算法4》原代码使用的数组名称是 `dfa`(确定有限状态机),因为我们的公众号之前有一系列动态规划的文章,就不说这么高大上的名词了,我对书中代码进行了一点修改,并沿用 `dp` 数组的名称。
::: note
本文的代码参考《算法4》原代码使用的数组名称是 `dfa`(确定有限状态机),因为我们的公众号之前有一系列动态规划的文章,就不说这么高大上的名词了,我对书中代码进行了一点修改,并沿用 `dp` 数组的名称。
:::
### 一、KMP 算法概述
@ -104,7 +112,11 @@ pat = "aaab"
![](https://labuladong.github.io/pictures/kmp/txt2.jpg)
> note这个`j` 不要理解为索引,它的含义更准确地说应该是**状态**state所以它会出现这个奇怪的位置后文会详述。
::: note
这个`j` 不要理解为索引,它的含义更准确地说应该是**状态**state所以它会出现这个奇怪的位置后文会详述。
:::
而对于 `txt2` 的下面这个即将出现的未匹配情况:
@ -432,7 +444,7 @@ KMP 算法也就是动态规划那点事,我们的公众号文章目录有一
<details class="hint-container details">
<summary><strong>引用本文的文章</strong></summary>
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [滑动窗口算法延伸Rabin Karp 字符匹配算法](https://labuladong.github.io/article/fname.html?fname=rabinkarp)
</details><hr>
@ -443,7 +455,7 @@ KMP 算法也就是动态规划那点事,我们的公众号文章目录有一
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -248,7 +248,7 @@ int stoneGame(int[] piles) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -234,7 +234,7 @@ def dp(n, a_num, copy):
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -146,7 +146,7 @@ bool dp(string& s, int i, string& p, int j);
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_6298796ae4b01a4852072fb9/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=动态规划之正则表达) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -53,7 +53,11 @@ int lengthOfLIS(int[] nums);
**我们的定义是这样的:`dp[i]` 表示以 `nums[i]` 这个数结尾的最长递增子序列的长度**。
> info为什么这样定义呢这是解决子序列问题的一个套路后文 [动态规划之子序列问题解题模板](https://labuladong.github.io/article/fname.html?fname=子序列问题模板) 总结了几种常见套路。你读完本章所有的动态规划问题,就会发现 `dp` 数组的定义方法也就那几种。
::: info
为什么这样定义呢?这是解决子序列问题的一个套路,后文 [动态规划之子序列问题解题模板](https://labuladong.github.io/article/fname.html?fname=子序列问题模板) 总结了几种常见套路。你读完本章所有的动态规划问题,就会发现 `dp` 数组的定义方法也就那几种。
:::
根据这个定义,我们就可以推出 base case`dp[i]` 初始值为 1因为以 `nums[i]` 结尾的最长递增子序列起码要包含它自己。
@ -186,7 +190,11 @@ int lengthOfLIS(int[] nums) {
我们只要把处理扑克牌的过程编程写出来即可。每次处理一张扑克牌不是要找一个合适的牌堆顶来放吗,牌堆顶的牌不是**有序**吗,这就能用到二分查找了:用二分查找来搜索当前牌应放置的位置。
> tip前文 [二分查找算法详解](https://labuladong.github.io/article/fname.html?fname=二分查找详解) 详细介绍了二分查找的细节及变体,这里就完美应用上了,如果没读过强烈建议阅读。
::: tip
前文 [二分查找算法详解](https://labuladong.github.io/article/fname.html?fname=二分查找详解) 详细介绍了二分查找的细节及变体,这里就完美应用上了,如果没读过强烈建议阅读。
:::
<!-- muliti_language -->
```java
@ -311,7 +319,7 @@ int lengthOfLIS(int[] nums) {
- [动态规划穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=动归两种视角)
- [动态规划解题套路框架](https://labuladong.github.io/article/fname.html?fname=动态规划详解进阶)
- [动态规划设计:最大子数组](https://labuladong.github.io/article/fname.html?fname=最大子数组)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [最优子结构原理和 dp 数组遍历方向](https://labuladong.github.io/article/fname.html?fname=最优子结构)
</details><hr>
@ -339,7 +347,7 @@ int lengthOfLIS(int[] nums) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -93,7 +93,11 @@ int fib(int N) {
![](https://labuladong.github.io/pictures/动态规划详解进阶/1.jpg)
> tip但凡遇到需要递归的问题最好都画出递归树这对你分析算法的复杂度寻找算法低效的原因都有巨大帮助。
::: tip
但凡遇到需要递归的问题,最好都画出递归树,这对你分析算法的复杂度,寻找算法低效的原因都有巨大帮助。
:::
这个递归树怎么理解?就是说想要计算原问题 `f(20)`,我就得先计算出子问题 `f(19)``f(18)`,然后要计算 `f(19)`,我就要先算出子问题 `f(18)``f(17)`,以此类推。最后遇到 `f(1)` 或者 `f(2)` 的时候,结果已知,就能直接返回结果,递归树不再向下生长了。
@ -269,7 +273,11 @@ int coinChange(int[] coins, int amount);
回到凑零钱问题,为什么说它符合最优子结构呢?假设你有面值为 `1, 2, 5` 的硬币,你想求 `amount = 11` 时的最少硬币数(原问题),如果你知道凑出 `amount = 10, 9, 6` 的最少硬币数(子问题),你只需要把子问题的答案加一(再选一枚面值为 `1, 2, 5` 的硬币),求个最小值,就是原问题的答案。因为硬币的数量是没有限制的,所以子问题之间没有相互制,是互相独立的。
> tip关于最优子结构的问题后文 [动态规划答疑篇](https://labuladong.github.io/article/fname.html?fname=最优子结构) 还会再举例探讨。
::: tip
关于最优子结构的问题,后文 [动态规划答疑篇](https://labuladong.github.io/article/fname.html?fname=最优子结构) 还会再举例探讨。
:::
那么,既然知道了这是个动态规划问题,就要思考如何列出正确的状态转移方程?
@ -332,7 +340,11 @@ int dp(int[] coins, int amount) {
}
```
> note这里 `coinChange``dp` 函数的签名完全一样,所以理论上不需要额外写一个 `dp` 函数。但为了后文讲解方便,这里还是另写一个 `dp` 函数来实现主要逻辑。
::: note
这里 `coinChange``dp` 函数的签名完全一样,所以理论上不需要额外写一个 `dp` 函数。但为了后文讲解方便,这里还是另写一个 `dp` 函数来实现主要逻辑。
:::
> 另外,我经常看到有人问,子问题的结果为什么要加 1`subProblem + 1`),而不是加硬币金额之类的。我这里统一提示一下,动态规划问题的关键是 `dp` 函数/数组的定义,你这个函数的返回值代表什么?你回过头去搞清楚这一点,然后就知道为什么要给子问题的返回值加 1 了。
@ -430,7 +442,11 @@ int coinChange(int[] coins, int amount) {
}
```
> info为啥 `dp` 数组中的值都初始化为 `amount + 1` 呢,因为凑成 `amount` 金额的硬币数最多只可能等于 `amount`(全用 1 元面值的硬币),所以初始化为 `amount + 1` 就相当于初始化为正无穷,便于后续取最小值。为啥不直接初始化为 int 型的最大值 `Integer.MAX_VALUE` 呢?因为后面有 `dp[i - coin] + 1`,这就会导致整型溢出。
::: info
为啥 `dp` 数组中的值都初始化为 `amount + 1` 呢,因为凑成 `amount` 金额的硬币数最多只可能等于 `amount`(全用 1 元面值的硬币),所以初始化为 `amount + 1` 就相当于初始化为正无穷,便于后续取最小值。为啥不直接初始化为 int 型的最大值 `Integer.MAX_VALUE` 呢?因为后面有 `dp[i - coin] + 1`,这就会导致整型溢出。
:::
![](https://labuladong.github.io/pictures/动态规划详解进阶/6.jpg)
@ -475,12 +491,10 @@ int coinChange(int[] coins, int amount) {
- [学习算法和刷题的框架思维](https://labuladong.github.io/article/fname.html?fname=学习数据结构和算法的高效方法)
- [对动态规划进行降维打击](https://labuladong.github.io/article/fname.html?fname=状态压缩技巧)
- [归并排序详解及应用](https://labuladong.github.io/article/fname.html?fname=归并排序)
- [当老司机学会了贪心算法](https://labuladong.github.io/article/fname.html?fname=老司机)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [旅游省钱大法:加权最短路径](https://labuladong.github.io/article/fname.html?fname=旅行最短路径)
- [最优子结构原理和 dp 数组遍历方向](https://labuladong.github.io/article/fname.html?fname=最优子结构)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
- [算法可视化功能简介(必读)](https://labuladong.github.io/article/fname.html?fname=可视化简介)
- [算法可视化面板简介(必读)](https://labuladong.github.io/article/fname.html?fname=可视化简介)
- [算法学习和心流体验](https://labuladong.github.io/article/fname.html?fname=心流)
- [算法时空复杂度分析实用指南](https://labuladong.github.io/article/fname.html?fname=时间复杂度)
- [算法笔试「骗分」套路](https://labuladong.github.io/article/fname.html?fname=刷题技巧)
@ -490,6 +504,7 @@ int coinChange(int[] coins, int amount) {
- [经典动态规划:戳气球](https://labuladong.github.io/article/fname.html?fname=扎气球)
- [经典动态规划:最长公共子序列](https://labuladong.github.io/article/fname.html?fname=LCS)
- [经典动态规划:编辑距离](https://labuladong.github.io/article/fname.html?fname=编辑距离)
- [老司机加油算法](https://labuladong.github.io/article/fname.html?fname=老司机)
</details><hr>
@ -504,6 +519,7 @@ int coinChange(int[] coins, int amount) {
| LeetCode | 力扣 |
| :----: | :----: |
| [111. Minimum Depth of Binary Tree](https://leetcode.com/problems/minimum-depth-of-binary-tree/?show=1) | [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/?show=1) |
| [112. Path Sum](https://leetcode.com/problems/path-sum/?show=1) | [112. 路径总和](https://leetcode.cn/problems/path-sum/?show=1) |
| [115. Distinct Subsequences](https://leetcode.com/problems/distinct-subsequences/?show=1) | [115. 不同的子序列](https://leetcode.cn/problems/distinct-subsequences/?show=1) |
| [139. Word Break](https://leetcode.com/problems/word-break/?show=1) | [139. 单词拆分](https://leetcode.cn/problems/word-break/?show=1) |
@ -537,7 +553,7 @@ int coinChange(int[] coins, int amount) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -472,6 +472,6 @@ class Solution {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -79,7 +79,11 @@ for 状态1 in 状态1的所有取值
但问题是,并不是每天都可以任意选择这三种选择的,因为 `sell` 必须在 `buy` 之后,`buy` 必须在 `sell` 之后。那么 `rest` 操作还应该分两种状态,一种是 `buy` 之后的 `rest`(持有了股票),一种是 `sell` 之后的 `rest`(没有持有股票)。而且别忘了,我们还有交易次数 `k` 的限制,就是说你 `buy` 还只能在 `k > 0` 的前提下操作。
> note注意我在本文会频繁使用「交易」这个词**我们把一次买入和一次卖出定义为一次「交易」**。
::: note
注意我在本文会频繁使用「交易」这个词,**我们把一次买入和一次卖出定义为一次「交易」**。
:::
很复杂对吧,不要怕,我们现在的目的只是穷举,你有再多的状态,老夫要做的就是一把梭全部列举出来。
@ -137,13 +141,21 @@ dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
2、我昨天本没有持有且截至昨天最大交易次数限制为 `k - 1`;但今天我选择 `buy`,所以今天我就持有股票了,最大交易次数限制为 `k`
> note这里着重提醒一下**时刻牢记「状态」的定义**,状态 `k` 的定义并不是「已进行的交易次数」,而是「最大交易次数的上限限制」。如果确定今天进行一次交易,且要保证截至今天最大交易次数上限为 `k`,那么昨天的最大交易次数上限必须是 `k - 1`。举个具体的例子,比方说要求你的银行卡里今天至少有 100 块钱,且你确定你今天可以赚 10 块钱,那么你就要保证昨天的银行卡要至少剩下 90 块钱。
::: note
这里着重提醒一下,**时刻牢记「状态」的定义**,状态 `k` 的定义并不是「已进行的交易次数」,而是「最大交易次数的上限限制」。如果确定今天进行一次交易,且要保证截至今天最大交易次数上限为 `k`,那么昨天的最大交易次数上限必须是 `k - 1`。举个具体的例子,比方说要求你的银行卡里今天至少有 100 块钱,且你确定你今天可以赚 10 块钱,那么你就要保证昨天的银行卡要至少剩下 90 块钱。
:::
这个解释应该很清楚了,如果 `buy`,就要从利润中减去 `prices[i]`,如果 `sell`,就要给利润增加 `prices[i]`。今天的最大利润就是这两种可能选择中较大的那个。
注意 `k` 的限制,在选择 `buy` 的时候相当于开启了一次交易,那么对于昨天来说,交易次数的上限 `k` 应该减小 1。
> note这里补充修正一点以前我以为在 `sell` 的时候给 `k` 减小 1 和在 `buy` 的时候给 `k` 减小 1 是等效的,但细心的读者向我提出质疑,经过深入思考我发现前者确实是错误的,因为交易是从 `buy` 开始,如果 `buy` 的选择不改变交易次数 `k` 的话,会出现交易次数超出限制的的错误。
::: note
这里补充修正一点,以前我以为在 `sell` 的时候给 `k` 减小 1 和在 `buy` 的时候给 `k` 减小 1 是等效的,但细心的读者向我提出质疑,经过深入思考我发现前者确实是错误的,因为交易是从 `buy` 开始,如果 `buy` 的选择不改变交易次数 `k` 的话,会出现交易次数超出限制的的错误。
:::
现在,我们已经完成了动态规划中最困难的一步:状态转移方程。**如果之前的内容你都可以理解,那么你已经可以秒杀所有问题了,只要套这个框架就行了**。不过还差最后一点点,就是定义 base case即最简单的情况。
@ -392,7 +404,11 @@ dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i] - fee)
在第一个式子里减也是一样的,相当于卖出股票的价格减小了。
```
> note如果直接把 `fee` 放在第一个式子里减,会有一些测试用例无法通过,错误原因是整型溢出而不是思路问题。一种解决方案是把代码中的 `int` 类型都改成 `long` 类型,避免 `int` 的整型溢出。
::: note
如果直接把 `fee` 放在第一个式子里减,会有一些测试用例无法通过,错误原因是整型溢出而不是思路问题。一种解决方案是把代码中的 `int` 类型都改成 `long` 类型,避免 `int` 的整型溢出。
:::
直接翻译成代码,注意状态转移方程改变后 base case 也要做出对应改变:
@ -508,7 +524,11 @@ int maxProfit_k_2(int[] prices) {
}
```
> note**这里肯定会有读者疑惑,`k` 的 base case 是 0按理说应该从 `k = 1, k++` 这样穷举状态 `k` 才对?而且如果你真的这样从小到大遍历 `k`,提交发现也是可以的**。
::: note
**这里肯定会有读者疑惑,`k` 的 base case 是 0按理说应该从 `k = 1, k++` 这样穷举状态 `k` 才对?而且如果你真的这样从小到大遍历 `k`,提交发现也是可以的**。
:::
这个疑问很正确,因为我们前文 [动态规划答疑篇](https://labuladong.github.io/article/fname.html?fname=最优子结构) 有介绍 `dp` 数组的遍历顺序是怎么确定的,主要是根据 base case以 base case 为起点,逐步向结果靠近。
@ -723,6 +743,6 @@ int maxProfit_k_inf(int[] prices, int cooldown, int fee) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -56,7 +56,7 @@
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_62987943e4b01c509ab8b6aa/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=子序列问题模板) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -69,7 +69,7 @@ int rob(int[] nums);
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_62987952e4b09dda12708bf8/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=抢房子) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -389,7 +389,7 @@ for (int i = 1; i < m; i++)
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -21,7 +21,11 @@
但是,动态规划求解的过程中也是可以进行阶段性优化的,如果你认真观察某些动态规划问题的状态转移方程,就能够把它们解法的空间复杂度进一步降低,由 O(N^2) 降低到 O(N)。
> note之前我在本文中误用了「状态压缩」这个词有读者指出「状态压缩」这个词的含义是把多个状态通过二进制运算用一个整数表示出来从而减少 `dp` 数组的维度。而本文描述的优化方式是通过观察状态转移方程的依赖关系,从而减少 `dp` 数组的维度,确实和「状态压缩」有所区别。所以严谨起见,我把原来文章中的「状态压缩」都改为了「空间压缩」,避免名词的误用。
::: note
之前我在本文中误用了「状态压缩」这个词,有读者指出「状态压缩」这个词的含义是把多个状态通过二进制运算用一个整数表示出来,从而减少 `dp` 数组的维度。而本文描述的优化方式是通过观察状态转移方程的依赖关系,从而减少 `dp` 数组的维度,确实和「状态压缩」有所区别。所以严谨起见,我把原来文章中的「状态压缩」都改为了「空间压缩」,避免名词的误用。
:::
能够使用空间压缩技巧的动态规划都是二维 `dp` 问题,**你看它的状态转移方程,如果计算状态 `dp[i][j]` 需要的都是 `dp[i][j]` 相邻的状态,那么就可以使用空间压缩技巧**,将二维的 `dp` 数组转化成一维,将空间复杂度从 O(N^2) 降低到 O(N)。
@ -53,7 +57,11 @@ int longestPalindromeSubseq(String s) {
}
```
> tip我们本文不探讨如何推状态转移方程只探讨对二维 DP 问题进行空间压缩的技巧。技巧都是通用的,所以如果你没看过前文,不明白这段代码的逻辑也无妨,完全不会阻碍你学会空间压缩。
::: tip
我们本文不探讨如何推状态转移方程,只探讨对二维 DP 问题进行空间压缩的技巧。技巧都是通用的,所以如果你没看过前文,不明白这段代码的逻辑也无妨,完全不会阻碍你学会空间压缩。
:::
你看我们对 `dp[i][j]` 的更新,其实只依赖于 `dp[i+1][j-1], dp[i][j-1], dp[i+1][j]` 这三个状态:
@ -238,7 +246,7 @@ int longestPalindromeSubseq(String s) {
- [动态规划之最小路径和](https://labuladong.github.io/article/fname.html?fname=最小路径和)
- [动态规划解题套路框架](https://labuladong.github.io/article/fname.html?fname=动态规划详解进阶)
- [动态规划设计:最大子数组](https://labuladong.github.io/article/fname.html?fname=最大子数组)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [经典动态规划:子集背包问题](https://labuladong.github.io/article/fname.html?fname=背包子集)
- [经典动态规划:完全背包问题](https://labuladong.github.io/article/fname.html?fname=背包零钱)
- [经典动态规划:最长公共子序列](https://labuladong.github.io/article/fname.html?fname=LCS)
@ -266,6 +274,6 @@ int longestPalindromeSubseq(String s) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -54,7 +54,11 @@ int minDistance(String s1, String s2)
前文 [最长公共子序列](https://labuladong.github.io/article/fname.html?fname=LCS) 说过,**解决两个字符串的动态规划问题,一般都是用两个指针 `i, j` 分别指向两个字符串的最后,然后一步步往前移动,缩小问题的规模**。
> tip其实让 `i, j` 从前往后移动也可以,改一下 `dp` 函数/数组的定义即可,思路是完全一样的。
::: tip
其实让 `i, j` 从前往后移动也可以,改一下 `dp` 函数/数组的定义即可,思路是完全一样的。
:::
设两个字符串分别为 `"rad"``"apple"`,为了把 `s1` 变成 `s2`,算法会这样进行:
@ -337,6 +341,114 @@ class Node {
![](https://labuladong.github.io/pictures/editDistance/6.jpg)
应大家的要求,我把这个思路也写出来,你可以自己运行试一下:
```java
int minDistance(String s1, String s2) {
int m = s1.length(), n = s2.length();
Node[][] dp = new Node[m + 1][n + 1];
// base case
for (int i = 0; i <= m; i++) {
// s1 转化成 s2 只需要删除一个字符
dp[i][0] = new Node(i, 2);
}
for (int j = 1; j <= n; j++) {
// s1 转化成 s2 只需要插入一个字符
dp[0][j] = new Node(j, 1);
}
// 状态转移方程
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (s1.charAt(i-1) == s2.charAt(j-1)){
// 如果两个字符相同,则什么都不需要做
Node node = dp[i - 1][j - 1];
dp[i][j] = new Node(node.val, 0);
} else {
// 否则,记录代价最小的操作
dp[i][j] = minNode(
dp[i - 1][j],
dp[i][j - 1],
dp[i-1][j-1]
);
// 并且将编辑距离加一
dp[i][j].val++;
}
}
}
// 根据 dp table 反推具体操作过程并打印
printResult(dp, s1, s2);
return dp[m][n].val;
}
// 计算 delete, insert, replace 中代价最小的操作
Node minNode(Node a, Node b, Node c) {
Node res = new Node(a.val, 2);
if (res.val > b.val) {
res.val = b.val;
res.choice = 1;
}
if (res.val > c.val) {
res.val = c.val;
res.choice = 3;
}
return res;
}
```
最后,`printResult` 函数反推结果并把具体的操作打印出来:
```java
void printResult(Node[][] dp, String s1, String s2) {
int rows = dp.length;
int cols = dp[0].length;
int i = rows - 1, j = cols - 1;
System.out.println("Change s1=" + s1 + " to s2=" + s2 + ":
");
while (i != 0 && j != 0) {
char c1 = s1.charAt(i - 1);
char c2 = s2.charAt(j - 1);
int choice = dp[i][j].choice;
System.out.print("s1[" + (i - 1) + "]:");
switch (choice) {
case 0:
// 跳过,则两个指针同时前进
System.out.println("skip '" + c1 + "'");
i--; j--;
break;
case 1:
// 将 s2[j] 插入 s1[i],则 s2 指针前进
System.out.println("insert '" + c2 + "'");
j--;
break;
case 2:
// 将 s1[i] 删除,则 s1 指针前进
System.out.println("delete '" + c1 + "'");
i--;
break;
case 3:
// 将 s1[i] 替换成 s2[j],则两个指针同时前进
System.out.println(
"replace '" + c1 + "'" + " with '" + c2 + "'");
i--; j--;
break;
}
}
// 如果 s1 还没有走完,则剩下的都是需要删除的
while (i > 0) {
System.out.print("s1[" + (i - 1) + "]:");
System.out.println("delete '" + s1.charAt(i - 1) + "'");
i--;
}
// 如果 s2 还没有走完,则剩下的都是需要插入 s1 的
while (j > 0) {
System.out.print("s1[0]:");
System.out.println("insert '" + s2.charAt(j - 1) + "'");
j--;
}
}
```
<hr>
@ -369,7 +481,7 @@ class Node {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -23,7 +23,7 @@
今天就来说一下背包问题吧,就讨论最常说的 0-1 背包问题。描述:
给你一个可装载重量为 `W` 的背包和 `N` 个物品,每个物品有重量和价值两个属性。其中第 `i` 个物品的重量为 `wt[i]`,价值为 `val[i]`,现在让你用这个背包装物品,最多能装的价值是多少?
给你一个可装载重量为 `W` 的背包和 `N` 个物品,每个物品有重量和价值两个属性。其中第 `i` 个物品的重量为 `wt[i]`,价值为 `val[i]`。现在让你用这个背包装物品,每个物品只能用一次,在不超过被包容量的前提下,最多能装的价值是多少?
![](https://labuladong.github.io/pictures/knapsack/1.png)
@ -60,7 +60,11 @@ for 状态1 in 状态1的所有取值
dp[状态1][状态2][...] = 择优(选择1选择2...)
```
> tip此框架出自历史文章 [团灭 LeetCode 股票问题](https://labuladong.github.io/article/fname.html?fname=团灭股票问题)。
::: tip
此框架出自历史文章 [团灭 LeetCode 股票问题](https://labuladong.github.io/article/fname.html?fname=团灭股票问题)。
:::
**第二步要明确 `dp` 数组的定义**。
@ -70,7 +74,11 @@ for 状态1 in 状态1的所有取值
比如说,如果 `dp[3][5] = 6`,其含义为:对于给定的一系列物品中,若只对前 3 个物品进行选择,当背包容量为 5 时,最多可以装下的价值为 6。
> info为什么要这么定义便于状态转移或者说这就是套路记下来就行了。建议看一下我们的动态规划系列文章几种套路都被扒得清清楚楚了。
::: info
为什么要这么定义?便于状态转移,或者说这就是套路,记下来就行了。建议看一下我们的动态规划系列文章,几种套路都被扒得清清楚楚了。
:::
根据这个定义,我们想求的最终答案就是 `dp[N][W]`。base case 就是 `dp[0][..] = dp[..][0] = 0`,因为没有物品或者背包没有空间的时候,能装的最大价值就是 0。
@ -151,7 +159,11 @@ int knapsack(int W, int N, int[] wt, int[] val) {
<visual slug='mydata-knapsack'/>
> note其实函数签名中的物品数量 `N` 就是 `wt` 数组的长度,所以实际上这个参数 `N` 是多此一举的。但为了体现原汁原味的 0-1 背包问题,我就带上这个参数 `N` 了,你自己写的话可以省略。
::: note
其实函数签名中的物品数量 `N` 就是 `wt` 数组的长度,所以实际上这个参数 `N` 是多此一举的。但为了体现原汁原味的 0-1 背包问题,我就带上这个参数 `N` 了,你自己写的话可以省略。
:::
至此,背包问题就解决了,相比而言,我觉得这是比较简单的动态规划问题,因为状态转移的推导比较自然,基本上你明确了 `dp` 数组的定义,就可以理所当然地确定状态转移了。
@ -166,8 +178,8 @@ int knapsack(int W, int N, int[] wt, int[] val) {
<details class="hint-container details">
<summary><strong>引用本文的文章</strong></summary>
- [回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分)
- [扫描线技巧:安排会议室](https://labuladong.github.io/article/fname.html?fname=安排会议室)
- [球盒模型:回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分)
- [目标和:背包问题的变体](https://labuladong.github.io/article/fname.html?fname=targetSum)
- [经典动态规划:子集背包问题](https://labuladong.github.io/article/fname.html?fname=背包子集)
- [经典动态规划:完全背包问题](https://labuladong.github.io/article/fname.html?fname=背包零钱)
@ -180,6 +192,6 @@ int knapsack(int W, int N, int[] wt, int[] val) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -67,7 +67,7 @@ int intervalSchedule(int[][] intvs);
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_649bf3aee4b09d72379e4576/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=贪心算法之区间调度问题) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -86,7 +86,7 @@
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_6298795de4b01a4852072fa7/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=高楼扔鸡蛋问题) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -100,7 +100,11 @@ int dp(int[][] grid, int i, int j) {
}
```
> note**为了简洁,之后 `dp(grid, i, j)` 就简写为 `dp(i, j)`,大家理解就好**。
::: note
**为了简洁,之后 `dp(grid, i, j)` 就简写为 `dp(i, j)`,大家理解就好**。
:::
接下来我们需要找状态转移了,还记得如何找状态转移方程吗?我们这样定义 `dp` 函数能否正确进行状态转移呢?
@ -259,6 +263,6 @@ class Solution {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -360,7 +360,7 @@ tail | grep '下一篇' $filename
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -72,7 +72,11 @@ struct task_struct {
对于一般的计算机,输入流是键盘,输出流是显示器,错误流也是显示器,所以现在这个进程和内核连了三根线。因为硬件都是由内核管理的,我们的进程需要通过「系统调用」让内核进程访问硬件资源。
> note不要忘了Linux 中一切都被抽象成文件,设备也是文件,可以进行读和写。
::: note
不要忘了Linux 中一切都被抽象成文件,设备也是文件,可以进行读和写。
:::
如果我们写的程序需要其他资源,比如打开一个文件进行读写,这也很简单,进行系统调用,让内核把文件打开,这个文件就会被放到 `files` 的第 4 个位置:
@ -147,7 +151,7 @@ $ cmd1 | cmd2 | cmd3
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -21,7 +21,11 @@
经过一番攀谈交心了解到,他跑了一个比较古老已经停止维护的开源项目,安装的旧版本的 Redis而且他对 Linux 的使用不是很熟练。我就知道,他的服务器已经被攻陷了,想到也许还会有不少像我这位朋友的人,不重视操作系统的权限、防火墙的设置和数据库的保护,我就写一篇文章简单看看这种情况出现的原因,以及如何防范。
> note这种手法现在已经行不通了因为新版本 Redis 都增加了 protect mode增加了安全性我们只能在本地简单模拟一下就别乱试了。
::: note
这种手法现在已经行不通了,因为新版本 Redis 都增加了 protect mode增加了安全性我们只能在本地简单模拟一下就别乱试了。
:::
### 事件经过
@ -101,7 +105,7 @@ Redis 监听的默认端口是 6379我们设置它接收网卡 127.0.0.1 的
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -115,7 +115,11 @@ type Session interface {
再说 `Provider` 为啥要抽象出来。我们上面那个图的 `Provider` 就是一个散列表,保存 `sid``Session` 的映射,但是实际中肯定会更加复杂。我们不是要时不时删除一些 session 吗,除了设置存活时间之外,还可以采用一些其他策略,比如 LRU 缓存淘汰算法,这样就需要 `Provider` 内部使用哈希链表这种数据结构来存储 session。
> tip关于 LRU 算法的奥妙,参见前文 [LRU 算法详解](https://labuladong.github.io/article/fname.html?fname=LRU算法)。
::: tip
关于 LRU 算法的奥妙,参见前文 [LRU 算法详解](https://labuladong.github.io/article/fname.html?fname=LRU算法)。
:::
因此,`Provider` 作为一个容器,就是要屏蔽算法细节,以合理的数据结构和算法组织 `sid``Session` 的映射关系,只需要实现下面这几个方法实现对 session 的增删查改:
@ -148,7 +152,7 @@ https://github.com/astaxie/build-web-application-with-golang
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -59,6 +59,6 @@
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_64a923dde4b007b201a392d0/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=刷题技巧) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -123,7 +123,7 @@ https://sqlzoo.net/
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -161,7 +161,11 @@ Diffie-Hellman 密钥交换算法可以做到。**准确的说,该算法并不
![](https://labuladong.github.io/pictures/密码技术/7.jpg)
> note以上只是为了说明证书只需要安装一次并不需要每次都向认证机构请求一般是服务器直接给客户端发送证书而不是认证机构。
::: note
以上只是为了说明,证书只需要安装一次,并不需要每次都向认证机构请求;一般是服务器直接给客户端发送证书,而不是认证机构。
:::
也许有人问Alice 要想通过数字签名确定证书的有效性,前提是要有该机构的(认证)公钥,这不是又回到刚才的死循环了吗?
@ -197,7 +201,7 @@ HTTPS 协议中的 SSL/TLS 安全层会组合使用以上几种加密方式,**
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -24,12 +24,12 @@
**-----------**
> tip本文有视频版[动手实现 TreeMap](https://appktavsiei5995.pc.xiaoe-tech.com/detail/p_62655516e4b0cedf38a93758/6)。
> tip本文有视频版[动手实现 TreeMap](https://labuladong.online/algo/ds-class/dong-shou--60928/treemap-yu-a003e/)。
> info在开头先打个广告我的 [手把手刷二叉树课程](https://aep.xet.tech/s/3YGcq3) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
> info在开头先打个广告我的 [手把手刷二叉树课程](https://labuladong.online/algo/tree-class/) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
@ -105,7 +105,11 @@ void traverse(TreeNode root, int k) {
我们前文 [高效计算数据流的中位数](https://labuladong.github.io/article/fname.html?fname=数据流中位数) 中就提过今天的这个问题:
> info如果让你实现一个在二叉搜索树中通过排名计算对应元素的方法 `select(int k)`,你会怎么设计?
::: info
如果让你实现一个在二叉搜索树中通过排名计算对应元素的方法 `select(int k)`,你会怎么设计?
:::
如果按照我们刚才说的方法利用「BST 中序遍历就是升序排序结果」这个性质,每次寻找第 `k` 小的元素都要中序遍历一次,最坏的时间复杂度是 `O(N)``N` 是 BST 的节点个数。
@ -233,9 +237,9 @@ void traverse(TreeNode root) {
简单总结下吧BST 相关的问题,要么利用 BST 左小右大的特性提升算法效率,要么利用中序遍历的特性满足题目的要求,也就这么些事儿吧。
当然BST 还可以玩出更多花样,提供更丰富的 API更多内容参见我的数据结构课程中的 [动手实现 TreeMap](https://appktavsiei5995.pc.xiaoe-tech.com/detail/p_62655516e4b0cedf38a93758/6) 章节。
当然BST 还可以玩出更多花样,提供更丰富的 API更多内容参见我的数据结构课程中的 [动手实现 TreeMap](https://labuladong.online/algo/ds-class/dong-shou--60928/treemap-yu-a003e/) 章节。
本文就到这里,更多经典的二叉树习题以及递归思维的训练,请参见 [手把手带你刷通二叉树](https://aep.xet.tech/s/3YGcq3)。
本文就到这里,更多经典的二叉树习题以及递归思维的训练,请参见 [手把手带你刷通二叉树](https://labuladong.online/algo/tree-class/)。
@ -269,6 +273,6 @@ void traverse(TreeNode root) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -25,7 +25,7 @@
**-----------**
> info在开头先打个广告我的 [手把手刷二叉树课程](https://aep.xet.tech/s/3YGcq3) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
> info在开头先打个广告我的 [手把手刷二叉树课程](https://labuladong.online/algo/tree-class/) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
@ -312,7 +312,7 @@ void BST(TreeNode root, int target) {
3、根据代码框架掌握了 BST 的增删查改操作。
本文就到这里,更多经典的二叉树习题以及递归思维的训练,请参见 [手把手带你刷通二叉树](https://aep.xet.tech/s/3YGcq3)。
本文就到这里,更多经典的二叉树习题以及递归思维的训练,请参见 [手把手带你刷通二叉树](https://labuladong.online/algo/tree-class/)。
@ -347,6 +347,6 @@ void BST(TreeNode root, int target) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -292,578 +292,6 @@ void levelTraverse(TreeNode root) {
**如果你能够理解上面这段代码,我们就可以来看 Dijkstra 算法的代码框架了**。
### Dijkstra 算法框架
**首先,我们先看一下 Dijkstra 算法的签名**
<!-- muliti_language -->
```java
// 输入一幅图和一个起点 start计算 start 到其他节点的最短距离
int[] dijkstra(int start, List<Integer>[] graph);
```
输入是一幅图 `graph` 和一个起点 `start`,返回是一个记录最短路径权重的数组。
比方说,输入起点 `start = 3`,函数返回一个 `int[]` 数组,假设赋值给 `distTo` 变量,那么从起点 `3` 到节点 `6` 的最短路径权重的值就是 `distTo[6]`
是的,标准的 Dijkstra 算法会把从起点 `start` 到所有其他节点的最短路径都算出来。
当然,如果你的需求只是计算从起点 `start` 到某一个终点 `end` 的最短路径,那么在标准 Dijkstra 算法上稍作修改就可以更高效地完成这个需求,这个我们后面再说。
**其次,我们也需要一个 `State` 类来辅助算法的运行**
<!-- muliti_language -->
```java
class State {
// 图节点的 id
int id;
// 从 start 节点到当前节点的距离
int distFromStart;
State(int id, int distFromStart) {
this.id = id;
this.distFromStart = distFromStart;
}
}
```
类似刚才二叉树的层序遍历,我们也需要用 `State` 类记录一些额外信息,也就是使用 `distFromStart` 变量记录从起点 `start` 到当前这个节点的距离。
刚才说普通 BFS 算法中,根据 BFS 的逻辑和无权图的特点,第一次遇到某个节点所走的步数就是最短距离,所以用一个 `visited` 数组防止走回头路,每个节点只会经过一次。
加权图中的 Dijkstra 算法和无权图中的普通 BFS 算法不同,在 Dijkstra 算法中,你第一次经过某个节点时的路径权重,不见得就是最小的,所以对于同一个节点,我们可能会经过多次,而且每次的 `distFromStart` 可能都不一样,比如下图:
![](https://labuladong.github.io/pictures/dijkstra/3.jpeg)
我会经过节点 `5` 三次,每次的 `distFromStart` 值都不一样,那我取 `distFromStart` 最小的那次,不就是从起点 `start` 到节点 `5` 的最短路径权重了么?
好了,明白上面的几点,我们可以来看看 Dijkstra 算法的代码模板。
**其实Dijkstra 可以理解成一个带 dp table或者说备忘录的 BFS 算法,伪码如下**
<!-- muliti_language -->
```java
// 返回节点 from 到节点 to 之间的边的权重
int weight(int from, int to);
// 输入节点 s 返回 s 的相邻节点
List<Integer> adj(int s);
// 输入一幅图和一个起点 start计算 start 到其他节点的最短距离
int[] dijkstra(int start, List<Integer>[] graph) {
// 图中节点的个数
int V = graph.length;
// 记录最短路径的权重,你可以理解为 dp table
// 定义distTo[i] 的值就是节点 start 到达节点 i 的最短路径权重
int[] distTo = new int[V];
// 求最小值,所以 dp table 初始化为正无穷
Arrays.fill(distTo, Integer.MAX_VALUE);
// base casestart 到 start 的最短距离就是 0
distTo[start] = 0;
// 优先级队列distFromStart 较小的排在前面
Queue<State> pq = new PriorityQueue<>((a, b) -> {
return a.distFromStart - b.distFromStart;
});
// 从起点 start 开始进行 BFS
pq.offer(new State(start, 0));
while (!pq.isEmpty()) {
State curState = pq.poll();
int curNodeID = curState.id;
int curDistFromStart = curState.distFromStart;
if (curDistFromStart > distTo[curNodeID]) {
// 已经有一条更短的路径到达 curNode 节点了
continue;
}
// 将 curNode 的相邻节点装入队列
for (int nextNodeID : adj(curNodeID)) {
// 看看从 curNode 达到 nextNode 的距离是否会更短
int distToNextNode = distTo[curNodeID] + weight(curNodeID, nextNodeID);
if (distTo[nextNodeID] > distToNextNode) {
// 更新 dp table
distTo[nextNodeID] = distToNextNode;
// 将这个节点以及距离放入队列
pq.offer(new State(nextNodeID, distToNextNode));
}
}
}
return distTo;
}
```
**对比普通的 BFS 算法,你可能会有以下疑问**
**1、没有 `visited` 集合记录已访问的节点,所以一个节点会被访问多次,会被多次加入队列,那会不会导致队列永远不为空,造成死循环**
**2、为什么用优先级队列 `PriorityQueue` 而不是 `LinkedList` 实现的普通队列?为什么要按照 `distFromStart` 的值来排序**
**3、如果我只想计算起点 `start` 到某一个终点 `end` 的最短路径,是否可以修改算法,提升一些效率**
我们先回答第一个问题,为什么这个算法不用 `visited` 集合也不会死循环。
对于这类问题,我教你一个思考方法:
循环结束的条件是队列为空,那么你就要注意看什么时候往队列里放元素(调用 `offer`)方法,再注意看什么时候从队列往外拿元素(调用 `poll` 方法)。
`while` 循环每执行一次,都会往外拿一个元素,但想往队列里放元素,可就有很多限制了,必须满足下面这个条件:
<!-- muliti_language -->
```java
// 看看从 curNode 达到 nextNode 的距离是否会更短
if (distTo[nextNodeID] > distToNextNode) {
// 更新 dp table
distTo[nextNodeID] = distToNextNode;
pq.offer(new State(nextNodeID, distToNextNode));
}
```
这也是为什么我说 `distTo` 数组可以理解成我们熟悉的 dp table因为这个算法逻辑就是在不断的最小化 `distTo` 数组中的元素:
如果你能让到达 `nextNodeID` 的距离更短,那就更新 `distTo[nextNodeID]` 的值,让你入队,否则的话对不起,不让入队。
**因为两个节点之间的最短距离(路径权重)肯定是一个确定的值,不可能无限减小下去,所以队列一定会空,队列空了之后,`distTo` 数组中记录的就是从 `start` 到其他节点的最短距离**。
接下来解答第二个问题,为什么要用 `PriorityQueue` 而不是 `LinkedList` 实现的普通队列?
如果你非要用普通队列,其实也没问题的,你可以直接把 `PriorityQueue` 改成 `LinkedList`,也能得到正确答案,但是效率会低很多。
**Dijkstra 算法使用优先级队列,主要是为了效率上的优化,类似一种贪心算法的思路**。
为什么说是一种贪心思路呢,比如说下面这种情况,你想计算从起点 `start` 到终点 `end` 的最短路径权重:
![](https://labuladong.github.io/pictures/dijkstra/4.jpeg)
假设你当前只遍历了图中的这几个节点,那么你下一步准备遍历那个节点?这三条路径都可能成为最短路径的一部分,**但你觉得哪条路径更有「潜力」成为最短路径中的一部分**
从目前的情况来看,显然橙色路径的可能性更大嘛,所以我们希望节点 `2` 排在队列靠前的位置,优先被拿出来向后遍历。
所以我们使用 `PriorityQueue` 作为队列,让 `distFromStart` 的值较小的节点排在前面,这就类似我们之前讲 [贪心算法](https://labuladong.github.io/article/fname.html?fname=跳跃游戏) 说到的贪心思路,可以很大程度上优化算法的效率。
大家应该听过 Bellman-Ford 算法这个算法是一种更通用的最短路径算法因为它可以处理带有负权重边的图Bellman-Ford 算法逻辑和 Dijkstra 算法非常类似,用到的就是普通队列,本文就提一句,后面有空再具体写。
接下来说第三个问题,如果只关心起点 `start` 到某一个终点 `end` 的最短路径,是否可以修改代码提升算法效率。
肯定可以的,因为我们标准 Dijkstra 算法会算出 `start` 到所有其他节点的最短路径,你只想计算到 `end` 的最短路径,相当于减少计算量,当然可以提升效率。
需要在代码中做的修改也非常少,只要改改函数签名,再加个 if 判断就行了:
<!-- muliti_language -->
```java
// 输入起点 start 和终点 end计算起点到终点的最短距离
int dijkstra(int start, int end, List<Integer>[] graph) {
// ...
while (!pq.isEmpty()) {
State curState = pq.poll();
int curNodeID = curState.id;
int curDistFromStart = curState.distFromStart;
// 在这里加一个判断就行了,其他代码不用改
if (curNodeID == end) {
return curDistFromStart;
}
if (curDistFromStart > distTo[curNodeID]) {
continue;
}
// ...
}
// 如果运行到这里,说明从 start 无法走到 end
return Integer.MAX_VALUE;
}
```
因为优先级队列自动排序的性质,**每次**从队列里面拿出来的都是 `distFromStart` 值最小的,所以当你**第一次**从队列中拿出终点 `end` 时,此时的 `distFromStart` 对应的值就是从 `start``end` 的最短距离。
这个算法较之前的实现提前 return 了,所以效率有一定的提高。
### 时间复杂度分析
Dijkstra 算法的时间复杂度是多少?你去网上查,可能会告诉你是 `O(ElogV)`,其中 `E` 代表图中边的条数,`V` 代表图中节点的个数。
因为理想情况下优先级队列中最多装 `V` 个节点,对优先级队列的操作次数和 `E` 成正比,所以整体的时间复杂度就是 `O(ElogV)`
不过这是理想情况Dijkstra 算法的代码实现有很多版本,不同编程语言或者不同数据结构 API 都会导致算法的时间复杂度发生一些改变。
比如本文实现的 Dijkstra 算法,使用了 Java 的 `PriorityQueue` 这个数据结构,这个容器类底层使用二叉堆实现,但没有提供通过索引操作队列中元素的 API所以队列中会有重复的节点最多可能有 `E` 个节点存在队列中。
所以本文实现的 Dijkstra 算法复杂度并不是理想情况下的 `O(ElogV)`,而是 `O(ElogE)`,可能会略大一些,因为图中边的条数一般是大于节点的个数的。
不过就对数函数来说,就算真数大一些,对数函数的结果也大不了多少,所以这个算法实现的实际运行效率也是很高的,以上只是理论层面的时间复杂度分析,供大家参考。
### 秒杀三道题目
以上说了 Dijkstra 算法的框架,下面我们套用这个框架做几道题,实践出真知。
第一题是力扣第 743 题「网络延迟时间」,题目如下:
<Problem slug="network-delay-time" />
函数签名如下:
<!-- muliti_language -->
```java
// times 记录边和权重n 为节点个数(从 1 开始k 为起点
// 计算从 k 发出的信号至少需要多久传遍整幅图
int networkDelayTime(int[][] times, int n, int k)
```
让你求所有节点都收到信号的时间,你把所谓的传递时间看做距离,实际上就是问你「从节点 `k` 到其他所有节点的最短路径中,最长的那条最短路径距离是多少」,说白了就是让你算从节点 `k` 出发到其他所有节点的最短路径,就是标准的 Dijkstra 算法。
在用 Dijkstra 之前别忘了要满足一些条件加权有向图没有负权重边OK可以用 Dijkstra 算法计算最短路径。
根据我们之前 Dijkstra 算法的框架,我们可以写出下面代码:
<!-- muliti_language -->
```java
int networkDelayTime(int[][] times, int n, int k) {
// 节点编号是从 1 开始的,所以要一个大小为 n + 1 的邻接表
List<int[]>[] graph = new LinkedList[n + 1];
for (int i = 1; i <= n; i++) {
graph[i] = new LinkedList<>();
}
// 构造图
for (int[] edge : times) {
int from = edge[0];
int to = edge[1];
int weight = edge[2];
// from -> List<(to, weight)>
// 邻接表存储图结构,同时存储权重信息
graph[from].add(new int[]{to, weight});
}
// 启动 dijkstra 算法计算以节点 k 为起点到其他节点的最短路径
int[] distTo = dijkstra(k, graph);
// 找到最长的那一条最短路径
int res = 0;
for (int i = 1; i < distTo.length; i++) {
if (distTo[i] == Integer.MAX_VALUE) {
// 有节点不可达,返回 -1
return -1;
}
res = Math.max(res, distTo[i]);
}
return res;
}
// 输入一个起点 start计算从 start 到其他节点的最短距离
int[] dijkstra(int start, List<int[]>[] graph) {}
```
上述代码首先利用题目输入的数据转化成邻接表表示一幅图,接下来我们可以直接套用 Dijkstra 算法的框架:
<!-- muliti_language -->
```java
class State {
// 图节点的 id
int id;
// 从 start 节点到当前节点的距离
int distFromStart;
State(int id, int distFromStart) {
this.id = id;
this.distFromStart = distFromStart;
}
}
// 输入一个起点 start计算从 start 到其他节点的最短距离
int[] dijkstra(int start, List<int[]>[] graph) {
// 定义distTo[i] 的值就是起点 start 到达节点 i 的最短路径权重
int[] distTo = new int[graph.length];
Arrays.fill(distTo, Integer.MAX_VALUE);
// base casestart 到 start 的最短距离就是 0
distTo[start] = 0;
// 优先级队列distFromStart 较小的排在前面
Queue<State> pq = new PriorityQueue<>((a, b) -> {
return a.distFromStart - b.distFromStart;
});
// 从起点 start 开始进行 BFS
pq.offer(new State(start, 0));
while (!pq.isEmpty()) {
State curState = pq.poll();
int curNodeID = curState.id;
int curDistFromStart = curState.distFromStart;
if (curDistFromStart > distTo[curNodeID]) {
continue;
}
// 将 curNode 的相邻节点装入队列
for (int[] neighbor : graph[curNodeID]) {
int nextNodeID = neighbor[0];
int distToNextNode = distTo[curNodeID] + neighbor[1];
// 更新 dp table
if (distTo[nextNodeID] > distToNextNode) {
distTo[nextNodeID] = distToNextNode;
pq.offer(new State(nextNodeID, distToNextNode));
}
}
}
return distTo;
}
```
你对比之前说的代码框架,只要稍稍修改,就可以把这道题目解决了。
感觉这道题完全没有难度,下面我们再看一道题目,力扣第 1631 题「最小体力消耗路径」:
<Problem slug="path-with-minimum-effort" />
函数签名如下:
<!-- muliti_language -->
```java
// 输入一个二维矩阵,计算从左上角到右下角的最小体力消耗
int minimumEffortPath(int[][] heights);
```
我们常见的二维矩阵题目,如果让你从左上角走到右下角,比较简单的题一般都会限制你只能向右或向下走,但这道题可没有限制哦,你可以上下左右随便走,只要路径的「体力消耗」最小就行。
如果你把二维数组中每个 `(x, y)` 坐标看做一个节点,它的上下左右坐标就是相邻节点,它对应的值和相邻坐标对应的值之差的绝对值就是题目说的「体力消耗」,你就可以理解为边的权重。
这样一想是不是就在让你以左上角坐标为起点以右下角坐标为终点计算起点到终点的最短路径Dijkstra 算法是不是可以做到?
<!-- muliti_language -->
```java
// 输入起点 start 和终点 end计算起点到终点的最短距离
int dijkstra(int start, int end, List<Integer>[] graph)
```
**只不过,这道题中评判一条路径是长还是短的标准不再是路径经过的权重总和,而是路径经过的权重最大值**。
明白这一点,再想一下使用 Dijkstra 算法的前提加权有向图没有负权重边求最短路径OK可以使用咱们来套框架。
二维矩阵抽象成图,我们先实现一下图的 `adj` 方法,之后的主要逻辑会清晰一些:
<!-- muliti_language -->
```java
// 方向数组,上下左右的坐标偏移量
int[][] dirs = new int[][]{{0,1}, {1,0}, {0,-1}, {-1,0}};
// 返回坐标 (x, y) 的上下左右相邻坐标
List<int[]> adj(int[][] matrix, int x, int y) {
int m = matrix.length, n = matrix[0].length;
// 存储相邻节点
List<int[]> neighbors = new ArrayList<>();
for (int[] dir : dirs) {
int nx = x + dir[0];
int ny = y + dir[1];
if (nx >= m || nx < 0 || ny >= n || ny < 0) {
// 索引越界
continue;
}
neighbors.add(new int[]{nx, ny});
}
return neighbors;
}
```
类似的,我们现在认为一个二维坐标 `(x, y)` 是图中的一个节点,所以这个 `State` 类也需要修改一下:
<!-- muliti_language -->
```java
class State {
// 矩阵中的一个位置
int x, y;
// 从起点 (0, 0) 到当前位置的最小体力消耗(距离)
int effortFromStart;
State(int x, int y, int effortFromStart) {
this.x = x;
this.y = y;
this.effortFromStart = effortFromStart;
}
}
```
接下来,就可以套用 Dijkstra 算法的代码模板了:
<!-- muliti_language -->
```java
// Dijkstra 算法,计算 (0, 0) 到 (m - 1, n - 1) 的最小体力消耗
int minimumEffortPath(int[][] heights) {
int m = heights.length, n = heights[0].length;
// 定义:从 (0, 0) 到 (i, j) 的最小体力消耗是 effortTo[i][j]
int[][] effortTo = new int[m][n];
// dp table 初始化为正无穷
for (int i = 0; i < m; i++) {
Arrays.fill(effortTo[i], Integer.MAX_VALUE);
}
// base case起点到起点的最小消耗就是 0
effortTo[0][0] = 0;
// 优先级队列effortFromStart 较小的排在前面
Queue<State> pq = new PriorityQueue<>((a, b) -> {
return a.effortFromStart - b.effortFromStart;
});
// 从起点 (0, 0) 开始进行 BFS
pq.offer(new State(0, 0, 0));
while (!pq.isEmpty()) {
State curState = pq.poll();
int curX = curState.x;
int curY = curState.y;
int curEffortFromStart = curState.effortFromStart;
// 到达终点提前结束
if (curX == m - 1 && curY == n - 1) {
return curEffortFromStart;
}
if (curEffortFromStart > effortTo[curX][curY]) {
continue;
}
// 将 (curX, curY) 的相邻坐标装入队列
for (int[] neighbor : adj(heights, curX, curY)) {
int nextX = neighbor[0];
int nextY = neighbor[1];
// 计算从 (curX, curY) 达到 (nextX, nextY) 的消耗
int effortToNextNode = Math.max(
effortTo[curX][curY],
Math.abs(heights[curX][curY] - heights[nextX][nextY])
);
// 更新 dp table
if (effortTo[nextX][nextY] > effortToNextNode) {
effortTo[nextX][nextY] = effortToNextNode;
pq.offer(new State(nextX, nextY, effortToNextNode));
}
}
}
// 正常情况不会达到这个 return
return -1;
}
```
你看,稍微改一改代码模板,这道题就解决了。
最后看一道题吧,力扣第 1514 题「概率最大的路径」,看下题目:
<Problem slug="path-with-maximum-probability" />
函数签名如下:
<!-- muliti_language -->
```java
// 输入一幅无向图,边上的权重代表概率,返回从 start 到达 end 最大的概率
double maxProbability(int n, int[][] edges, double[] succProb, int start, int end)
```
我说这题一看就是 Dijkstra 算法,但聪明的你肯定会反驳我:
**1、这题给的是无向图也可以用 Dijkstra 算法吗**
**2、更重要的是Dijkstra 算法计算的是最短路径,计算的是最小值,这题让你计算最大概率是一个最大值,怎么可能用 Dijkstra 算法呢**
问得好!
首先关于有向图和无向图,前文 [图算法基础](https://labuladong.github.io/article/fname.html?fname=图) 说过,无向图本质上可以认为是「双向图」,从而转化成有向图。
重点说说最大值和最小值这个问题,其实 Dijkstra 和很多最优化算法一样,计算的是「最优值」,这个最优值可能是最大值,也可能是最小值。
标准 Dijkstra 算法是计算最短路径的,但你有想过为什么 Dijkstra 算法不允许存在负权重边么?
**因为 Dijkstra 计算最短路径的正确性依赖一个前提:路径中每增加一条边,路径的总权重就会增加**。
这个前提的数学证明大家有兴趣可以自己搜索一下,我这里只说结论,其实你把这个结论反过来也是 OK 的:
如果你想计算最长路径,路径中每增加一条边,路径的总权重就会减少,要是能够满足这个条件,也可以用 Dijkstra 算法。
你看这道题是不是符合这个条件?边和边之间是乘法关系,每条边的概率都是小于 1 的,所以肯定会越乘越小。
只不过,这道题的解法要把优先级队列的排序顺序反过来,一些 if 大小判断也要反过来,我们直接看解法代码吧:
<!-- muliti_language -->
```java
double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {
List<double[]>[] graph = new LinkedList[n];
for (int i = 0; i < n; i++) {
graph[i] = new LinkedList<>();
}
// 构造邻接表结构表示图
for (int i = 0; i < edges.length; i++) {
int from = edges[i][0];
int to = edges[i][1];
double weight = succProb[i];
// 无向图就是双向图;先把 int 统一转成 double待会再转回来
graph[from].add(new double[]{(double)to, weight});
graph[to].add(new double[]{(double)from, weight});
}
return dijkstra(start, end, graph);
}
class State {
// 图节点的 id
int id;
// 从 start 节点到达当前节点的概率
double probFromStart;
State(int id, double probFromStart) {
this.id = id;
this.probFromStart = probFromStart;
}
}
double dijkstra(int start, int end, List<double[]>[] graph) {
// 定义probTo[i] 的值就是节点 start 到达节点 i 的最大概率
double[] probTo = new double[graph.length];
// dp table 初始化为一个取不到的最小值
Arrays.fill(probTo, -1);
// base casestart 到 start 的概率就是 1
probTo[start] = 1;
// 优先级队列probFromStart 较大的排在前面
Queue<State> pq = new PriorityQueue<>((a, b) -> {
return Double.compare(b.probFromStart, a.probFromStart);
});
// 从起点 start 开始进行 BFS
pq.offer(new State(start, 1));
while (!pq.isEmpty()) {
State curState = pq.poll();
int curNodeID = curState.id;
double curProbFromStart = curState.probFromStart;
// 遇到终点提前返回
if (curNodeID == end) {
return curProbFromStart;
}
if (curProbFromStart < probTo[curNodeID]) {
// 已经有一条概率更大的路径到达 curNode 节点了
continue;
}
// 将 curNode 的相邻节点装入队列
for (double[] neighbor : graph[curNodeID]) {
int nextNodeID = (int)neighbor[0];
// 看看从 curNode 达到 nextNode 的概率是否会更大
double probToNextNode = probTo[curNodeID] * neighbor[1];
if (probTo[nextNodeID] < probToNextNode) {
probTo[nextNodeID] = probToNextNode;
pq.offer(new State(nextNodeID, probToNextNode));
}
}
}
// 如果到达这里,说明从 start 开始无法到达 end返回 0
return 0.0;
}
```
好了,到这里本文就结束了,总共 6000 多字,这三道例题都是比较困难的,如果你能够看到这里,真得给你鼓掌。
其实前文 [毕业旅行省钱算法](https://labuladong.github.io/article/fname.html?fname=旅行最短路径) 中讲过限制之下的最小路径问题,当时是使用动态规划思路解决的,但文末也给了 Dijkstra 算法代码,仅仅在本文模板的基础上做了一些变换,你理解本文后可以对照着去看看那道题目。
最后还是那句话,做题在质不在量,希望大家能够透彻理解最基本的数据结构,以不变应万变。
<hr>
@ -877,9 +305,8 @@ double dijkstra(int start, int end, List<double[]>[] graph) {
- [二分图判定算法](https://labuladong.github.io/article/fname.html?fname=二分图)
- [图论基础及遍历算法](https://labuladong.github.io/article/fname.html?fname=图)
- [并查集Union-Find算法](https://labuladong.github.io/article/fname.html?fname=UnionFind算法详解)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [旅游省钱大法:加权最短路径](https://labuladong.github.io/article/fname.html?fname=旅行最短路径)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
- [环检测及拓扑排序算法](https://labuladong.github.io/article/fname.html?fname=拓扑排序)
</details><hr>
@ -906,6 +333,6 @@ double dijkstra(int start, int end, List<double[]>[] graph) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=dijkstra算法) 查看
![](https://labuladong.github.io/pictures/souyisou2.png)
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,252 +2,29 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
**-----------**
二叉堆Binary Heap没什么神秘性质比二叉搜索树 BST 还简单。其主要操作就两个,`sink`(下沉)和 `swim`(上浮),用以维护二叉堆的性质。其主要应用有两个,首先是一种排序方法「堆排序」,第二是一种很有用的数据结构「优先级队列」。
二叉堆Binary Heap没什么神秘性质比二叉搜索树 BST 还简单。
本文参考《算法 4》的代码以实现优先级队列Priority Queue为例来讲讲一下二叉堆怎么运作的。
其主要操作就两个,`sink`(下沉)和 `swim`(上浮),用以维护二叉堆的性质。其主要应用有两个,首先是一种排序方法「堆排序」,第二是一种很有用的数据结构「优先级队列」。
那么本文以实现优先级队列Priority Queue为例来讲讲一下二叉堆怎么运作的。
### 一、二叉堆概览
首先,二叉堆和二叉树有啥关系呢,为什么人们总是把二叉堆画成一棵二叉树?
因为,二叉堆在逻辑上其实是一种特殊的二叉树(完全二叉树),只不过存储在数组里。一般的链表二叉树,我们操作节点的指针,而在数组里,我们把数组索引作为指针:
<!-- muliti_language -->
```java
// 父节点的索引
int parent(int root) {
return root / 2;
}
// 左孩子的索引
int left(int root) {
return root * 2;
}
// 右孩子的索引
int right(int root) {
return root * 2 + 1;
}
```
画个图你立即就能理解了,比如 `arr` 是一个字符数组,注意数组的第一个索引 0 空着不用:
![](https://labuladong.github.io/pictures/heap/1.png)
你看到了,因为这棵二叉树是「完全二叉树」,所以把 `arr[1]` 作为整棵树的根的话,每个节点的父节点和左右孩子的索引都可以通过简单的运算得到,这就是二叉堆设计的一个巧妙之处。
为了方便讲解,下面都会画的图都是二叉树结构,相信你能把树和数组对应起来。
二叉堆还分为最大堆和最小堆。**最大堆的性质是:每个节点都大于等于它的两个子节点**。类似的,最小堆的性质是:每个节点都小于等于它的子节点。
两种堆核心思路都是一样的,本文以最大堆为例讲解。
对于一个最大堆,根据其性质,显然堆顶,也就是 `arr[1]` 一定是所有元素中最大的元素。
### 二、优先级队列概览
优先级队列这种数据结构有一个很有用的功能,你插入或者删除元素的时候,元素会自动排序,这底层的原理就是二叉堆的操作。
数据结构的功能无非增删查改,优先级队列有两个主要 API分别是 `insert` 插入一个元素和 `delMax` 删除最大元素(如果底层用最小堆,那么就是 `delMin`)。
下面我们实现一个简化的优先级队列,先看下代码框架:
> tip这里用到 Java 的泛型,`Key` 可以是任何一种可比较大小的数据类型,比如 Integer 等类型。
<!-- muliti_language -->
```java
public class MaxPQ
<Key extends Comparable<Key>> {
// 存储元素的数组
private Key[] pq;
// 当前 Priority Queue 中的元素个数
private int size = 0;
public MaxPQ(int cap) {
// 索引 0 不用,所以多分配一个空间
pq = (Key[]) new Comparable[cap + 1];
}
/* 返回当前队列中最大元素 */
public Key max() {
return pq[1];
}
/* 插入元素 e */
public void insert(Key e) {...}
/* 删除并返回当前队列中最大元素 */
public Key delMax() {...}
/* 上浮第 x 个元素,以维护最大堆性质 */
private void swim(int x) {...}
/* 下沉第 x 个元素,以维护最大堆性质 */
private void sink(int x) {...}
/* 交换数组的两个元素 */
private void swap(int i, int j) {
Key temp = pq[i];
pq[i] = pq[j];
pq[j] = temp;
}
/* pq[i] 是否比 pq[j] 小? */
private boolean less(int i, int j) {
return pq[i].compareTo(pq[j]) < 0;
}
/* 还有 left, right, parent 三个方法 */
}
```
空出来的四个方法是二叉堆和优先级队列的奥妙所在,下面用图文来逐个理解。
### 三、实现 swim 和 sink
为什么要有上浮 `swim` 和下沉 `sink` 的操作呢?为了维护堆结构。
我们要讲的是最大堆,每个节点都比它的两个子节点大,但是在插入元素和删除元素时,难免破坏堆的性质,这就需要通过这两个操作来恢复堆的性质了。
对于最大堆,会破坏堆性质的有两种情况:
1、如果某个节点 A 比它的子节点(中的一个)小,那么 A 就不配做父节点,应该下去,下面那个更大的节点上来做父节点,这就是对 A 进行**下沉**。
2、如果某个节点 A 比它的父节点大,那么 A 不应该做子节点,应该把父节点换下来,自己去做父节点,这就是对 A 的**上浮**。
当然,错位的节点 A 可能要上浮(或下沉)很多次,才能到达正确的位置,恢复堆的性质。所以代码中肯定有一个 `while` 循环。
细心的读者也许会问,这两个操作不是互逆吗,所以上浮的操作一定能用下沉来完成,为什么我还要费劲写两个方法?
是的,操作是互逆等价的,但是最终我们的操作只会在堆底和堆顶进行(等会讲原因),显然堆底的「错位」元素需要上浮,堆顶的「错位」元素需要下沉。
**上浮的代码实现:**
<!-- muliti_language -->
```java
public class MaxPQ <Key extends Comparable<Key>> {
// 为了节约篇幅,省略上文给出的代码部分...
private void swim(int x) {
// 如果浮到堆顶,就不能再上浮了
while (x > 1 && less(parent(x), x)) {
// 如果第 x 个元素比上层大
// 将 x 换上去
swap(parent(x), x);
x = parent(x);
}
}
}
```
画个 GIF 看一眼就明白了:
![](https://labuladong.github.io/pictures/heap/swim.gif)
**下沉的代码实现:**
下沉比上浮略微复杂一点,因为上浮某个节点 A只需要 A 和其父节点比较大小即可;但是下沉某个节点 A需要 A 和其**两个子节点**比较大小,如果 A 不是最大的就需要调整位置,要把较大的那个子节点和 A 交换。
<!-- muliti_language -->
```java
public class MaxPQ <Key extends Comparable<Key>> {
// 为了节约篇幅,省略上文给出的代码部分...
private void sink(int x) {
// 如果沉到堆底,就沉不下去了
while (left(x) <= size) {
// 先假设左边节点较大
int max = left(x);
// 如果右边节点存在,比一下大小
if (right(x) <= size && less(max, right(x)))
max = right(x);
// 结点 x 比俩孩子都大,就不必下沉了
if (less(max, x)) break;
// 否则,不符合最大堆的结构,下沉 x 结点
swap(x, max);
x = max;
}
}
}
```
画个 GIF 看下就明白了:
![](https://labuladong.github.io/pictures/heap/sink.gif)
至此,二叉堆的主要操作就讲完了,一点都不难吧,代码加起来也就十行。明白了 `sink``swim` 的行为,下面就可以实现优先级队列了。
### 四、实现 delMax 和 insert
这两个方法就是建立在 `swim``sink` 上的。
**`insert` 方法先把要插入的元素添加到堆底的最后,然后让其上浮到正确位置**。
![](https://labuladong.github.io/pictures/heap/insert.gif)
<!-- muliti_language -->
```java
public class MaxPQ <Key extends Comparable<Key>> {
// 为了节约篇幅,省略上文给出的代码部分...
public void insert(Key e) {
size++;
// 先把新元素加到最后
pq[size] = e;
// 然后让它上浮到正确的位置
swim(size);
}
}
```
**`delMax` 方法先把堆顶元素 `A` 和堆底最后的元素 `B` 对调,然后删除 `A`,最后让 `B` 下沉到正确位置**。
<!-- muliti_language -->
```java
public class MaxPQ <Key extends Comparable<Key>> {
// 为了节约篇幅,省略上文给出的代码部分...
public Key delMax() {
// 最大堆的堆顶就是最大元素
Key max = pq[1];
// 把这个最大元素换到最后,删除之
swap(1, size);
pq[size] = null;
size--;
// 让 pq[1] 下沉到正确位置
sink(1);
return max;
}
}
```
![](https://labuladong.github.io/pictures/heap/delete.gif)
至此,一个优先级队列就实现了,插入和删除元素的时间复杂度为 `O(logK)``K` 为当前二叉堆(优先级队列)中的元素总数。因为我们时间复杂度主要花费在 `sink` 或者 `swim` 上,而不管上浮还是下沉,最多也就树(堆)的高度,也就是 log 级别。
### 五、最后总结
二叉堆就是一种完全二叉树,所以适合存储在数组中,而且二叉堆拥有一些特殊性质。
二叉堆的操作很简单,主要就是上浮和下沉,来维护堆的性质(堆有序),核心代码也就十行。
优先级队列是基于二叉堆实现的,主要操作是插入和删除。插入是先插到最后,然后上浮到正确位置;删除是调换位置后再删除,然后下沉到正确位置。核心代码也就十行。
也许这就是数据结构的威力,简单的操作就能实现巧妙的功能,真心佩服发明二叉堆算法的人!
最后,更多二叉堆/优先级队列相关的题目练习见 [二叉堆(优先级队列)的经典习题](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_633faa64e4b0eca59c3a1aa3/1)。
<hr>
@ -292,9 +69,9 @@ public class MaxPQ <Key extends Comparable<Key>> {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.online/algo/ds-class/dong-shou--b9ca2/er-cha-dui-1a386) 查看
![](https://labuladong.github.io/pictures/souyisou2.png)
![](https://labuladong.github.io/pictures/qrcode.jpg)
======其他语言代码======

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -29,7 +29,7 @@
> info在开头先打个广告我的 [手把手刷二叉树课程](https://aep.xet.tech/s/3YGcq3) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
> info在开头先打个广告我的 [手把手刷二叉树课程](https://labuladong.online/algo/tree-class/) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
@ -237,11 +237,15 @@ void traverse(ListNode head) {
**二叉树题目的递归解法可以分两类思路,第一类是遍历一遍二叉树得出答案,第二类是通过分解问题计算出答案,这两类思路分别对应着 [回溯算法核心框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版) 和 [动态规划核心框架](https://labuladong.github.io/article/fname.html?fname=动态规划详解进阶)**。
> tip这里说一下我的函数命名习惯二叉树中用遍历思路解题时函数签名一般是 `void traverse(...)`,没有返回值,靠更新外部变量来计算结果,而用分解问题思路解题时函数名根据该函数具体功能而定,而且一般会有返回值,返回值是子问题的计算结果。
>
> 与此对应的,你会发现我在 [回溯算法核心框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版) 中给出的函数签名一般也是没有返回值的 `void backtrack(...)`,而在 [动态规划核心框架](https://labuladong.github.io/article/fname.html?fname=动态规划详解进阶) 中给出的函数签名是带有返回值的 `dp` 函数。这也说明它俩和二叉树之间千丝万缕的联系。
>
> 虽然函数命名没有什么硬性的要求,但我还是建议你也遵循我的这种风格,这样更能突出函数的作用和解题的思维模式,便于你自己理解和运用。
::: tip
这里说一下我的函数命名习惯:二叉树中用遍历思路解题时函数签名一般是 `void traverse(...)`,没有返回值,靠更新外部变量来计算结果,而用分解问题思路解题时函数名根据该函数具体功能而定,而且一般会有返回值,返回值是子问题的计算结果。
与此对应的,你会发现我在 [回溯算法核心框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版) 中给出的函数签名一般也是没有返回值的 `void backtrack(...)`,而在 [动态规划核心框架](https://labuladong.github.io/article/fname.html?fname=动态规划详解进阶) 中给出的函数签名是带有返回值的 `dp` 函数。这也说明它俩和二叉树之间千丝万缕的联系。
虽然函数命名没有什么硬性的要求,但我还是建议你也遵循我的这种风格,这样更能突出函数的作用和解题的思维模式,便于你自己理解和运用。
:::
当时我是用二叉树的最大深度这个问题来举例,重点在于把这两种思路和动态规划和回溯算法进行对比,而本文的重点在于分析这两种思路如何解决二叉树的题目。
@ -396,7 +400,7 @@ Java 的话无论 ArrayList 还是 LinkedList`addAll` 方法的复杂度都
**3、无论使用哪一种思维模式你都要明白二叉树的每一个节点需要做什么需要在什么时候前中后序做**。
**[我的刷题插件](https://labuladong.gitee.io/article/fname.html?fname=chrome插件简介) 更新了所有值得一做的二叉树题目思路,全部归类为上述两种思路**,你如果按照插件提供的思路解法过一遍二叉树的所有题目,不仅可以完全掌握递归思维,而且可以更容易理解高级的算法:
**[我的刷题插件](https://labuladong.github.io/article/fname.html?fname=chrome插件简介) 更新了所有值得一做的二叉树题目思路,全部归类为上述两种思路**,你如果按照插件提供的思路解法过一遍二叉树的所有题目,不仅可以完全掌握递归思维,而且可以更容易理解高级的算法:
![](https://labuladong.github.io/pictures/二叉树收官/plugin1.jpg)
@ -560,11 +564,15 @@ class Solution {
讲到这里,照应一下前文:遇到子树问题,首先想到的是给函数设置返回值,然后在后序位置做文章。
> info思考题请你思考一下运用后序遍历的题目使用的是「遍历」的思路还是「分解问题」的思路我会在文末给出答案。
::: info
思考题:请你思考一下,运用后序遍历的题目使用的是「遍历」的思路还是「分解问题」的思路?我会在文末给出答案。
:::
反过来,如果你写出了类似一开始的那种递归套递归的解法,大概率也需要反思是不是可以通过后序遍历优化了。
**[我的刷题插件](https://labuladong.gitee.io/article/fname.html?fname=chrome插件简介)对于这类考察后序遍历的题目也有特殊的说明**,并且会给出前置题目,帮助你由浅入深理解这类题目:
**[我的刷题插件](https://labuladong.github.io/article/fname.html?fname=chrome插件简介)对于这类考察后序遍历的题目也有特殊的说明**,并且会给出前置题目,帮助你由浅入深理解这类题目:
![](https://labuladong.github.io/pictures/二叉树收官/plugin2.png)
@ -806,7 +814,7 @@ void levelTraverse(TreeNode root) {
值得一提的是,有些很明显需要用层序遍历技巧的二叉树的题目,也可以用递归遍历的方式去解决,而且技巧性会更强,非常考察你对前中后序的把控。
对于这类问题,[我的刷题插件](https://labuladong.gitee.io/article/fname.html?fname=chrome插件简介)也会同时提供递归遍历和层序遍历的解法代码:
对于这类问题,[我的刷题插件](https://labuladong.github.io/article/fname.html?fname=chrome插件简介)也会同时提供递归遍历和层序遍历的解法代码:
![](https://labuladong.github.io/pictures/二叉树收官/plugin4.png)
@ -814,9 +822,13 @@ void levelTraverse(TreeNode root) {
希望大家能探索尽可能多的解法,只要参透二叉树这种基本数据结构的原理,那么就很容易在学习其他高级算法的道路上找到抓手,打通回路,形成闭环(手动狗头)。
最后,我在不断完善刷题插件对二叉树系列题目的支持,在公众号后台回复关键词「**插件**」即可下载,购买我的 **[手把手刷二叉树系列课程](https://aep.xet.tech/s/3YGcq3)** 即可手把手带你运用本文所讲的技巧。
最后,我在不断完善刷题插件对二叉树系列题目的支持,在公众号后台回复关键词「**插件**」即可下载,购买我的 **[手把手刷二叉树系列课程](https://labuladong.online/algo/tree-class/)** 即可手把手带你运用本文所讲的技巧。
> info思考题答案文中后序遍历的例题使用了「分解问题」的思路。因为当前节点接收并利用了子树返回的信息这就意味着你把原问题分解成了当前节点 + 左右子树的子问题。
::: info
思考题答案:文中后序遍历的例题使用了「分解问题」的思路。因为当前节点接收并利用了子树返回的信息,这就意味着你把原问题分解成了当前节点 + 左右子树的子问题。
:::
**2022/5/12 更新**
@ -923,14 +935,15 @@ class Solution {
- [二叉树递归专题课](https://labuladong.github.io/article/fname.html?fname=tree课程简介)
- [前缀树算法模板秒杀五道算法题](https://labuladong.github.io/article/fname.html?fname=trie)
- [动态规划和回溯算法的思维转换](https://labuladong.github.io/article/fname.html?fname=单词拼接)
- [可视化代码编辑器使用指南](https://labuladong.github.io/article/fname.html?fname=可视化编辑器-wx)
- [后序遍历的妙用](https://labuladong.github.io/article/fname.html?fname=后序遍历)
- [回溯算法秒杀所有排列/组合/子集问题](https://labuladong.github.io/article/fname.html?fname=子集排列组合)
- [回溯算法解题套路框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版)
- [图论基础及遍历算法](https://labuladong.github.io/article/fname.html?fname=图)
- [归并排序详解及应用](https://labuladong.github.io/article/fname.html?fname=归并排序)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
- [算法可视化功能简介(必读)](https://labuladong.github.io/article/fname.html?fname=可视化简介)
- [算法可视化面板简介(必读)](https://labuladong.github.io/article/fname.html?fname=可视化简介)
- [算法学习和心流体验](https://labuladong.github.io/article/fname.html?fname=心流)
</details><hr>
@ -954,6 +967,7 @@ class Solution {
| [108. Convert Sorted Array to Binary Search Tree](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/?show=1) | [108. 将有序数组转换为二叉搜索树](https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/?show=1) |
| [1080. Insufficient Nodes in Root to Leaf Paths](https://leetcode.com/problems/insufficient-nodes-in-root-to-leaf-paths/?show=1) | [1080. 根到叶路径上的不足节点](https://leetcode.cn/problems/insufficient-nodes-in-root-to-leaf-paths/?show=1) |
| [110. Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree/?show=1) | [110. 平衡二叉树](https://leetcode.cn/problems/balanced-binary-tree/?show=1) |
| [111. Minimum Depth of Binary Tree](https://leetcode.com/problems/minimum-depth-of-binary-tree/?show=1) | [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/?show=1) |
| [1110. Delete Nodes And Return Forest](https://leetcode.com/problems/delete-nodes-and-return-forest/?show=1) | [1110. 删点成林](https://leetcode.cn/problems/delete-nodes-and-return-forest/?show=1) |
| [1120. Maximum Average Subtree](https://leetcode.com/problems/maximum-average-subtree/?show=1)🔒 | [1120. 子树的最大平均值](https://leetcode.cn/problems/maximum-average-subtree/?show=1)🔒 |
| [113. Path Sum II](https://leetcode.com/problems/path-sum-ii/?show=1) | [113. 路径总和 II](https://leetcode.cn/problems/path-sum-ii/?show=1) |
@ -987,6 +1001,7 @@ class Solution {
| [250. Count Univalue Subtrees](https://leetcode.com/problems/count-univalue-subtrees/?show=1)🔒 | [250. 统计同值子树](https://leetcode.cn/problems/count-univalue-subtrees/?show=1)🔒 |
| [254. Factor Combinations](https://leetcode.com/problems/factor-combinations/?show=1)🔒 | [254. 因子的组合](https://leetcode.cn/problems/factor-combinations/?show=1)🔒 |
| [257. Binary Tree Paths](https://leetcode.com/problems/binary-tree-paths/?show=1) | [257. 二叉树的所有路径](https://leetcode.cn/problems/binary-tree-paths/?show=1) |
| [267. Palindrome Permutation II](https://leetcode.com/problems/palindrome-permutation-ii/?show=1)🔒 | [267. 回文排列 II](https://leetcode.cn/problems/palindrome-permutation-ii/?show=1)🔒 |
| [270. Closest Binary Search Tree Value](https://leetcode.com/problems/closest-binary-search-tree-value/?show=1)🔒 | [270. 最接近的二叉搜索树值](https://leetcode.cn/problems/closest-binary-search-tree-value/?show=1)🔒 |
| [298. Binary Tree Longest Consecutive Sequence](https://leetcode.com/problems/binary-tree-longest-consecutive-sequence/?show=1)🔒 | [298. 二叉树最长连续序列](https://leetcode.cn/problems/binary-tree-longest-consecutive-sequence/?show=1)🔒 |
| [301. Remove Invalid Parentheses](https://leetcode.com/problems/remove-invalid-parentheses/?show=1) | [301. 删除无效的括号](https://leetcode.cn/problems/remove-invalid-parentheses/?show=1) |
@ -1055,6 +1070,6 @@ class Solution {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -29,21 +29,25 @@
> info在开头先打个广告我的 [手把手刷二叉树课程](https://aep.xet.tech/s/3YGcq3) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
> info在开头先打个广告我的 [手把手刷二叉树课程](https://labuladong.online/algo/tree-class/) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
本文承接 [东哥带你刷二叉树(纲领篇)](https://labuladong.github.io/article/fname.html?fname=二叉树总结),先复述一下前文总结的二叉树解题总纲:
> note二叉树解题的思维模式分两类
>
> **1、是否可以通过遍历一遍二叉树得到答案**?如果可以,用一个 `traverse` 函数配合外部变量来实现,这叫「遍历」的思维模式。
>
> **2、是否可以定义一个递归函数通过子问题子树的答案推导出原问题的答案**?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。
>
> 无论使用哪种思维模式,你都需要思考:
>
> **如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做**?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。
::: note
二叉树解题的思维模式分两类:
**1、是否可以通过遍历一遍二叉树得到答案**?如果可以,用一个 `traverse` 函数配合外部变量来实现,这叫「遍历」的思维模式。
**2、是否可以定义一个递归函数通过子问题子树的答案推导出原问题的答案**?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。
无论使用哪种思维模式,你都需要思考:
**如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做**?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。
:::
本文就以几道比较简单的题目为例,带你实践运用这几条总纲,理解「遍历」的思维和「分解问题」的思维有何区别和联系。
@ -367,7 +371,7 @@ void flatten(TreeNode root) {
希望你能仔细体会,并运用到所有二叉树题目上。
本文就到这里,更多经典的二叉树习题以及递归思维的训练,请参见 [手把手带你刷通二叉树](https://aep.xet.tech/s/3YGcq3)。
本文就到这里,更多经典的二叉树习题以及递归思维的训练,请参见 [手把手带你刷通二叉树](https://labuladong.online/algo/tree-class/)。
接下来可阅读:
@ -412,7 +416,7 @@ void flatten(TreeNode root) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -26,21 +26,25 @@
**-----------**
> info在开头先打个广告我的 [手把手刷二叉树课程](https://aep.xet.tech/s/3YGcq3) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
> info在开头先打个广告我的 [手把手刷二叉树课程](https://labuladong.online/algo/tree-class/) 按照公式和套路讲解了 150 道二叉树题目,只需一顿饭钱,就能手把手带你刷完二叉树分类的题目,迅速掌握递归思维,让你豁然开朗。我绝对有这个信心,信不信,可以等你看完我的二叉树算法系列文章再做评判。
本文是承接 [东哥带你刷二叉树(纲领篇)](https://labuladong.github.io/article/fname.html?fname=二叉树总结) 的第二篇文章,先复述一下前文总结的二叉树解题总纲:
> note二叉树解题的思维模式分两类
>
> **1、是否可以通过遍历一遍二叉树得到答案**?如果可以,用一个 `traverse` 函数配合外部变量来实现,这叫「遍历」的思维模式。
>
> **2、是否可以定义一个递归函数通过子问题子树的答案推导出原问题的答案**?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。
>
> 无论使用哪种思维模式,你都需要思考:
>
> **如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做**?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。
::: note
二叉树解题的思维模式分两类:
**1、是否可以通过遍历一遍二叉树得到答案**?如果可以,用一个 `traverse` 函数配合外部变量来实现,这叫「遍历」的思维模式。
**2、是否可以定义一个递归函数通过子问题子树的答案推导出原问题的答案**?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。
无论使用哪种思维模式,你都需要思考:
**如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做**?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。
:::
第一篇文章 [东哥带你刷二叉树(思维篇)](https://labuladong.github.io/article/fname.html?fname=二叉树系列1) 讲了「遍历」和「分解问题」两种思维方式,本文讲二叉树的构造类问题。
@ -587,7 +591,7 @@ int leftRootVal = preorder[preStart + 1];
- [东哥带你刷二叉树(序列化篇)](https://labuladong.github.io/article/fname.html?fname=二叉树的序列化)
- [东哥带你刷二叉树(思路篇)](https://labuladong.github.io/article/fname.html?fname=二叉树系列1)
- [二叉树的递归转迭代的代码框架](https://labuladong.github.io/article/fname.html?fname=迭代遍历二叉树)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
</details><hr>
@ -613,6 +617,6 @@ int leftRootVal = preorder[preStart + 1];
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -26,7 +26,7 @@
stack是很简单的一种数据结构先进后出的逻辑顺序符合某些问题的特点比如说函数调用栈。单调栈实际上就是栈只是利用了一些巧妙的逻辑使得每次新元素入栈后栈内的元素都保持有序单调递增或单调递减
听起来有点像堆heap不是的单调栈用途不太广泛只处理一类典型的问题比如「下一个更大元素」「上一个更小元素」等。本文用讲解单调队列的算法模版解决「下一个更大元素」相关问题并且探讨处理「循环数组」的策略。至于其他的变体和经典例题我会在 [数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 中讲解。
听起来有点像堆heap不是的单调栈用途不太广泛只处理一类典型的问题比如「下一个更大元素」「上一个更小元素」等。本文用讲解单调队列的算法模版解决「下一个更大元素」相关问题并且探讨处理「循环数组」的策略。至于其他的变体和经典例题我会在 [数据结构精品课](https://labuladong.online/algo/ds-class/) 中讲解。
### 单调栈模板
@ -208,7 +208,7 @@ int[] nextGreaterElements(int[] nums) {
最后提出一些问题吧,本文提供的单调栈模板是 `nextGreaterElement` 函数,可以计算每个元素的下一个更大元素,但如果题目让你计算上一个更大元素,或者计算上一个更大或相等的元素,应该如何修改对应的模板呢?而且在实际应用中,题目不会直接让你计算下一个(上一个)更大(小)的元素,你如何把问题转化成单调栈相关的问题呢?
我会在 [单调栈的几种变体](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_628dc1ace4b09dda126cf793/1) 对比单调栈的几种其他形式,并在 [单调栈的运用](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_628dc2d7e4b0cedf38b67734/1) 中给出单调栈的经典例题。更多数据结构设计类题目参见 [数据结构设计经典习题](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_6312b9e5e4b0eca59c2b7e93/1)。
我会在 [单调栈的几种变体](https://labuladong.online/algo/ds-class/dui-lie-zh-a84cc/dan-diao-z-7a8ef) 对比单调栈的几种其他形式,并在 [单调栈的运用](https://labuladong.online/algo/ds-class/dui-lie-zh-a84cc/qiang-hua--2cb3b) 中给出单调栈的经典例题。更多数据结构设计类题目参见 [数据结构设计经典习题](https://labuladong.online/algo/ds-class/jing-dian--9ec8b/qiang-hua--00937)。
@ -251,7 +251,7 @@ int[] nextGreaterElements(int[] nums) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -279,7 +279,7 @@ class MonotonicQueue<E extends Comparable<E>> {
}
```
我将在 [单调队列通用实现及应用](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_62a692efe4b01a48520b9b9b/1) 中给出单调队列的通用实现和经典习题。更多数据结构设计类题目参见 [数据结构设计经典习题](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_6312b9e5e4b0eca59c2b7e93/1)。
我将在 [单调队列通用实现及应用](https://labuladong.online/algo/ds-class/dui-lie-zh-a84cc/qiang-hua--f28e1) 中给出单调队列的通用实现和经典习题。更多数据结构设计类题目参见 [数据结构设计经典习题](https://labuladong.online/algo/ds-class/jing-dian--9ec8b/qiang-hua--00937)。
@ -316,7 +316,7 @@ class MonotonicQueue<E extends Comparable<E>> {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -103,7 +103,11 @@ boolean[][] matrix;
所以说,使用哪一种方式实现图,要看具体情况。
> tip在常规的算法题中邻接表的使用会更频繁一些主要是因为操作起来较为简单但这不意味着邻接矩阵应该被轻视。矩阵是一个强有力的数学工具图的一些隐晦性质可以借助精妙的矩阵运算展现出来。不过本文不准备引入数学内容所以有兴趣的读者可以自行搜索学习。
::: tip
在常规的算法题中,邻接表的使用会更频繁一些,主要是因为操作起来较为简单,但这不意味着邻接矩阵应该被轻视。矩阵是一个强有力的数学工具,图的一些隐晦性质可以借助精妙的矩阵运算展现出来。不过本文不准备引入数学内容,所以有兴趣的读者可以自行搜索学习。
:::
最后,我们再明确一个图论中特有的**度**degree的概念在无向图中「度」就是每个节点相连的边的条数。
@ -344,7 +348,7 @@ class Solution {
- [前缀树算法模板秒杀五道算法题](https://labuladong.github.io/article/fname.html?fname=trie)
- [回溯算法解题套路框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版)
- [并查集Union-Find算法](https://labuladong.github.io/article/fname.html?fname=UnionFind算法详解)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [环检测及拓扑排序算法](https://labuladong.github.io/article/fname.html?fname=拓扑排序)
- [用算法打败算法](https://labuladong.github.io/article/fname.html?fname=PDF中的算法)
- [算法学习和心流体验](https://labuladong.github.io/article/fname.html?fname=心流)
@ -380,6 +384,6 @@ class Solution {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -326,7 +326,7 @@ def calculate(s: str) -> int:
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -190,7 +190,11 @@ void traverse(List<Integer>[] graph, int s) {
**上述 GIF 描述了递归遍历二叉树的过程,在 `visited` 中被标记为 true 的节点用灰色表示,在 `onPath` 中被标记为 true 的节点用绿色表示**。
> tip类比贪吃蛇游戏`visited` 记录蛇经过过的格子,而 `onPath` 仅仅记录蛇身。`onPath` 用于判断是否成环,类比当贪吃蛇自己咬到自己(成环)的场景。
::: tip
类比贪吃蛇游戏,`visited` 记录蛇经过过的格子,而 `onPath` 仅仅记录蛇身。`onPath` 用于判断是否成环,类比当贪吃蛇自己咬到自己(成环)的场景。
:::
这样,就可以在遍历图的过程中顺便判断是否存在环了,完整代码如下:
@ -279,7 +283,11 @@ int[] findOrder(int numCourses, int[][] prerequisites);
![](https://labuladong.github.io/pictures/拓扑排序/top.jpg)
> note图片中拓扑排序的结果有误`C7->C8->C6` 应该改为 `C6->C7->C8`
::: note
图片中拓扑排序的结果有误,`C7->C8->C6` 应该改为 `C6->C7->C8`
:::
**直观地说就是,让你把一幅图「拉平」,而且这个「拉平」的图里面,所有箭头方向都是一致的**,比如上图所有箭头都是朝右的。
@ -306,12 +314,17 @@ public int[] findOrder(int numCourses, int[][] prerequisites) {
**其实特别简单,将后序遍历的结果进行反转,就是拓扑排序的结果**。
> note有的读者提到他在网上看到的拓扑排序算法不用对后序遍历结果进行反转这是为什么呢
>
> 你确实可以看到这样的解法,原因是他建图的时候对边的定义和我不同。我建的图中箭头方向是「被依赖」关系,比如节点 `1` 指向 `2`,含义是节点 `1` 被节点 `2` 依赖,即做完 `1` 才能去做 `2`
::: note
有的读者提到,他在网上看到的拓扑排序算法不用对后序遍历结果进行反转,这是为什么呢?
你确实可以看到这样的解法,原因是他建图的时候对边的定义和我不同。我建的图中箭头方向是「被依赖」关系,比如节点 `1` 指向 `2`,含义是节点 `1` 被节点 `2` 依赖,即做完 `1` 才能去做 `2`
如果你反过来,把有向边定义为「依赖」关系,那么整幅图中边全部反转,就可以不对后序遍历结果反转。具体来说,就是把我的解法代码中 `graph[from].add(to);` 改成 `graph[to].add(from);` 就可以不反转了。
:::
**不过呢,现实中一般都是从初级任务指向进阶任务,所以像我这样把边定义为「被依赖」关系可能比较符合我们的认知习惯**。
直接看解法代码吧,在上一题环检测的代码基础上添加了记录后序遍历结果的逻辑:
@ -603,7 +616,7 @@ List<Integer>[] buildGraph(int n, int[][] edges) {
- [二分图判定算法](https://labuladong.github.io/article/fname.html?fname=二分图)
- [图论基础及遍历算法](https://labuladong.github.io/article/fname.html?fname=图)
- [并查集Union-Find算法](https://labuladong.github.io/article/fname.html?fname=UnionFind算法详解)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [用算法打败算法](https://labuladong.github.io/article/fname.html?fname=PDF中的算法)
</details><hr>
@ -629,6 +642,6 @@ List<Integer>[] buildGraph(int n, int[][] edges) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -299,7 +299,7 @@ class Twitter {
我们解决的问题应该只能算 Timeline Service 模块的一小部分功能越多系统的复杂性可能是指数级增长的。所以说合理的顶层设计十分重要其作用是远超某一个算法的。Github 上有一个优秀的开源项目,专门收集了很多大型系统设计的案例和解析,而且有中文版本,上面这个图也出自该项目。对系统设计感兴趣的读者可以点击 [这里](https://github.com/donnemartin/system-design-primer) 查看。
本文就到这里,更多数据结构设计相关的题目参见 [数据结构设计经典习题](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_6312b9e5e4b0eca59c2b7e93/1)。
本文就到这里,更多数据结构设计相关的题目参见 [数据结构设计经典习题](https://labuladong.online/algo/ds-class/jing-dian--9ec8b/qiang-hua--00937)。
@ -317,7 +317,7 @@ class Twitter {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -26,7 +26,11 @@
反转单链表的迭代实现不是一个困难的事情,但是递归实现就有点难度了,如果再加一点难度,让你仅仅反转单链表中的一部分,你是否能**够递归实现**呢?
> tip迭代反转单链表的实现参见 [如何 k 个一组反转链表](https://labuladong.github.io/article/fname.html?fname=k个一组反转链表)。
::: tip
迭代反转单链表的实现参见 [如何 k 个一组反转链表](https://labuladong.github.io/article/fname.html?fname=k个一组反转链表)。
:::
本文就来由浅入深step by step 地解决这个问题。如果你还不会递归地反转单链表也没关系,**本文会从递归反转整个单链表开始拓展**,只要你明白单链表的结构,相信你能够有所收获。
@ -273,7 +277,7 @@ ListNode reverseBetween(ListNode head, int m, int n) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -283,7 +283,7 @@ class MyStack {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -238,7 +238,11 @@ void BFS(String target) {
}
```
> PS这段代码当然有很多问题但是我们做算法题肯定不是一蹴而就的而是从简陋到完美的。不要完美主义咱要慢慢来好不。
::: note
这段代码当然有很多问题,但是我们做算法题肯定不是一蹴而就的,而是从简陋到完美的。不要完美主义,咱要慢慢来,好不。
:::
**这段 BFS 代码已经能够穷举所有可能的密码组合了,但是显然不能完成题目,有如下问题需要解决**
@ -407,7 +411,7 @@ while (!q1.isEmpty() && !q2.isEmpty()) {
- [二叉树的递归转迭代的代码框架](https://labuladong.github.io/article/fname.html?fname=迭代遍历二叉树)
- [分治算法详解:运算优先级](https://labuladong.github.io/article/fname.html?fname=分治算法)
- [如何用 BFS 算法秒杀各种智力题](https://labuladong.github.io/article/fname.html?fname=BFS解决滑动拼图)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [旅游省钱大法:加权最短路径](https://labuladong.github.io/article/fname.html?fname=旅行最短路径)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
- [环检测及拓扑排序算法](https://labuladong.github.io/article/fname.html?fname=拓扑排序)
@ -451,6 +455,6 @@ while (!q1.isEmpty() && !q2.isEmpty()) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -225,6 +225,6 @@ class Solution {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -79,501 +79,6 @@ class UF {
这样你应该大概明白什么是动态连通性了Union-Find 算法的关键就在于 `union``connected` 函数的效率。那么用什么模型来表示这幅图的连通状态呢?用什么数据结构来实现代码呢?
### 二、基本思路
注意我刚才把「模型」和具体的「数据结构」分开说,这么做是有原因的。因为我们使用森林(若干棵树)来表示图的动态连通性,用数组来具体实现这个森林。
怎么用森林来表示连通性呢?我们设定树的每个节点有一个指针指向其父节点,如果是根节点的话,这个指针指向自己。比如说刚才那幅 10 个节点的图,一开始的时候没有相互连通,就是这样:
![](https://labuladong.github.io/pictures/unionfind/3.jpg)
<!-- muliti_language -->
```java
class UF {
// 记录连通分量
private int count;
// 节点 x 的父节点是 parent[x]
private int[] parent;
/* 构造函数n 为图的节点总数 */
public UF(int n) {
// 一开始互不连通
this.count = n;
// 父节点指针初始指向自己
parent = new int[n];
for (int i = 0; i < n; i++)
parent[i] = i;
}
/* 其他函数 */
}
```
**如果某两个节点被连通,则让其中的(任意)一个节点的根节点接到另一个节点的根节点上**
![](https://labuladong.github.io/pictures/unionfind/4.jpg)
<!-- muliti_language -->
```java
class UF {
// 为了节约篇幅,省略上文给出的代码部分...
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ)
return;
// 将两棵树合并为一棵
parent[rootP] = rootQ;
// parent[rootQ] = rootP 也一样
count--; // 两个分量合二为一
}
/* 返回某个节点 x 的根节点 */
private int find(int x) {
// 根节点的 parent[x] == x
while (parent[x] != x)
x = parent[x];
return x;
}
/* 返回当前的连通分量个数 */
public int count() {
return count;
}
}
```
**这样,如果节点 `p``q` 连通的话,它们一定拥有相同的根节点**
![](https://labuladong.github.io/pictures/unionfind/5.jpg)
<!-- muliti_language -->
```java
class UF {
// 为了节约篇幅,省略上文给出的代码部分...
public boolean connected(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
return rootP == rootQ;
}
}
```
至此Union-Find 算法就基本完成了。是不是很神奇?竟然可以这样使用数组来模拟出一个森林,如此巧妙的解决这个比较复杂的问题!
那么这个算法的复杂度是多少呢?我们发现,主要 API `connected``union` 中的复杂度都是 `find` 函数造成的,所以说它们的复杂度和 `find` 一样。
`find` 主要功能就是从某个节点向上遍历到树根,其时间复杂度就是树的高度。我们可能习惯性地认为树的高度就是 `logN`,但这并不一定。`logN` 的高度只存在于平衡二叉树,对于一般的树可能出现极端不平衡的情况,使得「树」几乎退化成「链表」,树的高度最坏情况下可能变成 `N`
![](https://labuladong.github.io/pictures/unionfind/6.jpg)
所以说上面这种解法,`find` , `union` , `connected` 的时间复杂度都是 O(N)。这个复杂度很不理想的,你想图论解决的都是诸如社交网络这样数据规模巨大的问题,对于 `union``connected` 的调用非常频繁,每次调用需要线性时间完全不可忍受。
**问题的关键在于,如何想办法避免树的不平衡呢**?只需要略施小计即可。
### 三、平衡性优化
我们要知道哪种情况下可能出现不平衡现象,关键在于 `union` 过程:
<!-- muliti_language -->
```java
class UF {
// 为了节约篇幅,省略上文给出的代码部分...
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ)
return;
// 将两棵树合并为一棵
parent[rootP] = rootQ;
// parent[rootQ] = rootP 也可以
count--;
}
}
```
我们一开始就是简单粗暴的把 `p` 所在的树接到 `q` 所在的树的根节点下面,那么这里就可能出现「头重脚轻」的不平衡状况,比如下面这种局面:
![](https://labuladong.github.io/pictures/unionfind/7.jpg)
长此以往,树可能生长得很不平衡。**我们其实是希望,小一些的树接到大一些的树下面,这样就能避免头重脚轻,更平衡一些**。解决方法是额外使用一个 `size` 数组,记录每棵树包含的节点数,我们不妨称为「重量」:
<!-- muliti_language -->
```java
class UF {
private int count;
private int[] parent;
// 新增一个数组记录树的“重量”
private int[] size;
public UF(int n) {
this.count = n;
parent = new int[n];
// 最初每棵树只有一个节点
// 重量应该初始化 1
size = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
}
/* 其他函数 */
}
```
比如说 `size[3] = 5` 表示,以节点 `3` 为根的那棵树,总共有 `5` 个节点。这样我们可以修改一下 `union` 方法:
<!-- muliti_language -->
```java
class UF {
// 为了节约篇幅,省略上文给出的代码部分...
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ)
return;
// 小树接到大树下面,较平衡
if (size[rootP] > size[rootQ]) {
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
} else {
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
}
count--;
}
}
```
这样,通过比较树的重量,就可以保证树的生长相对平衡,树的高度大致在 `logN` 这个数量级,极大提升执行效率。
此时,`find` , `union` , `connected` 的时间复杂度都下降为 O(logN),即便数据规模上亿,所需时间也非常少。
### 四、路径压缩
这步优化虽然代码很简单,但原理非常巧妙。
**其实我们并不在乎每棵树的结构长什么样,只在乎根节点**。
因为无论树长啥样,树上的每个节点的根节点都是相同的,所以能不能进一步压缩每棵树的高度,使树高始终保持为常数?
![](https://labuladong.github.io/pictures/unionfind/8.jpg)
这样每个节点的父节点就是整棵树的根节点,`find` 就能以 O(1) 的时间找到某一节点的根节点,相应的,`connected` 和 `union` 复杂度都下降为 O(1)。
要做到这一点主要是修改 `find` 函数逻辑,非常简单,但你可能会看到两种不同的写法。
第一种是在 `find` 中加一行代码:
<!-- muliti_language -->
```java
class UF {
// 为了节约篇幅,省略上文给出的代码部分...
private int find(int x) {
while (parent[x] != x) {
// 这行代码进行路径压缩
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
}
```
这个操作有点匪夷所思,看个 GIF 就明白它的作用了(为清晰起见,这棵树比较极端):
![](https://labuladong.github.io/pictures/unionfind/9.gif)
用语言描述就是,每次 while 循环都会让部分子节点向上移动,这样每次调用 `find` 函数向树根遍历的同时,顺手就将树高缩短了。
路径压缩的第二种写法是这样:
<!-- muliti_language -->
```java
class UF {
// 为了节约篇幅,省略上文给出的代码部分...
// 第二种路径压缩的 find 方法
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
}
```
我一度认为这种递归写法和第一种迭代写法做的事情一样,但实际上是我大意了,有读者指出这种写法进行路径压缩的效率是高于上一种解法的。
这个递归过程有点不好理解,你可以自己手画一下递归过程。我把这个函数做的事情翻译成迭代形式,方便你理解它进行路径压缩的原理:
<!-- muliti_language -->
```java
// 这段迭代代码方便你理解递归代码所做的事情
public int find(int x) {
// 先找到根节点
int root = x;
while (parent[root] != root) {
root = parent[root];
}
// 然后把 x 到根节点之间的所有节点直接接到根节点下面
int old_parent = parent[x];
while (x != root) {
parent[x] = root;
x = old_parent;
old_parent = parent[old_parent];
}
return root;
}
```
这种路径压缩的效果如下:
![](https://labuladong.github.io/pictures/unionfind/10.jpeg)
比起第一种路径压缩,显然这种方法压缩得更彻底,直接把一整条树枝压平,一点意外都没有。就算一些极端情况下产生了一棵比较高的树,只要一次路径压缩就能大幅降低树高,从 [摊还分析](https://labuladong.github.io/article/fname.html?fname=时间复杂度) 的角度来看,所有操作的平均时间复杂度依然是 O(1),所以从效率的角度来说,推荐你使用这种路径压缩算法。
**另外,如果使用路径压缩技巧,那么 `size` 数组的平衡优化就不是特别必要了**。所以你一般看到的 Union Find 算法应该是如下实现:
<!-- muliti_language -->
```java
class UF {
// 连通分量个数
private int count;
// 存储每个节点的父节点
private int[] parent;
// n 为图中节点的个数
public UF(int n) {
this.count = n;
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
// 将节点 p 和节点 q 连通
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ)
return;
parent[rootQ] = rootP;
// 两个连通分量合并成一个连通分量
count--;
}
// 判断节点 p 和节点 q 是否连通
public boolean connected(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
return rootP == rootQ;
}
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
// 返回图中的连通分量个数
public int count() {
return count;
}
}
```
Union-Find 算法的复杂度可以这样分析:构造函数初始化数据结构需要 O(N) 的时间和空间复杂度;连通两个节点 `union`、判断两个节点的连通性 `connected`、计算连通分量 `count` 所需的时间复杂度均为 O(1)。
到这里,相信你已经掌握了 Union-Find 算法的核心逻辑,总结一下我们优化算法的过程:
1、用 `parent` 数组记录每个节点的父节点,相当于指向父节点的指针,所以 `parent` 数组内实际存储着一个森林(若干棵多叉树)。
2、用 `size` 数组记录着每棵树的重量,目的是让 `union` 后树依然拥有平衡性,保证各个 API 时间复杂度为 O(logN),而不会退化成链表影响操作效率。
3、在 `find` 函数中进行路径压缩,保证任意树的高度保持在常数,使得各个 API 时间复杂度为 O(1)。使用了路径压缩之后,可以不使用 `size` 数组的平衡优化。
下面我们看一些具体的并查集题目。
### 题目实践
力扣第 323 题「无向图中连通分量的数目」就是最基本的连通分量题目:
给你输入一个包含 `n` 个节点的图,用一个整数 `n` 和一个数组 `edges` 表示,其中 `edges[i] = [ai, bi]` 表示图中节点 `ai``bi` 之间有一条边。请你计算这幅图的连通分量个数。
函数签名如下:
<!-- muliti_language -->
```java
int countComponents(int n, int[][] edges)
```
这道题我们可以直接套用 `UF` 类来解决:
<!-- muliti_language -->
```java
public int countComponents(int n, int[][] edges) {
UF uf = new UF(n);
// 将每个节点进行连通
for (int[] e : edges) {
uf.union(e[0], e[1]);
}
// 返回连通分量的个数
return uf.count();
}
class UF {
// 见上文
}
```
**另外,一些使用 DFS 深度优先算法解决的问题,也可以用 Union-Find 算法解决**。
比如力扣第 130 题「被围绕的区域」:
给你一个 M×N 的二维矩阵,其中包含字符 `X``O`,让你找到矩阵中**四面**被 `X` 围住的 `O`,并且把它们替换成 `X`
<!-- muliti_language -->
```java
void solve(char[][] board);
```
注意哦,必须是四面被围的 `O` 才能被换成 `X`,也就是说边角上的 `O` 一定不会被围,进一步,与边角上的 `O` 相连的 `O` 也不会被 `X` 围四面,也不会被替换。
![](https://labuladong.github.io/pictures/unionfind应用/2.jpg)
> note这让我想起小时候玩的棋类游戏「黑白棋」只要你用两个棋子把对方的棋子夹在中间对方的子就被替换成你的子。可见占据四角的棋子是无敌的与其相连的边棋子也是无敌的无法被夹掉
其实这个问题应该归为 [岛屿系列问题](https://labuladong.github.io/article/fname.html?fname=岛屿题目) 使用 DFS 算法解决:
先用 for 循环遍历棋盘的**四边**,用 DFS 算法把那些与边界相连的 `O` 换成一个特殊字符,比如 `#`;然后再遍历整个棋盘,把剩下的 `O` 换成 `X`,把 `#` 恢复成 `O`。这样就能完成题目的要求,时间复杂度 O(MN)。
但这个问题也可以用 Union-Find 算法解决,虽然实现复杂一些,甚至效率也略低,但这是使用 Union-Find 算法的通用思想,值得一学。
**你可以把那些不需要被替换的 `O` 看成一个拥有独门绝技的门派,它们有一个共同「祖师爷」叫 `dummy`,这些 `O``dummy` 互相连通,而那些需要被替换的 `O``dummy` 不连通**。
![](https://labuladong.github.io/pictures/unionfind应用/3.jpg)
这就是 Union-Find 的核心思路,明白这个图,就很容易看懂代码了。
首先要解决的是根据我们的实现Union-Find 底层用的是一维数组,构造函数需要传入这个数组的大小,而题目给的是一个二维棋盘。
这个很简单,二维坐标 `(x,y)` 可以转换成 `x * n + y` 这个数(`m` 是棋盘的行数,`n` 是棋盘的列数),**敲黑板,这是将二维坐标映射到一维的常用技巧**。
其次,我们之前描述的「祖师爷」是虚构的,需要给他老人家留个位置。索引 `[0.. m*n-1]` 都是棋盘内坐标的一维映射,那就让这个虚拟的 `dummy` 节点占据索引 `m * n` 好了。
看解法代码:
<!-- muliti_language -->
```java
void solve(char[][] board) {
if (board.length == 0) return;
int m = board.length;
int n = board[0].length;
// 给 dummy 留一个额外位置
UF uf = new UF(m * n + 1);
int dummy = m * n;
// 将首列和末列的 O 与 dummy 连通
for (int i = 0; i < m; i++) {
if (board[i][0] == 'O')
uf.union(i * n, dummy);
if (board[i][n - 1] == 'O')
uf.union(i * n + n - 1, dummy);
}
// 将首行和末行的 O 与 dummy 连通
for (int j = 0; j < n; j++) {
if (board[0][j] == 'O')
uf.union(j, dummy);
if (board[m - 1][j] == 'O')
uf.union(n * (m - 1) + j, dummy);
}
// 方向数组 d 是上下左右搜索的常用手法
int[][] d = new int[][]{{1,0}, {0,1}, {0,-1}, {-1,0}};
for (int i = 1; i < m - 1; i++)
for (int j = 1; j < n - 1; j++)
if (board[i][j] == 'O')
// 将此 O 与上下左右的 O 连通
for (int k = 0; k < 4; k++) {
int x = i + d[k][0];
int y = j + d[k][1];
if (board[x][y] == 'O')
uf.union(x * n + y, i * n + j);
}
// 所有不和 dummy 连通的 O都要被替换
for (int i = 1; i < m - 1; i++)
for (int j = 1; j < n - 1; j++)
if (!uf.connected(dummy, i * n + j))
board[i][j] = 'X';
}
class UF {
// 见上文
}
```
这段代码很长,其实就是刚才的思路实现,只有和边界 `O` 相连的 `O` 才具有和 `dummy` 的连通性,他们不会被替换。
其实用 Union-Find 算法解决这个简单的问题有点杀鸡用牛刀,它可以解决更复杂,更具有技巧性的问题,**主要思路是适时增加虚拟节点,想办法让元素「分门别类」,建立动态连通关系**。
力扣第 990 题「等式方程的可满足性」用 Union-Find 算法就显得十分优美了,题目是这样:
给你一个数组 `equations`,装着若干字符串表示的算式。每个算式 `equations[i]` 长度都是 4而且只有这两种情况`a==b` 或者 `a!=b`,其中 `a,b` 可以是任意小写字母。你写一个算法,如果 `equations` 中所有算式都不会互相冲突,返回 true否则返回 false。
比如说,输入 `["a==b","b!=c","c==a"]`,算法返回 false因为这三个算式不可能同时正确。
再比如,输入 `["c==c","b==d","x!=z"]`,算法返回 true因为这三个算式并不会造成逻辑冲突。
我们前文说过,动态连通性其实就是一种等价关系,具有「自反性」「传递性」和「对称性」,其实 `==` 关系也是一种等价关系,具有这些性质。所以这个问题用 Union-Find 算法就很自然。
**核心思想是,将 `equations` 中的算式根据 `==``!=` 分成两部分,先处理 `==` 算式,使得他们通过相等关系各自勾结成门派(连通分量);然后处理 `!=` 算式,检查不等关系是否破坏了相等关系的连通性**。
<!-- muliti_language -->
```java
boolean equationsPossible(String[] equations) {
// 26 个英文字母
UF uf = new UF(26);
// 先让相等的字母形成连通分量
for (String eq : equations) {
if (eq.charAt(1) == '=') {
char x = eq.charAt(0);
char y = eq.charAt(3);
uf.union(x - 'a', y - 'a');
}
}
// 检查不等关系是否打破相等关系的连通性
for (String eq : equations) {
if (eq.charAt(1) == '!') {
char x = eq.charAt(0);
char y = eq.charAt(3);
// 如果相等关系成立,就是逻辑冲突
if (uf.connected(x - 'a', y - 'a'))
return false;
}
}
return true;
}
class UF {
// 见上文
}
```
至此,这道判断算式合法性的问题就解决了,借助 Union-Find 算法,是不是很简单呢?
最后Union-Find 算法也会在一些其他经典图论算法中用到,比如判断「图」和「树」,以及最小生成树的计算,详情见 [Kruskal 最小生成树算法](https://labuladong.github.io/article/fname.html?fname=kruskal)。
<hr>
@ -585,7 +90,7 @@ class UF {
- [Prim 最小生成树算法](https://labuladong.github.io/article/fname.html?fname=prim算法)
- [一文秒杀所有岛屿题目](https://labuladong.github.io/article/fname.html?fname=岛屿题目)
- [二分图判定算法](https://labuladong.github.io/article/fname.html?fname=二分图)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [用算法打败算法](https://labuladong.github.io/article/fname.html?fname=PDF中的算法)
</details><hr>
@ -617,9 +122,9 @@ class UF {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=UnionFind算法详解) 查看
![](https://labuladong.github.io/pictures/souyisou2.png)
![](https://labuladong.github.io/pictures/qrcode.jpg)
======其他语言代码======

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -27,17 +27,19 @@
本文是前文 [二分搜索详解](https://mp.weixin.qq.com/s/uA2suoVykENmCQcKFMOSuQ) 的修订版,添加了对二分搜索算法更详细的分析。
本文是公众号文章 [二分搜索详解](https://mp.weixin.qq.com/s/uA2suoVykENmCQcKFMOSuQ) 的修订版,添加了对二分搜索算法更详细的分析。
先给大家讲个笑话乐呵一下:
有一天阿东到图书馆借了 `N` 本书,出图书馆的时候,警报响了,于是保安把阿东拦下,要检查一下哪本书没有登记出借。阿东正准备把每一本书在报警器下过一下,以找出引发警报的书,但是保安露出不屑的眼神:你连二分查找都不会吗?于是保安把书分成两堆,让第一堆过一下报警器,报警器响;于是再把这堆书分成两堆…… 最终,检测了 `logN` 次之后,保安成功的找到了那本引起警报的书,露出了得意和嘲讽的笑容。于是阿东背着剩下的书走了。
有一天阿东到图书馆借了 `N` 本书,出图书馆的时候,警报响了,于是保安把阿东拦下,要检查一下哪本书没有登记出借。阿东正准备把每一本书在报警器下过一下,以找出引发警报的书。但是保安露出不屑的眼神:你连二分查找都不会吗?
于是保安把书分成两堆,让第一堆过一下报警器,报警器响;于是再把这堆书分成两堆…… 最终,检测了 `logN` 次之后,保安成功的找到了那本引起警报的书,露出了得意和嘲讽的笑容。于是阿东背着剩下的书走了。
从此,图书馆丢了 `N - 1` 本书(手动狗头)。
二分查找并不简单Knuth 大佬(发明 KMP 算法的那位)都说二分查找:**思路很简单,细节是魔鬼**。很多人喜欢拿整型溢出的 bug 说事儿,但是二分查找真正的坑根本就不是那个细节问题,而是在于到底要给 `mid` 加一还是减一while 里到底用 `<=` 还是 `<`
你要是没有正确理解这些细节,写二分肯定就是玄学编程,有没有 bug 只能靠菩萨保佑(谁写谁知道)。我特意写了一首诗来歌颂该算法,概括本文的主要内容,建议保存(手动狗头):
你要是没有正确理解这些细节,写二分肯定就是玄学编程,有没有 bug 只能靠菩萨保佑,谁写谁知道。我特意写了一首诗来歌颂该算法,概括本文的主要内容,建议保存(手动狗头):
![](https://labuladong.github.io/pictures/二分查找/poem.png)
@ -178,13 +180,33 @@ int left_bound(int[] nums, int target) {
`while(left < right)` 终止的条件是 `left == right`,此时搜索区间 `[left, left)` 为空,所以可以正确终止。
> info这里先要说一个搜索左右边界和上面这个算法的一个区别也是很多读者问的**刚才的 `right` 不是 `nums.length - 1` 吗,为啥这里非要写成 `nums.length` 使得「搜索区间」变成左闭右开呢**
>
> 因为对于搜索左右侧边界的二分查找,这种写法比较普遍,我就拿这种写法举例了,保证你以后遇到这类代码可以理解。你非要用两端都闭的写法反而更简单,我会在后面写相关的代码,把三种二分搜索都用一种两端都闭的写法统一起来,你耐心往后看就行了。
::: info
**2、为什么没有返回 -1 的操作?如果 `nums` 中不存在 `target` 这个值,怎么办**
这里先要说一个搜索左右边界和上面这个算法的一个区别,也是很多读者问的:**刚才的 `right` 不是 `nums.length - 1` 吗,为啥这里非要写成 `nums.length` 使得「搜索区间」变成左闭右开呢**
答:其实很简单,在返回的时候额外判断一下 `nums[left]` 是否等于 `target` 就行了,如果不等于,就说明 `target` 不存在。需要注意的是,访问数组索引之前要保证索引不越界:
因为对于搜索左右侧边界的二分查找,这种写法比较普遍,我就拿这种写法举例了,保证你以后遇到这类代码可以理解。你非要用两端都闭的写法反而更简单,我会在后面写相关的代码,把三种二分搜索都用一种两端都闭的写法统一起来,你耐心往后看就行了。
:::
**2、如果 `nums` 中不存在 `target` 这个值,计算出来的这个索引含义是什么?如果我想让它返回 -1怎么做**
::: important 当 `target` 不存在时,`left_bound` 返回值的含义
这是一个很好且很重要的问题,你把这个地方理解了,在二分搜索的实际应用场景中就不会懵逼。
直接说结论:**如果 `target` 不存在,搜索左侧边界的二分搜索返回的索引是大于 `target` 的最小索引**。
举个例子,`nums = [2,3,5,7], target = 4``left_bound` 函数返回值是 2因为元素 5 是大于 4 的最小元素。
有点绕晕了是吧?这个 `left_bound` 函数明明是搜索左边界的,但是当 `target` 不存在的时候,却返回的是大于 `target` 的最小索引。这个结论不用死记,你要是拿不准,简单举个例子就能得到这个结论了。
所以说,二分搜索这个东西思路很简单,细节是魔鬼嘛,里面的坑太多了。要是真想考你,肯定可以把你考到怀疑人生。
我的建议是,如果你必须手写二分代码,那么你一定要了解清楚代码的种种行为,本文总结的框架就是在帮你理清这里面的细节。如果非必要,不要自己手写,尽肯能用编程语言提供的标准库函数,可以节约时间,而且标准库函数的行为在文档里都有明确的说明,不容易出错。
:::
如果想让 `target` 不存在时返回 -1 其实很简单,在返回的时候额外判断一下 `nums[left]` 是否等于 `target` 就行了,如果不等于,就说明 `target` 不存在。需要注意的是,访问数组索引之前要保证索引不越界:
```java
while (left < right) {
@ -198,7 +220,11 @@ if (left < 0 || left >= nums.length) {
return nums[left] == target ? left : -1;
```
> tip其实对于这个算法`left` 不可能小于 0。你可以想象一下算法执行的逻辑`left` 初始化就是 0且只可能一直往右走那么只可能在右侧越界。不过在访问数组索引之前保证索引在左右两端都不越界是一个很好的编程习惯没有坏处我这里就同时判断了。这样做的另一个好处是可以让二分的模板更统一降低你的记忆成本。
::: tip
其实对于这个算法,`left` 不可能小于 0。你可以想象一下算法执行的逻辑`left` 初始化就是 0且只可能一直往右走那么只可能在右侧越界。不过在访问数组索引之前保证索引在左右两端都不越界是一个很好的编程习惯没有坏处我这里就同时判断了。这样做的另一个好处是可以让二分的模板更统一降低你的记忆成本。
:::
**3、为什么 `left = mid + 1``right = mid` ?和之前的算法不一样**
@ -349,9 +375,20 @@ if (nums[mid] == target) {
至于为什么 `left` 的更新必须是 `left = mid + 1`,当然是为了把 `nums[mid]` 排除出搜索区间,这里就不再赘述。
**3、为什么没有返回 -1 的操作?如果 `nums` 中不存在 `target` 这个值,怎么办**
**3、如果 `nums` 中不存在 `target` 这个值,计算出来的这个索引含义是什么?如果我想让它返回 -1怎么做**
答:只要在最后判断一下 `nums[left-1]` 是不是 `target` 就行了,类似之前的左侧边界搜索,做一点额外的判断即可:
::: important 当 `target` 不存在时,`right_bound` 返回值的含义
直接说结论,和前面讲的 `left_bound` 相反:**如果 `target` 不存在,搜索右侧边界的二分搜索返回的索引是小于 `target` 的最大索引**。
这个结论不用死记,你要是拿不准,简单举个例子就能得到这个结论了。比如 `nums = [2,3,5,7], target = 4``right_bound` 函数返回值是 1因为元素 3 是小于 4 的最大元素。
与前面的建议相同,考虑到二分搜索代码细节的复杂性,如果非必要,不要自己手写,尽肯能用编程语言提供的标准库函数。
:::
如果你想在 `target` 不存在时返回 -1很简单只要在最后判断一下 `nums[left-1]` 是不是 `target` 就行了,类似之前的左侧边界搜索,做一点额外的判断即可:
<!-- muliti_language -->
```java
@ -522,10 +559,6 @@ int right_bound(int[] nums, int target) {
left = mid + 1;
}
}
// 判断 target 是否存在于 nums 中
// if (left - 1 < 0 || left - 1 >= nums.length) {
// return -1;
// }
// 由于 while 的结束条件是 right == left - 1且现在在求右边界
// 所以用 right 替代 left - 1 更好记
@ -538,7 +571,7 @@ int right_bound(int[] nums, int target) {
如果以上内容你都能理解,那么恭喜你,二分查找算法的细节不过如此。通过本文,你学会了:
1、分析二分查找代码时不要出现 else全部展开成 else if 方便理解。
1、分析二分查找代码时不要出现 else全部展开成 else if 方便理解。把逻辑写对之后再合并分支,提升运行效率。
2、注意「搜索区间」和 while 的终止条件,如果存在漏掉的元素,记得在最后检查。
@ -548,7 +581,7 @@ int right_bound(int[] nums, int target) {
最后我想说,以上二分搜索的框架属于「术」的范畴,如果上升到「道」的层面,**二分思维的精髓就是:通过已知信息尽可能多地收缩(折半)搜索空间**,从而增加穷举效率,快速找到目标。
理解本文能保证你写出正确的二分查找的代码,但实际题目中不会直接让你写二分代码,我会在 [二分查找的变体](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_62a07736e4b01a485209b0b4/1) 和 [二分查找的运用](https://labuladong.github.io/article/fname.html?fname=二分运用) 中进一步讲解如何把二分思维运用到更多算法题中。
理解本文能保证你写出正确的二分查找的代码,但实际题目中不会直接让你写二分代码,我会在 [二分查找的变体](https://labuladong.online/algo/ds-class/shu-zu-lia-39fd9/qiang-hua--13406) 和 [二分查找的运用](https://labuladong.github.io/article/fname.html?fname=二分运用) 中进一步讲解如何把二分思维运用到更多算法题中。
@ -558,7 +591,7 @@ int right_bound(int[] nums, int target) {
- [base case 和备忘录的初始值怎么定?](https://labuladong.github.io/article/fname.html?fname=备忘录等基础)
- [【强化练习】二分搜索算法经典习题](https://labuladong.github.io/article/fname.html?fname=二分题目)
- [丑数系列算法详解](https://labuladong.github.io/article/fname.html?fname=丑数)
- [一文秒杀所有丑数系列问题](https://labuladong.github.io/article/fname.html?fname=丑数)
- [二分搜索怎么用?我又总结了套路](https://labuladong.github.io/article/fname.html?fname=二分运用)
- [二分查找高效判定子序列](https://labuladong.github.io/article/fname.html?fname=二分查找判定子序列)
- [动态规划设计:最长递增子序列](https://labuladong.github.io/article/fname.html?fname=动态规划设计:最长递增子序列)
@ -567,7 +600,7 @@ int right_bound(int[] nums, int target) {
- [带权重的随机选择算法](https://labuladong.github.io/article/fname.html?fname=随机权重)
- [快速排序详解及应用](https://labuladong.github.io/article/fname.html?fname=快速排序)
- [我写了首诗,把滑动窗口算法变成了默写题](https://labuladong.github.io/article/fname.html?fname=滑动窗口技巧进阶)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
- [用算法打败算法](https://labuladong.github.io/article/fname.html?fname=PDF中的算法)
- [讲两道常考的阶乘算法题](https://labuladong.github.io/article/fname.html?fname=阶乘题目)
@ -608,7 +641,7 @@ int right_bound(int[] nums, int target) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -133,7 +133,7 @@
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -180,7 +180,7 @@ class NumMatrix {
前缀和技巧就讲到这里,应该说这个算法技巧是会者不难难者不会,实际运用中还是要多培养自己的思维灵活性,做到一眼看出题目是一个前缀和问题。
除了本文举例的基本用法,前缀和数组经常和其他数据结构或算法技巧相结合,我会在 [前缀和技巧高频习题](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_627cd61de4b0cedf38b0f3a0/1) 中举例讲解。
除了本文举例的基本用法,前缀和数组经常和其他数据结构或算法技巧相结合,我会在 [前缀和技巧高频习题](https://labuladong.online/algo/ds-class/shu-zu-lia-39fd9/qiang-hua--a9442) 中举例讲解。
@ -194,7 +194,7 @@ class NumMatrix {
- [小而美的算法技巧:差分数组](https://labuladong.github.io/article/fname.html?fname=差分技巧)
- [带权重的随机选择算法](https://labuladong.github.io/article/fname.html?fname=随机权重)
- [归并排序详解及应用](https://labuladong.github.io/article/fname.html?fname=归并排序)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
</details><hr>
@ -237,7 +237,7 @@ class NumMatrix {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -127,11 +127,15 @@ ListNode deleteDuplicates(ListNode head) {
![](https://labuladong.github.io/pictures/数组去重/2.gif)
> note这里可能有读者会问链表中那些重复的元素并没有被删掉就让这些节点在链表上挂着合适吗
>
> 这就要探讨不同语言的特性了,像 Java/Python 这类带有垃圾回收的语言,可以帮我们自动找到并回收这些「悬空」的链表节点的内存,而像 C++ 这类语言没有自动垃圾回收的机制,确实需要我们编写代码时手动释放掉这些节点的内存。
>
> 不过话说回来,就算法思维的培养来说,我们只需要知道这种快慢指针技巧即可。
::: note
这里可能有读者会问,链表中那些重复的元素并没有被删掉,就让这些节点在链表上挂着,合适吗?
这就要探讨不同语言的特性了,像 Java/Python 这类带有垃圾回收的语言,可以帮我们自动找到并回收这些「悬空」的链表节点的内存,而像 C++ 这类语言没有自动垃圾回收的机制,确实需要我们编写代码时手动释放掉这些节点的内存。
不过话说回来,就算法思维的培养来说,我们只需要知道这种快慢指针技巧即可。
:::
**除了让你在有序数组/链表中去重,题目还可能让你对数组中的某些元素进行「原地删除」**。
@ -398,7 +402,7 @@ String longestPalindrome(String s) {
你应该能发现最长回文子串使用的左右指针和之前题目的左右指针有一些不同:之前的左右指针都是从两端向中间相向而行,而回文子串问题则是让左右指针从中心向两端扩展。不过这种情况也就回文串这类问题会遇到,所以我也把它归为左右指针了。
到这里,数组相关的双指针技巧就全部讲完了,这些技巧的更多扩展延伸见 [更多双指针经典高频题](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_62a1dd68e4b09dda1273a5f9/1)。
到这里,数组相关的双指针技巧就全部讲完了,这些技巧的更多扩展延伸见 [更多双指针经典高频题](https://labuladong.online/algo/ds-class/shu-zu-lia-39fd9/qiang-hua--0b827)。
@ -409,11 +413,12 @@ String longestPalindrome(String s) {
- [【强化练习】双指针更多经典习题](https://labuladong.github.io/article/fname.html?fname=双指针题目)
- [一个方法团灭 nSum 问题](https://labuladong.github.io/article/fname.html?fname=nSum)
- [一道数组去重的算法题把我整不会了](https://labuladong.github.io/article/fname.html?fname=单调栈去重)
- [二维数组的花式遍历技巧](https://labuladong.github.io/article/fname.html?fname=花式遍历)
- [分治算法详解:运算优先级](https://labuladong.github.io/article/fname.html?fname=分治算法)
- [动态规划之子序列问题解题模板](https://labuladong.github.io/article/fname.html?fname=子序列问题模板)
- [如何判断回文链表](https://labuladong.github.io/article/fname.html?fname=判断回文链表)
- [我写了首诗,把滑动窗口算法变成了默写题](https://labuladong.github.io/article/fname.html?fname=滑动窗口技巧进阶)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [扫描线技巧:安排会议室](https://labuladong.github.io/article/fname.html?fname=安排会议室)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
- [用算法打败算法](https://labuladong.github.io/article/fname.html?fname=PDF中的算法)
@ -437,6 +442,7 @@ String longestPalindrome(String s) {
| [1. Two Sum](https://leetcode.com/problems/two-sum/?show=1) | [1. 两数之和](https://leetcode.cn/problems/two-sum/?show=1) |
| [125. Valid Palindrome](https://leetcode.com/problems/valid-palindrome/?show=1) | [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/?show=1) |
| [131. Palindrome Partitioning](https://leetcode.com/problems/palindrome-partitioning/?show=1) | [131. 分割回文串](https://leetcode.cn/problems/palindrome-partitioning/?show=1) |
| [267. Palindrome Permutation II](https://leetcode.com/problems/palindrome-permutation-ii/?show=1)🔒 | [267. 回文排列 II](https://leetcode.cn/problems/palindrome-permutation-ii/?show=1)🔒 |
| [281. Zigzag Iterator](https://leetcode.com/problems/zigzag-iterator/?show=1)🔒 | [281. 锯齿迭代器](https://leetcode.cn/problems/zigzag-iterator/?show=1)🔒 |
| [42. Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/?show=1) | [42. 接雨水](https://leetcode.cn/problems/trapping-rain-water/?show=1) |
| [658. Find K Closest Elements](https://leetcode.com/problems/find-k-closest-elements/?show=1) | [658. 找到 K 个最接近的元素](https://leetcode.cn/problems/find-k-closest-elements/?show=1) |
@ -454,7 +460,7 @@ String longestPalindrome(String s) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -71,7 +71,13 @@ def backtrack(路径, 选择列表):
力扣第 46 题「全排列」就是给你输入一个数组 `nums`,让你返回这些数字的全排列。
> info**我们这次讨论的全排列问题不包含重复的数字,包含重复数字的扩展场景我在后文 [回溯算法秒杀排列组合子集的九种题型](https://labuladong.github.io/article/fname.html?fname=子集排列组合) 中讲解**。
::: info 提示
**我们这次讨论的全排列问题不包含重复的数字,包含重复数字的扩展场景我在后文 [回溯算法秒杀排列组合子集的九种题型](https://labuladong.github.io/article/fname.html?fname=子集排列组合) 中讲解**。
另外,有些读者之前看过的全排列算法代码可能是那种 `swap` 交换元素的写法,和我在本文介绍的代码不同。这是回溯算法两种穷举思路,我会在后文 [球盒模型:回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分) 讲明白。现在还不适合直接跟你讲那个解法,你照着我的思路学习即可。
:::
我们在高中的时候就做过排列组合的数学题,我们也知道 `n` 个不重复的数,全排列共有 `n!` 个。那么我们当时是怎么穷举全排列的呢?
@ -112,9 +118,13 @@ void traverse(TreeNode root) {
}
```
> info细心的读者肯定会疑问多叉树 DFS 遍历框架的前序位置和后序位置应该在 for 循环外面,并不应该是在 for 循环里面呀?为什么在回溯算法中跑到 for 循环里面了?
>
> 是的DFS 算法的前序和后序位置应该在 for 循环外面,不过回溯算法和 DFS 算法略有不同,后文 [图论算法基础](https://labuladong.github.io/article/fname.html?fname=图) 会详细对比,这里可以暂且忽略这个问题。
::: info
细心的读者肯定会疑问:多叉树 DFS 遍历框架的前序位置和后序位置应该在 for 循环外面,并不应该是在 for 循环里面呀?为什么在回溯算法中跑到 for 循环里面了?
是的DFS 算法的前序和后序位置应该在 for 循环外面,不过回溯算法和 DFS 算法略有不同,后文 [图论算法基础](https://labuladong.github.io/article/fname.html?fname=图) 会详细对比,这里可以暂且忽略这个问题。
:::
而所谓的前序遍历和后序遍历,他们只是两个很有用的时间点,我给你画张图你就明白了:
@ -209,7 +219,11 @@ class Solution {
vector<vector<string>> solveNQueens(int n);
```
> tip皇后可以攻击同一行、同一列、左上左下右上右下四个方向的任意单位。
::: tip
皇后可以攻击同一行、同一列、左上左下右上右下四个方向的任意单位。
:::
比如如果给你输入 `N = 4`,那么你就要在 4x4 的棋盘上放置 4 个皇后,返回以下结果(用 `.` 代表空棋盘,`Q` 代表皇后):
@ -296,9 +310,13 @@ bool isValid(vector<string>& board, int row, int col) {
}
```
> info肯定有读者问按照 N 皇后问题的描述,我们为什么不检查左下角,右下角和下方的格子,只检查了左上角,右上角和上方的格子呢?
>
> 因为皇后是一行一行从上往下放的,所以左下方,右下方和正下方不用检查(还没放皇后);因为一行只会放一个皇后,所以每行不用检查。也就是最后只用检查上面,左上,右上三个方向。
::: info
肯定有读者问,按照 N 皇后问题的描述,我们为什么不检查左下角,右下角和下方的格子,只检查了左上角,右上角和上方的格子呢?
因为皇后是一行一行从上往下放的,所以左下方,右下方和正下方不用检查(还没放皇后);因为一行只会放一个皇后,所以每行不用检查。也就是最后只用检查上面,左上,右上三个方向。
:::
函数 `backtrack` 依然像个在决策树上游走的指针,通过 `row``col` 就可以表示函数遍历到的位置,通过 `isValid` 函数可以将不符合条件的情况剪枝:
@ -407,15 +425,15 @@ def backtrack(...):
- [分治算法详解:运算优先级](https://labuladong.github.io/article/fname.html?fname=分治算法)
- [前缀树算法模板秒杀五道算法题](https://labuladong.github.io/article/fname.html?fname=trie)
- [动态规划和回溯算法的思维转换](https://labuladong.github.io/article/fname.html?fname=单词拼接)
- [可视化代码编辑器使用指南](https://labuladong.github.io/article/fname.html?fname=可视化编辑器-wx)
- [回溯算法最佳实践:括号生成](https://labuladong.github.io/article/fname.html?fname=合法括号生成)
- [回溯算法最佳实践:解数独](https://labuladong.github.io/article/fname.html?fname=sudoku)
- [回溯算法秒杀所有排列/组合/子集问题](https://labuladong.github.io/article/fname.html?fname=子集排列组合)
- [回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分)
- [图论基础及遍历算法](https://labuladong.github.io/article/fname.html?fname=图)
- [学习算法和刷题的框架思维](https://labuladong.github.io/article/fname.html?fname=学习数据结构和算法的高效方法)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [环检测及拓扑排序算法](https://labuladong.github.io/article/fname.html?fname=拓扑排序)
- [球盒模型:回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分)
- [目标和:背包问题的变体](https://labuladong.github.io/article/fname.html?fname=targetSum)
- [算法学习和心流体验](https://labuladong.github.io/article/fname.html?fname=心流)
- [算法笔试「骗分」套路](https://labuladong.github.io/article/fname.html?fname=刷题技巧)
@ -434,6 +452,7 @@ def backtrack(...):
| LeetCode | 力扣 |
| :----: | :----: |
| [111. Minimum Depth of Binary Tree](https://leetcode.com/problems/minimum-depth-of-binary-tree/?show=1) | [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/?show=1) |
| [112. Path Sum](https://leetcode.com/problems/path-sum/?show=1) | [112. 路径总和](https://leetcode.cn/problems/path-sum/?show=1) |
| [113. Path Sum II](https://leetcode.com/problems/path-sum-ii/?show=1) | [113. 路径总和 II](https://leetcode.cn/problems/path-sum-ii/?show=1) |
| [131. Palindrome Partitioning](https://leetcode.com/problems/palindrome-partitioning/?show=1) | [131. 分割回文串](https://leetcode.cn/problems/palindrome-partitioning/?show=1) |
@ -463,7 +482,7 @@ def backtrack(...):
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -101,7 +101,7 @@ string multiply(string num1, string num2) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -242,7 +242,11 @@ void traverse(TreeNode root, int k) {
对于一个理解二叉树的人来说,刷一道二叉树的题目花不了多长时间。那么如果你对刷题无从下手或者有畏惧心理,不妨从二叉树下手,前 10 道也许有点难受;结合框架再做 20 道,也许你就有点自己的理解了;刷完整个专题,再去做什么回溯动规分治专题,**你就会发现只要涉及递归的问题,都是树的问题**。
> tip[刷题插件](https://mp.weixin.qq.com/s/OE1zPVPj0V2o82N4HtLQbw) 集成了手把手刷二叉树功能,按照公式和套路讲解了 150 道二叉树题目,可手把手带你刷完二叉树分类的题目,迅速掌握递归思维。
::: tip
[刷题插件](https://mp.weixin.qq.com/s/OE1zPVPj0V2o82N4HtLQbw) 集成了手把手刷二叉树功能,按照公式和套路讲解了 150 道二叉树题目,可手把手带你刷完二叉树分类的题目,迅速掌握递归思维。
:::
再举例吧,说几道我们之前文章写过的问题。
@ -344,7 +348,7 @@ N 叉树的遍历框架,找出来了吧?你说,树这种结构重不重要
学完基本算法之后,建议从「二叉树」系列问题开始刷,结合框架思维,把树结构理解到位,然后再去看回溯、动规、分治等算法专题,对思路的理解就会更加深刻。
> info最后打个广告我亲自制作了一门 [数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO),以视频课为主,手把手带你实现常用的数据结构及相关算法,旨在帮助算法基础较为薄弱的读者深入理解常用数据结构的底层原理,在算法学习中少走弯路。
> info最后打个广告我亲自制作了一门 [数据结构精品课](https://labuladong.online/algo/ds-class/),以视频课为主,手把手带你实现常用的数据结构及相关算法,旨在帮助算法基础较为薄弱的读者深入理解常用数据结构的底层原理,在算法学习中少走弯路。
@ -362,6 +366,7 @@ N 叉树的遍历框架,找出来了吧?你说,树这种结构重不重要
- [二叉树的递归转迭代的代码框架](https://labuladong.github.io/article/fname.html?fname=迭代遍历二叉树)
- [二叉树递归专题课](https://labuladong.github.io/article/fname.html?fname=tree课程简介)
- [前缀树算法模板秒杀五道算法题](https://labuladong.github.io/article/fname.html?fname=trie)
- [可视化代码编辑器使用指南](https://labuladong.github.io/article/fname.html?fname=可视化编辑器-wx)
- [回溯算法秒杀所有排列/组合/子集问题](https://labuladong.github.io/article/fname.html?fname=子集排列组合)
- [回溯算法解题套路框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版)
- [图论基础及遍历算法](https://labuladong.github.io/article/fname.html?fname=图)
@ -369,11 +374,10 @@ N 叉树的遍历框架,找出来了吧?你说,树这种结构重不重要
- [如何判断回文链表](https://labuladong.github.io/article/fname.html?fname=判断回文链表)
- [存储系统设计之 LSM 树原理](https://labuladong.github.io/article/fname.html?fname=LSM树)
- [归并排序详解及应用](https://labuladong.github.io/article/fname.html?fname=归并排序)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
- [环检测及拓扑排序算法](https://labuladong.github.io/article/fname.html?fname=拓扑排序)
- [目标和:背包问题的变体](https://labuladong.github.io/article/fname.html?fname=targetSum)
- [算法可视化功能简介(必读)](https://labuladong.github.io/article/fname.html?fname=可视化简介)
- [算法学习和心流体验](https://labuladong.github.io/article/fname.html?fname=心流)
- [算法时空复杂度分析实用指南](https://labuladong.github.io/article/fname.html?fname=时间复杂度)
- [题目不让我干什么,我偏要干什么](https://labuladong.github.io/article/fname.html?fname=nestInteger)
@ -402,7 +406,7 @@ N 叉树的遍历框架,找出来了吧?你说,树这种结构重不重要
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -194,7 +194,11 @@ int[] corpFlightBookings(int[][] bookings, int n)
给你输入一个长度为 `n` 的数组 `nums`,其中所有元素都是 0。再给你输入一个 `bookings`,里面是若干三元组 `(i, j, k)`,每个三元组的含义就是要求你给 `nums` 数组的闭区间 `[i-1,j-1]` 中所有元素都加上 `k`。请你返回最后的 `nums` 数组是多少?
> note因为题目说的 `n` 是从 1 开始计数的,而数组索引从 0 开始,所以对于输入的三元组 `(i, j, k)`,数组区间应该对应 `[i-1,j-1]`
::: note
因为题目说的 `n` 是从 1 开始计数的,而数组索引从 0 开始,所以对于输入的三元组 `(i, j, k)`,数组区间应该对应 `[i-1,j-1]`
:::
这么一看,不就是一道标准的差分数组题嘛?我们可以直接复用刚才写的类:
@ -286,7 +290,7 @@ boolean carPooling(int[][] trips, int capacity) {
最后,差分数组和前缀和数组都是比较常见且巧妙的算法技巧,分别适用不同的场景,而且是会者不难,难者不会。所以,关于差分数组的使用,你学会了吗?
更多经典的数组/链表技巧习题见 [数组链表解题技巧精讲](https://appktavsiei5995.pc.xiaoe-tech.com/detail/p_62655effe4b0812e1790ecd7/6)。
更多经典的数组/链表技巧习题见 [数组链表解题技巧精讲](https://labuladong.online/algo/ds-class/shu-zu-lia-39fd9/qiang-hua--0b827/)。
@ -295,7 +299,7 @@ boolean carPooling(int[][] trips, int capacity) {
<summary><strong>引用本文的文章</strong></summary>
- [二维数组的花式遍历技巧](https://labuladong.github.io/article/fname.html?fname=花式遍历)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [扫描线技巧:安排会议室](https://labuladong.github.io/article/fname.html?fname=安排会议室)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
@ -307,6 +311,6 @@ boolean carPooling(int[][] trips, int capacity) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -128,7 +128,11 @@ while (true) {
// 输出1,2,3,4,1,2,3,4,1,2,3,4...
```
> note注意这个技巧只适用于数组长度是 2 的幂次方的情况,比如 2、4、8、16、32 以此类推。至于如何将数组长度扩展为 2 的幂次方,这也是有比较巧妙的位运算算法的,可以参考 https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
::: note
注意这个技巧只适用于数组长度是 2 的幂次方的情况,比如 2、4、8、16、32 以此类推。至于如何将数组长度扩展为 2 的幂次方,这也是有比较巧妙的位运算算法的,可以参考 https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
:::
简单说,`& (arr.length - 1)` 这个位运算能够替代 `% arr.length` 的模运算,性能会更好一些。
@ -308,7 +312,7 @@ int missingNumber(int[] nums) {
<details class="hint-container details">
<summary><strong>引用本文的文章</strong></summary>
- [丑数系列算法详解](https://labuladong.github.io/article/fname.html?fname=丑数)
- [一文秒杀所有丑数系列问题](https://labuladong.github.io/article/fname.html?fname=丑数)
- [如何同时寻找缺失和重复的元素](https://labuladong.github.io/article/fname.html?fname=缺失和重复的元素)
</details><hr>
@ -334,7 +338,7 @@ int missingNumber(int[] nums) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -214,7 +214,7 @@ for (int feq : count)
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -46,14 +46,14 @@
```cpp
int left = 0, right = 0;
while (left < right && right < s.size()) {
while (left < right && right < nums.size()) {
// 增大窗口
window.add(s[right]);
window.add(nums[right]);
right++;
while (window needs shrink) {
// 缩小窗口
window.remove(s[left]);
window.remove(nums[left]);
left++;
}
}
@ -102,7 +102,9 @@ void slidingWindow(string s) {
}
```
**其中两处 `...` 表示的更新窗口数据的地方,到时候你直接往里面填就行了**。
因为下面讲解的题目大都是字符串相关的,所以上面这个框架就以字符串为例了。但实际上字符串就是数组,所以这个框架完全可以套用在数组类型的题目上,你根据具体题目自行变通即可。
**框架中两处 `...` 表示的更新窗口数据的地方,在具体的题目中,你需要做的就是往这里面填代码逻辑**。
而且,这两个 `...` 处的操作分别是扩大和缩小窗口的更新操作,等会你会发现它们操作是完全对称的。
@ -149,7 +151,11 @@ for (int i = 0; i < s.size(); i++)
1、我们在字符串 `S` 中使用双指针中的左右指针技巧,初始化 `left = right = 0`,把索引**左闭右开**区间 `[left, right)` 称为一个「窗口」。
> tip理论上你可以设计两端都开或者两端都闭的区间但设计为左闭右开区间是最方便处理的。因为这样初始化 `left = right = 0` 时区间 `[0, 0)` 中没有元素,但只要让 `right` 向右移动(扩大)一位,区间 `[0, 1)` 就包含一个元素 `0` 了。如果你设置为两端都开的区间,那么让 `right` 向右移动一位后开区间 `(0, 1)` 仍然没有元素;如果你设置为两端都闭的区间,那么初始区间 `[0, 0]` 就包含了一个元素。这两种情况都会给边界处理带来不必要的麻烦。
::: tip
理论上你可以设计两端都开或者两端都闭的区间,但设计为左闭右开区间是最方便处理的。因为这样初始化 `left = right = 0` 时区间 `[0, 0)` 中没有元素,但只要让 `right` 向右移动(扩大)一位,区间 `[0, 1)` 就包含一个元素 `0` 了。如果你设置为两端都开的区间,那么让 `right` 向右移动一位后开区间 `(0, 1)` 仍然没有元素;如果你设置为两端都闭的区间,那么初始区间 `[0, 0]` 就包含了一个元素。这两种情况都会给边界处理带来不必要的麻烦。
:::
2、我们先不断地增加 `right` 指针扩大窗口 `[left, right)`,直到窗口中的字符串符合要求(包含了 `T` 中的所有字符)。
@ -261,7 +267,11 @@ string minWindow(string s, string t) {
<visual slug='minimum-window-substring' />
> warning使用 Java 的读者要尤其警惕语言特性的陷阱。Java 的 IntegerString 等类型判定相等应该用 `equals` 方法而不能直接用等号 `==`,这是 Java 包装类的一个隐晦细节。所以在缩小窗口更新数据的时候,不能直接改写为 `window.get(d) == need.get(d)`,而要用 `window.get(d).equals(need.get(d))`,之后的题目代码同理。
::: warning
使用 Java 的读者要尤其警惕语言特性的陷阱。Java 的 IntegerString 等类型判定相等应该用 `equals` 方法而不能直接用等号 `==`,这是 Java 包装类的一个隐晦细节。所以在缩小窗口更新数据的时候,不能直接改写为 `window.get(d) == need.get(d)`,而要用 `window.get(d).equals(need.get(d))`,之后的题目代码同理。
:::
需要注意的是,当我们发现某个字符在 `window` 的数量满足了 `need` 的需要,就要更新 `valid`,表示有一个字符已经满足要求。而且,你能发现,两次对窗口内数据的更新操作是完全对称的。
@ -334,7 +344,11 @@ bool checkInclusion(string t, string s) {
至于如何处理窗口的扩大和缩小,和最小覆盖子串完全相同。
> note由于这道题中 `[left, right)` 其实维护的是一个**定长**的窗口,窗口大小为 `t.size()`。因为定长窗口每次向前滑动时只会移出一个字符,所以可以把内层的 while 改成 if效果是一样的。
::: note
由于这道题中 `[left, right)` 其实维护的是一个**定长**的窗口,窗口大小为 `t.size()`。因为定长窗口每次向前滑动时只会移出一个字符,所以可以把内层的 while 改成 if效果是一样的。
:::
### 三、找所有字母异位词
@ -439,7 +453,7 @@ int lengthOfLongestSubstring(string s) {
3、什么时候应该更新答案
我在 [滑动窗口经典习题](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_62b57985e4b00a4f371dd705/1) 中使用这套思维模式列举了更多经典的习题,旨在强化你对算法的理解和记忆,以后就再也不怕子串、子数组问题了。
我在 [滑动窗口经典习题](https://labuladong.online/algo/ds-class/shu-zu-lia-39fd9/qiang-hua--0bb36) 中使用这套思维模式列举了更多经典的习题,旨在强化你对算法的理解和记忆,以后就再也不怕子串、子数组问题了。
@ -454,7 +468,7 @@ int lengthOfLongestSubstring(string s) {
- [单调队列结构解决滑动窗口问题](https://labuladong.github.io/article/fname.html?fname=单调队列)
- [双指针技巧秒杀七道数组题目](https://labuladong.github.io/article/fname.html?fname=双指针技巧)
- [归并排序详解及应用](https://labuladong.github.io/article/fname.html?fname=归并排序)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [数据结构精品课](https://labuladong.github.io/article/fname.html?fname=ds课程简介)
- [本站简介](https://labuladong.github.io/article/fname.html?fname=home)
- [滑动窗口算法延伸Rabin Karp 字符匹配算法](https://labuladong.github.io/article/fname.html?fname=rabinkarp)
@ -479,14 +493,17 @@ int lengthOfLongestSubstring(string s) {
| [209. Minimum Size Subarray Sum](https://leetcode.com/problems/minimum-size-subarray-sum/?show=1) | [209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/?show=1) |
| [219. Contains Duplicate II](https://leetcode.com/problems/contains-duplicate-ii/?show=1) | [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/?show=1) |
| [220. Contains Duplicate III](https://leetcode.com/problems/contains-duplicate-iii/?show=1) | [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/?show=1) |
| [340. Longest Substring with At Most K Distinct Characters](https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/?show=1)🔒 | [340. 至多包含 K 个不同字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-most-k-distinct-characters/?show=1)🔒 |
| [395. Longest Substring with At Least K Repeating Characters](https://leetcode.com/problems/longest-substring-with-at-least-k-repeating-characters/?show=1) | [395. 至少有 K 个重复字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/?show=1) |
| [424. Longest Repeating Character Replacement](https://leetcode.com/problems/longest-repeating-character-replacement/?show=1) | [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/?show=1) |
| [560. Subarray Sum Equals K](https://leetcode.com/problems/subarray-sum-equals-k/?show=1) | [560. 和为 K 的子数组](https://leetcode.cn/problems/subarray-sum-equals-k/?show=1) |
| [713. Subarray Product Less Than K](https://leetcode.com/problems/subarray-product-less-than-k/?show=1) | [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/?show=1) |
| [862. Shortest Subarray with Sum at Least K](https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/?show=1) | [862. 和至少为 K 的最短子数组](https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/?show=1) |
| - | [剑指 Offer 48. 最长不含重复字符的子字符串](https://leetcode.cn/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/?show=1) |
| - | [剑指 Offer 57 - II. 和为s的连续正数序列](https://leetcode.cn/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/?show=1) |
| - | [剑指 Offer II 008. 和大于等于 target 的最短子数组](https://leetcode.cn/problems/2VG8Kg/?show=1) |
| - | [剑指 Offer II 009. 乘积小于 K 的子数组](https://leetcode.cn/problems/ZVAVXX/?show=1) |
| - | [剑指 Offer II 010. 和为 k 的子数组](https://leetcode.cn/problems/QTMn0o/?show=1) |
| - | [剑指 Offer II 014. 字符串中的变位词](https://leetcode.cn/problems/MPnaiL/?show=1) |
| - | [剑指 Offer II 015. 字符串中的所有变位词](https://leetcode.cn/problems/VabMRr/?show=1) |
| - | [剑指 Offer II 016. 不含重复字符的最长子字符串](https://leetcode.cn/problems/wtcaE1/?show=1) |
@ -500,6 +517,6 @@ int lengthOfLongestSubstring(string s) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -154,7 +154,7 @@ class Solution {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -21,6 +21,7 @@
| [48. Rotate Image](https://leetcode.com/problems/rotate-image/) | [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 🟠
| [54. Spiral Matrix](https://leetcode.com/problems/spiral-matrix/) | [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/) | 🟠
| [59. Spiral Matrix II](https://leetcode.com/problems/spiral-matrix-ii/) | [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 🟠
| [61. Rotate List](https://leetcode.com/problems/rotate-list/) | [61. 旋转链表](https://leetcode.cn/problems/rotate-list/) | 🟠
| - | [剑指 Offer 29. 顺时针打印矩阵](https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/) | 🟢
| - | [剑指 Offer 58 - I. 翻转单词顺序](https://leetcode.cn/problems/fan-zhuan-dan-ci-shun-xu-lcof/) | 🟢
@ -81,7 +82,21 @@ s = "labuladong world hello"
这样,就实现了原地反转所有单词顺序的目的。力扣第 151 题「颠倒字符串中的单词」就是类似的问题,你可以顺便去做一下。
我讲这道题的目的是什么呢?
上面这个小技巧还可以再包装包装,比如说你可以去看一下力扣第 61 题「旋转链表」:给你一个单链表,让你旋转链表,将链表每个节点向右移动 `k` 个位置。
比如说输入单链表 `1 -> 2 -> 3 -> 4 -> 5``k = 2`,你的算法需要返回 `4 -> 5 -> 1 -> 2 -> 3`,即将链表每个节点向右移动 2 个位置。
这个题,不要真傻乎乎地一个一个去移动链表节点,我给你翻译翻译,其实就是将链表的后 `k` 个节点移动到链表的头部嘛,反应过来没有?
还没反应过来,那再提示一下,把后 `k` 个节点移动到链表的头部,其实就是让你把链表的前 `n - k` 个节点和后 `k` 个节点原地翻转,对不对?
这样,是不是和前面说的原地翻转字符串中的单词是一样的道理呢?你只需要先将整个链表反转,然后将前 `n - k` 个节点和后 `k` 个节点分别反转,就得到了结果。
当然,这个题有一些小细节,比如这个 `k` 可能大于链表的长度,那么你需要先求出链表的长度 `n`,然后取模 `k = k % n`,这样 `k` 就不会大于链表的长度,且最后得到的结果也是正确的。
有时间的话自己去做一下这个题吧,比较简单,我这里就不贴代码了。
我讲上面这两道题的目的是什么呢?
**旨在说明,有时候咱们拍脑袋的常规思维,在计算机看来可能并不是最优雅的;但是计算机觉得最优雅的思维,对咱们来说却不那么直观**。也许这就是算法的魅力所在吧。
@ -139,7 +154,7 @@ void reverse(int[] arr) {
肯定有读者会问,如果没有做过这道题,怎么可能想到这种思路呢?
仔细想想,旋转二维矩阵的难点在于将「行」变成「列」,将「列」变成「行」,而只有按照对角线的对称操作是可以轻松完成这一点的,对称操作之后就很容易发现规律了。
是的,没做过这类题目,确实不好想到这种思路,但你这不是做过了么?所谓会者不难难者不会,你这辈子估计都忘不掉了。
**既然说道这里,我们可以发散一下,如何将矩阵逆时针旋转 90 度呢**
@ -313,10 +328,10 @@ int[][] generateMatrix(int n) {
至此,两道螺旋矩阵的题目也解决了。
以上就是遍历二维数组的一些技巧,其他数组技巧可参见之前的文章 [前缀和数组](https://labuladong.github.io/article/fname.html?fname=前缀和技巧)[差分数组](https://labuladong.github.io/article/fname.html?fname=差分技巧)[数组双指针算法集合](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzAxODQxMDM0Mw==&action=getalbum&album_id=2120601117519675393),链表相关技巧可参见 [单链表六大算法技巧汇总](https://labuladong.github.io/article/fname.html?fname=链表技巧)。
以上就是遍历二维数组的一些技巧,其他数组技巧可参见之前的文章 [前缀和数组](https://labuladong.github.io/article/fname.html?fname=前缀和技巧)[差分数组](https://labuladong.github.io/article/fname.html?fname=差分技巧)[数组双指针算法集合](https://labuladong.github.io/article/fname.html?fname=双指针技巧),链表相关技巧可参见 [单链表六大算法技巧汇总](https://labuladong.github.io/article/fname.html?fname=链表技巧)。
> info最后打个广告我亲自制作了一门 [数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO),以视频课为主,手把手带你实现常用的数据结构及相关算法,旨在帮助算法基础较为薄弱的读者深入理解常用数据结构的底层原理,在算法学习中少走弯路。
> info最后打个广告我亲自制作了一门 [数据结构精品课](https://labuladong.online/algo/ds-class/),以视频课为主,手把手带你实现常用的数据结构及相关算法,旨在帮助算法基础较为薄弱的读者深入理解常用数据结构的底层原理,在算法学习中少走弯路。
@ -343,6 +358,6 @@ int[][] generateMatrix(int n) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -17,7 +17,11 @@
| LeetCode | 力扣 | 难度 |
| :----: | :----: | :----: |
| [46. Permutations](https://leetcode.com/problems/permutations/) | [46. 全排列](https://leetcode.cn/problems/permutations/) | 🟠
| [698. Partition to K Equal Sum Subsets](https://leetcode.com/problems/partition-to-k-equal-sum-subsets/) | [698. 划分为k个相等的子集](https://leetcode.cn/problems/partition-to-k-equal-sum-subsets/) | 🟠
| [78. Subsets](https://leetcode.com/problems/subsets/) | [78. 子集](https://leetcode.cn/problems/subsets/) | 🟠
| - | [剑指 Offer II 079. 所有子集](https://leetcode.cn/problems/TVdhkn/) | 🟠
| - | [剑指 Offer II 083. 没有重复元素集合的全排列](https://leetcode.cn/problems/VvJkup/) | 🟠
**-----------**
@ -29,7 +33,11 @@
本文就来看一道非常经典的回溯算法问题,力扣第 698 题「划分为k个相等的子集」。这道题可以帮你更深刻理解回溯算法的思维得心应手地写出回溯函数。
> note阅读本文之前建议先阅读并理解 [回溯算法秒杀排列/组合/子集问题](https://labuladong.github.io/article/fname.html?fname=子集排列组合)。因为本文这道题所求的就是子集的问题,有一些模式和套路和原始的子集问题是非常类似的,可以结合着理解。
::: note
阅读本文之前,建议先阅读并理解 [回溯算法秒杀排列/组合/子集问题](https://labuladong.github.io/article/fname.html?fname=子集排列组合)。因为本文这道题所求的就是子集的问题,有一些模式和套路和原始的子集问题是非常类似的,可以结合着理解。
:::
题目非常简单:
@ -44,15 +52,23 @@ boolean canPartitionKSubsets(int[] nums, int k);
我们之前 [背包问题之子集划分](https://labuladong.github.io/article/fname.html?fname=背包子集) 写过一次子集划分问题,不过那道题只需要我们把集合划分成两个相等的集合,可以转化成背包问题用动态规划技巧解决。
> info思考题为什么划分成两个相等的子集可以转化成背包问题用动态规划思路解决而划分成 `k` 个相等的子集就不可以转化成背包问题,只能用回溯算法暴力穷举?请先尝试自己思考,我会在文末给出答案。
但是如果划分成多个相等的集合,解法一般只能通过暴力穷举,时间复杂度爆表,是练习回溯算法和递归思维的好机会。
### 一、思路分析
::: info 思考题
为什么划分成两个相等的子集可以转化成背包问题用动态规划思路解决,而划分成 `k` 个相等的子集就不可以转化成背包问题,只能用回溯算法暴力穷举?请先尝试自己思考,我会在文末给出答案。
:::
### 暴力穷举思维方法:球盒模型
**一切回溯算法,都从球盒模型开始,没有例外。一切回溯算法,都从球盒模型开始,没有例外。一切回溯算法,都从球盒模型开始,没有例外**。
你懂了这个,就可以随心所欲运用回溯算法。下面的内容,仔细看,认真想。
首先,我们回顾一下以前学过的排列组合知识:
1、`P(n, k)`(也有很多书写成 `A(n, k)`)表示从 `n` 个不同元素中拿出 `k` 个元素的排列Permutation/Arrangement`C(n, k)` 表示从 `n` 个不同元素中拿出 `k` 个元素的组合Combination总数。
1、`P(n, k)`(也有很多书写成 `A(n, k)`)表示从 `n` 个不同元素中拿出 `k` 个元素的排列Permutation/Arrangement总数`C(n, k)` 表示从 `n` 个不同元素中拿出 `k` 个元素的组合Combination总数。
2、「排列」和「组合」的主要区别在于是否考虑顺序的差异。
@ -92,6 +108,225 @@ boolean canPartitionKSubsets(int[] nums, int k);
至于如何解递归式,涉及数学的内容比较多,这里就不做深入探讨了,有兴趣的读者可以自行学习组合数学相关知识。
### 用球盒模型重新理解排列组合
好,上面从数学的角度介绍了全排列穷举的两种视角,现在回归到代码上,我要考你,支棱起来哦,听题:
::: important 小试牛刀
前文 [回溯算法核心框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版) 和 [回溯算法秒杀排列/组合/子集的九种变体](https://labuladong.github.io/article/fname.html?fname=子集排列组合) 都给出过全排列的代码。
就以最基本的元素无重不可复选的全排列为例,我直接把代码 copy 过来:
```java
class Solution {
List<List<Integer>> res = new LinkedList<>();
// 记录回溯算法的递归路径
LinkedList<Integer> track = new LinkedList<>();
// track 中的元素会被标记为 true
boolean[] used;
/* 主函数,输入一组不重复的数字,返回它们的全排列 */
public List<List<Integer>> permute(int[] nums) {
used = new boolean[nums.length];
backtrack(nums);
return res;
}
// 回溯算法核心函数
void backtrack(int[] nums) {
// base case到达叶子节点
if (track.size() == nums.length) {
// 收集叶子节点上的值
res.add(new LinkedList(track));
return;
}
// 回溯算法标准框架
for (int i = 0; i < nums.length; i++) {
// 已经存在 track 中的元素,不能重复选择
if (used[i]) {
continue;
}
// 做选择
used[i] = true;
track.addLast(nums[i]);
// 进入下一层回溯树
backtrack(nums);
// 取消选择
track.removeLast();
used[i] = false;
}
}
}
```
请问,这个解法是以什么视角进行穷举的?是以球的视角还是盒的视角?给你三分钟思考,请回答!
:::
::: details 点击查看我的答案
这个代码是以盒的视角进行穷举的,即站在每个位置的角度来选择球。
:::
为什么是这个答案呢?假设 `nums` 里面有 `n` 个数字,那么全排列问题相当于把 `n` 个球放到包含 `n` 个位置的盒子里,要求盒子必须装满,问你有几种不同的装法。
以盒的视角理解,盒子的第一个位置可以接收 `n` 个球的任意一个,有 `n` 种选择,第二个位置可以接收 `n - 1` 个球的任意一个,有 `n - 1` 种选择,第三个位置有 `n - 2` 种选择,以此类推。
我直接用 [算法可视化面板](https://labuladong.github.io/article/fname.html?fname=可视化简介) 把递归树画出来,你一眼就可以看懂了。请你把进度条拖到最后让整棵回溯树显示出来,然后把鼠标在每一层节点上横向移动,观察递归树节点和树枝上的值:
<visual slug='box-view-of-permute' open step=-1 title="球盒模型:以盒的视角求解全排列" />
::: tip 拓展延伸
那么很自然的一个问题,能不能写出一个以球的视角理解的全排列问题的解法?当然可以,睁大眼睛看好哦。
:::
很多读者看了我讲的回溯算法框架,就跑来跟我说啊,他看的那个全排列算法是通过 `swap` 操作来计算的,不需要 `used` 数组的额外空间,比我讲解的回溯算法框架效率高,怎么怎么的。
之所以我在前文 [回溯算法核心框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版) 和 [回溯算法秒杀排列/组合/子集的九种变体](https://labuladong.github.io/article/fname.html?fname=子集排列组合) 都不用那个解法,是因为我要保证框架的一致性。
**到这里,我可以教给你那个 `swap` 元素计算全排列的解法了,因为那个解法和用 `used` 数组的解法就对应着「球」和「盒」两种不同的穷举视角。两者同出,异名同谓,玄之又玄,回溯的心法尽在其中**。
我只需要稍改之前的全排列代码,并修改一下可视化注释,就让你立刻看明白。请你把鼠标移动到每个节点上,在每一层横向移动,查看每一层的节点的值以及树枝上显示的选择:
<visual slug='ball-view-of-permute' open step=-1 title="球盒模型:以球的视角求解全排列(未优化)" />
当然,上述代码还有优化空间,比如说你发现那个 `used` 数组不是必要的,我们可以只通过那个 `count` 参数,保证 `[0..count]` 的球都是已经放进盒子的,`[count..]`后面的球是需要穷举位置的。这样就可以进一步优化空间复杂度:
<visual slug='ball-view-of-permute-improved' open step=-1 title="球盒模型:以球的视角求解全排列(优化)" />
好了,这就是有些读者心心念念的,通过 `swap` 方式的全排列代码,这有什么难吗?
::: important 再次小试牛刀
有了前面的铺垫,我又要进一步为难你了。[回溯算法秒杀排列/组合/子集的九种变体](https://labuladong.github.io/article/fname.html?fname=子集排列组合) 都给出过子集问题的代码。
就以最基本的元素无重不可复选的子集为例,我直接把代码 copy 过来:
```java
class Solution {
List<List<Integer>> res = new LinkedList<>();
// 记录回溯算法的递归路径
LinkedList<Integer> track = new LinkedList<>();
// 主函数
public List<List<Integer>> subsets(int[] nums) {
backtrack(nums, 0);
return res;
}
// 回溯算法核心函数,遍历子集问题的回溯树
void backtrack(int[] nums, int start) {
// 前序位置,每个节点的值都是一个子集
res.add(new LinkedList<>(track));
// 回溯算法标准框架
for (int i = start; i < nums.length; i++) {
// 做选择
track.addLast(nums[i]);
// 通过 start 参数控制树枝的遍历,避免产生重复的子集
backtrack(nums, i + 1);
// 撤销选择
track.removeLast();
}
}
}
```
请问,这个解法是以什么视角进行穷举的?是以球的视角还是盒的视角?给你三分钟思考,请回答!
:::
::: details 点击查看我的答案
这个解法是以盒的视角穷举的。
因为刚才讲的全排列问题会考虑顺序的差异,而子集问题不考虑顺序的差异。为了方便理解,我们这里干脆不说「球盒模型」了,说「球桶模型」吧,因为放进盒子的求给人感觉是有顺序的,而丢进桶里的东西给人感觉是无所谓顺序的。
那么,以桶的视角理解,子集问题相当于把 `n` 个球丢到容量为 `n` 的桶里,桶可以不装满。
这样,第一个球面对的是空桶,所以可以有 `n` 种位置选择,第二个球面对的是已经装了一个球的桶,所以可以有 `n - 1` 种位置选择,第三个球有 `n - 2` 种位置选择,以此类推。
你看代码也能体现出来这种穷举过程,`start` 来控制选择空间逐渐缩小:
```java
// 回溯算法框架核心代码
void backtrack(int[] nums, int start) {
for (int i = start; i < nums.length; i++) {
track.addLast(nums[i]);
// 通过 start 参数控制树枝的生长
backtrack(nums, i + 1);
track.removeLast();
}
}
```
:::
我继续用 [算法可视化面板](https://labuladong.github.io/article/fname.html?fname=可视化简介) 来论证我的答案,请你把进度条拖到最后让整棵回溯树显示出来,然后把鼠标在每一层节点上横向移动,观察递归树节点和树枝上的值,你可以很直观地看明白:
<visual slug='box-view-of-subsets' open step=-1 title="球盒模型:以盒的视角求解子集" />
::: important 最后一次考你
既然上面说了,我给的子集问题解法是以桶的视角理解的,那么你能不能写出一个以球的视角理解的子集问题的解法?给你十分钟写代码。
如果你有这个时间,一定要亲自动手尝试一下,不要着急看我的答案。你能认真看到这里,肯定可以写出来的,不要怀疑。
:::
::: details 点击查看我的思路
从球的视角理解,每个球都有两种选择,要么在桶中,要么不在桶中。这样,我们可以写出下面的代码:
```java
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> track = new ArrayList<>();
backtrack(nums, 0, track, res);
return res;
}
private void backtrack(int[] nums, int i, List<Integer> track, List<List<Integer>> res) {
if (i == nums.length) {
res.add(new ArrayList<>(track));
return;
}
// 做第一种选择,元素在子集中
track.add(nums[i]);
backtrack(nums, i + 1, track, res);
// 撤销选择
track.remove(track.size() - 1);
// 做第二种选择,元素不在子集中
backtrack(nums, i + 1, track, res);
}
}
```
:::
我继续用 [算法可视化面板](https://labuladong.github.io/article/fname.html?fname=可视化简介) 来论证我的答案,请你把进度条拖到最后让整棵回溯树显示出来,然后把鼠标在节点上移动,观察递归树节点和树枝上的值:
<visual slug='ball-view-of-subsets' open step=-1 title="球盒模型:以球的视角求解子集" />
这也解释了,为什么所有子集(幂集)的数量是 `2^n`,因为每个元素都有两种选择,要么在子集中,要么不在子集中,所以其递归树就是一棵满二叉树,一共有 `2^n` 个叶子节点。
### 题目思路
回到正题,这道算法题让我们求子集划分,子集问题和排列组合问题有所区别,但我们可以借鉴「球盒模型」的抽象,用两种不同的视角来解决这道子集划分问题。
把装有 `n` 个数字的数组 `nums` 分成 `k` 个和相同的集合,你可以想象将 `n` 个数字分配到 `k` 个「桶」里,最后这 `k` 个「桶」里的数字之和要相同。
@ -114,7 +349,7 @@ boolean canPartitionKSubsets(int[] nums, int k);
**用不同的视角进行穷举,虽然结果相同,但是解法代码的逻辑完全不同,进而算法的效率也会不同;对比不同的穷举视角,可以帮你更深刻地理解回溯算法,我们慢慢道来**。
### 二、以数字的视角
### 以数字的视角
用 for 循环迭代遍历 `nums` 数组大家肯定都会:
@ -284,7 +519,7 @@ boolean canPartitionKSubsets(int[] nums, int k) {
这个解法可以得到正确答案,但耗时比较多,已经无法通过所有测试用例了,接下来看看另一种视角的解法。
### 三、以桶的视角
### 以桶的视角
文章开头说了,**以桶的视角进行穷举,每个桶需要遍历 `nums` 中的所有数字,决定是否把当前数字装进桶中;当装满一个桶之后,还要装下一个桶,直到所有桶都装满为止**。
@ -545,7 +780,7 @@ class Solution {
至此,这道题的第二种思路也完成了。
### 四、最后总结
### 最后总结
本文写的这两种思路都可以算出正确答案,不过第一种解法即便经过了排序优化,也明显比第二种解法慢很多,这是为什么呢?
@ -563,7 +798,11 @@ class Solution {
好了,这道题我们从两种视角进行穷举,虽然代码量看起来多,但核心逻辑都是类似的,相信你通过本文能够更深刻地理解回溯算法。
> info文中思考题答案为什么划分两个相等的子集可以转化成背包问题
::: info
文中思考题答案:为什么划分两个相等的子集可以转化成背包问题?
:::
> [0-1 背包问题](https://labuladong.github.io/article/fname.html?fname=背包问题) 的场景中,有一个背包和若干物品,每个物品有**两个选择**,分别是「装进背包」和「不装进背包」。把原集合 `S` 划分成两个相等子集 `S_1, S_2` 的场景下,`S` 中的每个元素也有**两个选择**,分别是「装进 `S_1`」和「不装进 `S_1`(装进 `S_2`)」,这时候的穷举思路其实和背包问题相同。
@ -576,6 +815,8 @@ class Solution {
<summary><strong>引用本文的文章</strong></summary>
- [动态规划穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=动归两种视角)
- [回溯算法秒杀所有排列/组合/子集问题](https://labuladong.github.io/article/fname.html?fname=子集排列组合)
- [回溯算法解题套路框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版)
- [谁能想到,斗地主也能玩出算法](https://labuladong.github.io/article/fname.html?fname=斗地主)
</details><hr>
@ -586,6 +827,6 @@ class Solution {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -357,7 +357,7 @@ class LRUCache {
}
```
至此LRU 算法就没有什么神秘的了。更多数据结构设计相关的题目参见 [数据结构设计经典习题](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_6312b9e5e4b0eca59c2b7e93/1)。
至此LRU 算法就没有什么神秘的了。更多数据结构设计相关的题目参见 [数据结构设计经典习题](https://labuladong.online/algo/ds-class/jing-dian--9ec8b/qiang-hua--00937)。
接下来可阅读:
@ -397,7 +397,7 @@ class LRUCache {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -188,7 +188,7 @@ ListNode reverseKGroup(ListNode head, int k) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -150,8 +150,8 @@ int bulbSwitch(int n) {
<details class="hint-container details">
<summary><strong>引用本文的文章</strong></summary>
- [丑数系列算法详解](https://labuladong.github.io/article/fname.html?fname=丑数)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [一文秒杀所有丑数系列问题](https://labuladong.github.io/article/fname.html?fname=丑数)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [经典动态规划:博弈问题](https://labuladong.github.io/article/fname.html?fname=动态规划之博弈问题)
</details><hr>
@ -162,7 +162,7 @@ int bulbSwitch(int n) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -243,7 +243,7 @@ int left_bound(ArrayList<Integer> arr, int target) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -44,7 +44,11 @@
因为算法题一般都让你求最值,比如让你求吃香蕉的「最小速度」,让你求轮船的「最低运载能力」,求最值的过程,必然是搜索一个边界的过程,所以后面我们就详细分析一下这两种搜索边界的二分算法代码。
> note注意本文我写的都是左闭右开的二分搜索写法如果你习惯两端都闭的写法可以自行改写代码。
::: note
注意,本文我写的都是左闭右开的二分搜索写法,如果你习惯两端都闭的写法,可以自行改写代码。
:::
「搜索左侧边界」的二分搜索算法的具体代码实现如下:
@ -112,9 +116,9 @@ int right_bound(int[] nums, int target) {
<details class="hint-container details">
<summary><strong>引用本文的文章</strong></summary>
- [丑数系列算法详解](https://labuladong.github.io/article/fname.html?fname=丑数)
- [一文秒杀所有丑数系列问题](https://labuladong.github.io/article/fname.html?fname=丑数)
- [我写了首诗,把二分搜索算法变成了默写题](https://labuladong.github.io/article/fname.html?fname=二分查找详解)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [用算法打败算法](https://labuladong.github.io/article/fname.html?fname=PDF中的算法)
- [经典动态规划:高楼扔鸡蛋](https://labuladong.github.io/article/fname.html?fname=高楼扔鸡蛋问题)
- [讲两道常考的阶乘算法题](https://labuladong.github.io/article/fname.html?fname=阶乘题目)
@ -142,6 +146,6 @@ int right_bound(int[] nums, int target) {
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_627cce2de4b01a4851fe0ed1/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.online/algo/ds-class/shu-zu-lia-39fd9/er-fen-cha-b34e4) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -271,7 +271,7 @@ p.next = reverse(q);
具体到回文链表的判断问题,由于回文的特殊性,可以不完全反转链表,而是仅仅反转部分链表,将空间复杂度降到 O(1)。
> info最后打个广告我亲自制作了一门 [数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO),以视频课为主,手把手带你实现常用的数据结构及相关算法,旨在帮助算法基础较为薄弱的读者深入理解常用数据结构的底层原理,在算法学习中少走弯路。
> info最后打个广告我亲自制作了一门 [数据结构精品课](https://labuladong.online/algo/ds-class/),以视频课为主,手把手带你实现常用的数据结构及相关算法,旨在帮助算法基础较为薄弱的读者深入理解常用数据结构的底层原理,在算法学习中少走弯路。
@ -295,7 +295,7 @@ p.next = reverse(q);
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -218,7 +218,11 @@ int findCelebrity(int n) {
这个算法避免了嵌套 for 循环,时间复杂度降为 O(N) 了,不过引入了一个队列来存储候选人集合,使用了 O(N) 的空间复杂度。
> note`LinkedList` 的作用只是充当一个容器把候选人装起来,每次找出两个进行比较和淘汰,但至于具体找出哪两个,都是无所谓的,也就是说候选人归队的顺序无所谓,我们用的是 `addFirst` 只是方便后续的优化,你完全可以用 `addLast`,结果都是一样的。
::: note
`LinkedList` 的作用只是充当一个容器把候选人装起来,每次找出两个进行比较和淘汰,但至于具体找出哪两个,都是无所谓的,也就是说候选人归队的顺序无所谓,我们用的是 `addFirst` 只是方便后续的优化,你完全可以用 `addLast`,结果都是一样的。
:::
是否可以进一步优化,把空间复杂度也优化掉?
@ -275,6 +279,6 @@ int findCelebrity(int n) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -74,6 +74,12 @@
那么,接下来我们就开始穷举,把排列/组合/子集问题的 9 种形式都过一遍,学学如何用回溯算法把它们一套带走。
::: info 提示
另外,有些读者之前看过的排列/子集/组合的解法代码可能和我在本文介绍的代码不同。这是因为回溯算法有两种穷举视角,我会在后文 [球盒模型:回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分) 手把手给你讲清楚。现在还不适合直接跟你讲那些解法,你照着我的思路学习即可。
:::
### 子集(元素无重不可复选)
力扣第 78 题「子集」就是这个问题:
@ -125,7 +131,11 @@ List<List<Integer>> subsets(int[] nums)
![](https://labuladong.github.io/pictures/排列组合/6.jpeg)
> info**注意,本文之后所说「节点的值」都是指节点和根节点之间树枝上的元素,且将根节点认为是第 0 层**。
::: info
**注意,本文之后所说「节点的值」都是指节点和根节点之间树枝上的元素,且将根节点认为是第 0 层**。
:::
那么再进一步,如果想计算所有子集,那只要遍历这棵多叉树,把所有节点的值收集起来不就行了?
@ -642,6 +652,10 @@ if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
可以看到,`!used[i - 1]` 这种剪枝逻辑剪得干净利落,而 `used[i - 1]` 这种剪枝逻辑虽然也能得到无重结果,但它剪掉的树枝较少,存在的无效计算较多,所以效率会差一些。
你可以使用可视化面板的「编辑」按钮自行修改代码验证一下,看看两种写法产生的回溯树有何差别:
<visual slug='permutations-ii' />
当然,关于排列去重,也有读者提出别的剪枝思路:
<!-- muliti_language -->
@ -987,10 +1001,9 @@ void backtrack(int[] nums) {
- [东哥带你刷二叉树(纲领篇)](https://labuladong.github.io/article/fname.html?fname=二叉树总结)
- [分治算法详解:运算优先级](https://labuladong.github.io/article/fname.html?fname=分治算法)
- [动态规划和回溯算法的思维转换](https://labuladong.github.io/article/fname.html?fname=单词拼接)
- [回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分)
- [回溯算法解题套路框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版)
- [我的刷题心得](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [算法可视化功能简介(必读)](https://labuladong.github.io/article/fname.html?fname=可视化简介)
- [我的刷题心得:算法的本质](https://labuladong.github.io/article/fname.html?fname=算法心得)
- [球盒模型:回溯算法穷举的两种视角](https://labuladong.github.io/article/fname.html?fname=集合划分)
- [算法时空复杂度分析实用指南](https://labuladong.github.io/article/fname.html?fname=时间复杂度)
</details><hr>
@ -1009,6 +1022,7 @@ void backtrack(int[] nums) {
| [131. Palindrome Partitioning](https://leetcode.com/problems/palindrome-partitioning/?show=1) | [131. 分割回文串](https://leetcode.cn/problems/palindrome-partitioning/?show=1) |
| [17. Letter Combinations of a Phone Number](https://leetcode.com/problems/letter-combinations-of-a-phone-number/?show=1) | [17. 电话号码的字母组合](https://leetcode.cn/problems/letter-combinations-of-a-phone-number/?show=1) |
| [254. Factor Combinations](https://leetcode.com/problems/factor-combinations/?show=1)🔒 | [254. 因子的组合](https://leetcode.cn/problems/factor-combinations/?show=1)🔒 |
| [267. Palindrome Permutation II](https://leetcode.com/problems/palindrome-permutation-ii/?show=1)🔒 | [267. 回文排列 II](https://leetcode.cn/problems/palindrome-permutation-ii/?show=1)🔒 |
| [368. Largest Divisible Subset](https://leetcode.com/problems/largest-divisible-subset/?show=1) | [368. 最大整除子集](https://leetcode.cn/problems/largest-divisible-subset/?show=1) |
| [491. Non-decreasing Subsequences](https://leetcode.com/problems/non-decreasing-subsequences/?show=1) | [491. 递增子序列](https://leetcode.cn/problems/non-decreasing-subsequences/?show=1) |
| [638. Shopping Offers](https://leetcode.com/problems/shopping-offers/?show=1) | [638. 大礼包](https://leetcode.cn/problems/shopping-offers/?show=1) |
@ -1025,7 +1039,7 @@ void backtrack(int[] nums) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -49,12 +49,44 @@ int minMeetingRooms(int[][] meetings);
我们之前写过很多区间调度相关的文章,这里就顺便帮大家梳理一下这类问题的思路:
**第一个场景**,假设现在只有一个会议室,还有若干会议,你如何将尽可能多的会议安排到这个会议室里?
这个问题需要将这些会议(区间)按结束时间(右端点)排序,然后进行处理,详见前文 [贪心算法做时间管理](https://labuladong.github.io/article/fname.html?fname=贪心算法之区间调度问题)。
**第二个场景**,给你若干较短的视频片段,和一个较长的视频片段,请你从较短的片段中尽可能少地挑出一些片段,拼接出较长的这个片段。
这个问题需要将这些视频片段(区间)按开始时间(左端点)排序,然后进行处理,详见前文 [剪视频剪出一个贪心算法](https://labuladong.github.io/article/fname.html?fname=剪视频)。
**第三个场景**,给你若干区间,其中可能有些区间比较短,被其他区间完全覆盖住了,请你删除这些被覆盖的区间。
这个问题需要将这些区间按左端点排序,然后就能找到并删除那些被完全覆盖的区间了,详见前文 [删除覆盖区间](https://labuladong.github.io/article/fname.html?fname=区间问题合集)。
**第四个场景**,给你若干区间,请你将所有有重叠部分的区间进行合并。
这个问题需要将这些区间按左端点排序,方便找出存在重叠的区间,详见前文 [合并重叠区间](https://labuladong.github.io/article/fname.html?fname=区间问题合集)。
**第五个场景**,有两个部门同时预约了同一个会议室的若干时间段,请你计算会议室的冲突时段。
这个问题就是给你两组区间列表,请你找出这两组区间的交集,这需要你将这些区间按左端点排序,详见前文 [区间交集问题](https://labuladong.github.io/article/fname.html?fname=区间问题合集)。
**第六个场景**,假设现在只有一个会议室,还有若干会议,如何安排会议才能使这个会议室的闲置时间最少?
这个问题需要动动脑筋,说白了这就是个 0-1 背包问题的变形:
会议室可以看做一个背包,每个会议可以看做一个物品,物品的价值就是会议的时长,请问你如何选择物品(会议)才能最大化背包中的价值(会议室的使用时长)?
当然,这里背包的约束不是一个最大重量,而是各个物品(会议)不能互相冲突。把各个会议按照结束时间进行排序,然后参考前文 [0-1 背包问题详解](https://labuladong.github.io/article/fname.html?fname=背包问题) 的思路即可解决,等我以后有机会可以写一写这个问题。
**第七个场景**,就是本文想讲的场景,给你若干会议,让你合理申请会议室。
好了,举例了这么多,来看看今天的这个问题如何解决。
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_649bf421e4b0f2aa7dfe0d9c/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=安排会议室) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -165,7 +165,11 @@ class Solution {
因为 `dfs` 函数遍历到值为 `0` 的位置会直接返回,所以只要把经过的位置都设置为 `0`,就可以起到不走回头路的作用。
> tip这类 DFS 算法还有个别名叫做 [FloodFill 算法](https://labuladong.github.io/article/fname.html?fname=FloodFill算法详解及应用),现在有没有觉得 FloodFill 这个名字还挺贴切的~
::: tip
这类 DFS 算法还有个别名叫做 [FloodFill 算法](https://labuladong.github.io/article/fname.html?fname=FloodFill算法详解及应用),现在有没有觉得 FloodFill 这个名字还挺贴切的~
:::
这个最最基本的算法问题就说到这,我们来看看后面的题目有什么花样。
@ -252,7 +256,11 @@ class Solution {
只要提前把靠边的陆地都淹掉,然后算出来的就是封闭岛屿了。
> tip处理这类岛屿题目除了 DFS/BFS 算法之外Union Find 并查集算法也是一种可选的方法,前文 [Union Find 算法运用](https://labuladong.github.io/article/fname.html?fname=UnionFind算法详解) 就用 Union Find 算法解决了一道类似的问题。
::: tip
处理这类岛屿题目除了 DFS/BFS 算法之外Union Find 并查集算法也是一种可选的方法,前文 [Union Find 算法运用](https://labuladong.github.io/article/fname.html?fname=UnionFind算法详解) 就用 Union Find 算法解决了一道类似的问题。
:::
这道岛屿题目的解法稍微改改就可以解决力扣第 1020 题「飞地的数量」,这题不让你求封闭岛屿的数量,而是求封闭岛屿的面积总和。
@ -478,10 +486,14 @@ void dfs(int[][] grid, int i, int j) {
**你看,这就相当于是岛屿序列化的结果,只要每次使用 `dfs` 遍历岛屿的时候生成这串数字进行比较,就可以计算到底有多少个不同的岛屿了**。
> info细心的读者问到为什么记录「撤销」操作才能唯一表示遍历顺序呢不记录撤销操作好像也可以实际上不是的。
::: info
细心的读者问到,为什么记录「撤销」操作才能唯一表示遍历顺序呢?不记录撤销操作好像也可以?实际上不是的。
>
> 比方说「下,右,撤销右,撤销下」和「下,撤销下,右,撤销右」显然是两个不同的遍历顺序,但如果不记录撤销操作,那么它俩都是「下,右」,成了相同的遍历顺序,显然是不对的。
:::
所以我们需要稍微改造 `dfs` 函数,添加一些函数参数以便记录遍历顺序:
<!-- muliti_language -->
@ -506,7 +518,11 @@ void dfs(int[][] grid, int i, int j, StringBuilder sb, int dir) {
}
```
> note仔细看这个代码在递归前做选择在递归后撤销选择它像不像 [回溯算法框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版)?实际上它就是回溯算法,因为它关注的是「树枝」(岛屿的遍历顺序),而不是「节点」(岛屿的每个格子)。
::: note
仔细看这个代码,在递归前做选择,在递归后撤销选择,它像不像 [回溯算法框架](https://labuladong.github.io/article/fname.html?fname=回溯算法详解修订版)?实际上它就是回溯算法,因为它关注的是「树枝」(岛屿的遍历顺序),而不是「节点」(岛屿的每个格子)。
:::
`dir` 记录方向,`dfs` 函数递归结束后,`sb` 记录着整个遍历顺序。有了这个 `dfs` 函数就好办了,我们可以直接写出最后的解法代码:
@ -575,6 +591,6 @@ class Solution {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -245,7 +245,7 @@ class ExamRoom {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -188,8 +188,8 @@ class Solution {
<details class="hint-container details">
<summary><strong>引用本文的文章</strong></summary>
- [丑数系列算法详解](https://labuladong.github.io/article/fname.html?fname=丑数)
- [配套 Chrome 刷题插件(必装)](https://labuladong.github.io/article/fname.html?fname=chrome插件简介)
- [一文秒杀所有丑数系列问题](https://labuladong.github.io/article/fname.html?fname=丑数)
- [配套 Chrome 刷题插件](https://labuladong.github.io/article/fname.html?fname=chrome插件简介)
</details><hr>
@ -214,7 +214,7 @@ class Solution {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -53,11 +53,11 @@ int trap(int[] height);
```python
water[i] = min(
# 左边最高的柱子
max(height[0..i]),
# 右边最高的柱子
max(height[i..end])
) - height[i]
# 左边最高的柱子
max(height[0..i]),
# 右边最高的柱子
max(height[i..end])
) - height[i]
```
@ -131,6 +131,14 @@ class Solution {
### 三、双指针解法
::: note 我的建议
这个解法作为思路拓展,看看就好,不必过于执着最优解。因为对于大部分人,在真实的面试/笔试中,能够使用朴实无华的方法见招拆招,写出上面的解法就可以了。虽然多了一些空间复杂度,但一般判题平台还是能过的。
除非过不了所有测试用例,且你写完了其他题目还有富余的时间,再花时间针对上面的解法进行优化也不迟。
:::
这种解法的思路是完全相同的,但在实现手法上非常巧妙,我们这次也不要用备忘录提前计算了,而是用双指针**边走边算**,节省下空间复杂度。
首先,看一部分代码:
@ -297,7 +305,7 @@ if (height[left] < height[right]) {
**_____________**
**《labuladong 的算法小抄》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
![](https://labuladong.github.io/pictures/souyisou2.png)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -62,7 +62,7 @@ O(N) 的时间复杂度遍历数组是无法避免的,所以我们可以想想
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_649bf4b0e4b0f2aa7dfe0e07/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=缺失和重复的元素) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)

View File

@ -2,14 +2,14 @@
<p align='center'>
<a href="https://github.com/labuladong/fucking-algorithm" target="view_window"><img alt="GitHub" src="https://img.shields.io/github/stars/labuladong/fucking-algorithm?label=Stars&style=flat-square&logo=GitHub"></a>
<a href="https://appktavsiei5995.pc.xiaoe-tech.com/index" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://labuladong.online/algo/" target="_blank"><img class="my_header_icon" src="https://img.shields.io/static/v1?label=精品课程&message=查看&color=pink&style=flat"></a>
<a href="https://www.zhihu.com/people/labuladong"><img src="https://img.shields.io/badge/%E7%9F%A5%E4%B9%8E-@labuladong-000000.svg?style=flat-square&logo=Zhihu"></a>
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
</p>
![](https://labuladong.github.io/pictures/souyisou1.png)
**通知:[数据结构精品课](https://aep.h5.xeknow.com/s/1XJHEO) 和 [递归算法专题课](https://aep.xet.tech/s/3YGcq3) 限时附赠网站会员,全新纸质书[《labuladong 的算法笔记》](https://labuladong.gitee.io/algo/images/book/book_intro_qrcode.jpg) 出版,签名版限时半价!另外,建议你在我的 [网站](https://labuladong.github.io/algo/) 学习文章,体验更好。**
**通知:[数据结构精品课](https://labuladong.online/algo/ds-class/) 和 [递归算法专题课](https://labuladong.online/algo/tree-class/) 限时附赠网站会员;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo-visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
@ -68,6 +68,6 @@
**_____________**
本文为会员内容,请扫码关注公众号或 [点这里](https://appktavsiei5995.pc.xiaoe-tech.com/detail/i_649bbb87e4b0b0bc2bf8e9d9/1) 查看:
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.gitee.io/article/fname.html?fname=随机权重) 查看:
![](https://labuladong.github.io/pictures/qrcode.jpg)