1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
*.txt
|
*.txt
|
||||||
|
!tencent13147342467085209222.txt
|
66
README.md
@ -2,7 +2,7 @@
|
|||||||
| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|
|
| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|
|
||||||
| 算法[:pencil2:](#pencil2-算法) | 操作系统[:computer:](#computer-操作系统)|网络[:cloud:](#cloud-网络) | 面向对象[:art:](#art-面向对象) |数据库[:floppy_disk:](#floppy_disk-数据库)| Java [:coffee:](#coffee-java)| 系统设计[:bulb:](#bulb-系统设计)| 工具[:wrench:](#wrench-工具)| 编码实践[:watermelon:](#watermelon-编码实践)| 后记[:memo:](#memo-后记) | -->
|
| 算法[:pencil2:](#pencil2-算法) | 操作系统[:computer:](#computer-操作系统)|网络[:cloud:](#cloud-网络) | 面向对象[:art:](#art-面向对象) |数据库[:floppy_disk:](#floppy_disk-数据库)| Java [:coffee:](#coffee-java)| 系统设计[:bulb:](#bulb-系统设计)| 工具[:wrench:](#wrench-工具)| 编码实践[:watermelon:](#watermelon-编码实践)| 后记[:memo:](#memo-后记) | -->
|
||||||
|
|
||||||
| 算法 | 操作系统 | 网络 | 面向对象 | 数据库 | Java | 系统设计 | 工具 | 编码实践 | 后记 |
|
| 算法 | 操作系统 | 网络 | 面向对象 | 数据库 | Java | 系统设计 | 工具 | 编码实践 | 后记 |
|
||||||
| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|
|
| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|
|
||||||
| [:pencil2:](#pencil2-算法) | [:computer:](#computer-操作系统)|[:cloud:](#cloud-网络) | [:art:](#art-面向对象) |[:floppy_disk:](#floppy_disk-数据库)| [:coffee:](#coffee-java)| [:bulb:](#bulb-系统设计)| [:wrench:](#wrench-工具)| [:watermelon:](#watermelon-编码实践)| [:memo:](#memo-后记) |
|
| [:pencil2:](#pencil2-算法) | [:computer:](#computer-操作系统)|[:cloud:](#cloud-网络) | [:art:](#art-面向对象) |[:floppy_disk:](#floppy_disk-数据库)| [:coffee:](#coffee-java)| [:bulb:](#bulb-系统设计)| [:wrench:](#wrench-工具)| [:watermelon:](#watermelon-编码实践)| [:memo:](#memo-后记) |
|
||||||
|
|
||||||
@ -13,25 +13,35 @@
|
|||||||
<br>
|
<br>
|
||||||
<a href="https://cyc2018.github.io/CS-Notes"> <img src="https://img.shields.io/badge/>-read-4ab8a1.svg"></a> <a href="https://xiaozhuanlan.com/CyC2018"> <img src="https://img.shields.io/badge/_-more-4ab8a1.svg"></a>
|
<a href="https://cyc2018.github.io/CS-Notes"> <img src="https://img.shields.io/badge/>-read-4ab8a1.svg"></a> <a href="https://xiaozhuanlan.com/CyC2018"> <img src="https://img.shields.io/badge/_-more-4ab8a1.svg"></a>
|
||||||
<br> <br>
|
<br> <br>
|
||||||
本项目包含了技术面试必备的基础知识,浅显易懂,你不需要花很长的时间去阅读和理解成堆的技术书籍就可以快速掌握这些知识,从而节省宝贵的面试复习时间。你也可以阅读 <a href="https://github.com/CyC2018/Backend-Interview-Guide">面试进阶指南</a>,包含了学习指导和面试技巧,让你更轻松拿到满意的 Offer。
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
🎓 本项目包含了技术面试必备的基础知识,内容浅显易懂,你不需要花很长的时间去阅读和理解成堆的技术书籍就可以快速掌握这些知识,从而节省宝贵的面试复习时间。
|
||||||
|
|
||||||
|
🎨 推荐使用 https://cyc2018.github.io/CS-Notes 进行阅读,从而获得更好的阅读体验。如果访问速度比较慢,可以考虑国内的 http://cyc2018.gitee.io/cs-notes/ 。
|
||||||
|
|
||||||
|
💯你也可以订阅 <a href="https://xiaozhuanlan.com/CyC2018">面试进阶指南</a>,包含了学习指导和面试技巧,让你更轻松拿到满意的 Offer。
|
||||||
|
|
||||||
|
⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg" width="200px">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## :pencil2: 算法
|
## :pencil2: 算法
|
||||||
|
|
||||||
- [剑指 Offer 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/剑指%20offer%20题解.md)
|
- [剑指 Offer 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/剑指%20Offer%20题解%20-%20目录.md)
|
||||||
- [Leetcode 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode%20题解.md)
|
- [Leetcode 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode%20题解%20-%20目录.md)
|
||||||
- [算法](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/算法.md)
|
- [算法](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/算法%20-%20目录.md)
|
||||||
|
|
||||||
## :computer: 操作系统
|
## :computer: 操作系统
|
||||||
|
|
||||||
- [计算机操作系统](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机操作系统.md)
|
- [计算机操作系统](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机操作系统%20-%20目录.md)
|
||||||
- [Linux](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Linux.md)
|
- [Linux](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Linux.md)
|
||||||
|
|
||||||
## :cloud: 网络
|
## :cloud: 网络
|
||||||
|
|
||||||
- [计算机网络](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机网络.md)
|
- [计算机网络](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机网络%20-%20目录.md)
|
||||||
- [HTTP](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/HTTP.md)
|
- [HTTP](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/HTTP.md)
|
||||||
- [Socket](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Socket.md)
|
- [Socket](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Socket.md)
|
||||||
|
|
||||||
@ -79,6 +89,14 @@
|
|||||||
|
|
||||||
## :memo: 后记
|
## :memo: 后记
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
本仓库内容 **不是** 将网上的资料随意拼凑而来,除了少部分引用书上和技术文档的原文,其余都是我的原创。在您引用本仓库内容或者对内容进行修改演绎时,请署名并以相同方式共享,谢谢。
|
||||||
|
|
||||||
|
转载文章请在开头明显处标明该页面地址。如果是公众号转载,也请在合适的位置贴上 [CyC2018 公众号二维码海报](https://github.com/CyC2018/CS-Notes/blob/master/assets/%E5%85%AC%E4%BC%97%E5%8F%B7%20%E6%B5%B7%E6%8A%A5.png)。
|
||||||
|
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="知识共享许可协议" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a>
|
||||||
|
|
||||||
### 内推信息
|
### 内推信息
|
||||||
|
|
||||||
[Job-Recommend](https://github.com/CyC2018/Job-Recommend)
|
[Job-Recommend](https://github.com/CyC2018/Job-Recommend)
|
||||||
@ -87,37 +105,28 @@
|
|||||||
|
|
||||||
为大家提供一个学习交流平台,在这里你可以自由地讨论技术问题。
|
为大家提供一个学习交流平台,在这里你可以自由地讨论技术问题。
|
||||||
|
|
||||||
<img src="assets/group1.png" width="150px"></br>
|
<img src="assets/group1.png" width="150px">
|
||||||
|
|
||||||
### 关于我
|
### 后端面试指南
|
||||||
|
|
||||||
<a href="https://www.zhihu.com/people/xiao-shi-guang-33/activities">
|
|
||||||
<img src="assets/知乎.jpg" width="60px">
|
|
||||||
</a>
|
|
||||||
<a href="https://xiaozhuanlan.com/CyC2018">
|
<a href="https://xiaozhuanlan.com/CyC2018">
|
||||||
<img src="assets/小专栏.jpg" width="60px">
|
<img src="assets/小专栏.jpg" width="80px">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://shimo.im/docs/1Vuo5GeWCHMnxMtF/">
|
|
||||||
<img src="assets/知识星球.png" width="60px">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
### 排版
|
### 排版
|
||||||
|
|
||||||
笔记内容按照 [文文案排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines) 进行排版,以保证内容的可读性。笔记不使用 `![]()` 这种方式来引用图片,而是用 `<img>` 标签。一方面是为了能够控制图片以合适的大小显示,另一方面是因为 GFM 不支持 `<center> ![]() </center>` 让图片居中显示,只能使用 `<div align="center"> <img src=""/> </div>` 达到居中的效果。
|
笔记内容按照 [中文文案排版指北](https://github.com/sparanoid/chinese-copywriting-guidelines) 进行排版,以保证内容的可读性。
|
||||||
|
|
||||||
我将自己实现的文档排版功能提取出来,放在 Github Page 中,无需下载安装即可免费使用:[Text-Typesetting](https://github.com/CyC2018/Text-Typesetting)。
|
不使用 `![]()` 这种方式来引用图片,而是用 `<img>` 标签。一方面是为了能够控制图片以合适的大小显示,另一方面是因为 [GFM](https://github.github.com/gfm/) 不支持 `<center> ![]() </center>` 这种方法让图片居中显示,只能使用 `<div align="center"> <img src=""/> </div>` 达到居中的效果。
|
||||||
|
|
||||||
|
在线排版工具:[Text-Typesetting](https://github.com/CyC2018/Text-Typesetting)。
|
||||||
|
|
||||||
### 上传方案
|
### 上传方案
|
||||||
|
|
||||||
我在本地使用为知笔记软件进行书写,为了方便将本地笔记内容上传到 Github 上,实现了一整套自动化上传方案,包括文本文件的导出、提取图片、Markdown 文档转换、Git 同步。进行 Markdown 文档转换是因为 Github 使用的 GFM 不支持 MathJax 公式和 TOC 标记,所以需要替换 MathJax 公式为 CodeCogs 的云服务和重新生成 TOC 目录。
|
为了方便将本地笔记内容上传到 Github 上,实现了一整套自动化上传方案,包括提取图片、Markdown 文档转换、Git 同步。进行 Markdown 文档转换是因为 Github 使用的 GFM 不支持 MathJax 公式和 TOC 标记,所以需要替换 MathJax 公式为 CodeCogs 的云服务和重新生成 TOC 目录。
|
||||||
|
|
||||||
我将自己实现文档转换功能提取出来,方便大家在需要将本地 Markdown 上传到 Github,或者制作项目 README 文档时生成目录时使用:[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。
|
GFM 转换工具:[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。
|
||||||
|
|
||||||
### License
|
|
||||||
|
|
||||||
学习笔记不是从网上到处拼凑而来,除了少部分引用书上和技术文档的原文,其余都是我的原创。在您引用本仓库内容或者对内容进行修改演绎时,请署名并以相同方式共享,谢谢。
|
|
||||||
|
|
||||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="知识共享许可协议" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a>
|
|
||||||
|
|
||||||
### Logo
|
### Logo
|
||||||
|
|
||||||
@ -132,6 +141,9 @@ Power by [logomakr](https://logomakr.com/).
|
|||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/g10guang">
|
<a href="https://github.com/g10guang">
|
||||||
<img src="https://avatars1.githubusercontent.com/u/18458140?s=400&v=4" width="50px">
|
<img src="https://avatars1.githubusercontent.com/u/18458140?s=400&v=4" width="50px">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/Sctwang">
|
||||||
|
<img src="https://avatars3.githubusercontent.com/u/33345444?s=400&v=4" width="50px">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/ResolveWang">
|
<a href="https://github.com/ResolveWang">
|
||||||
<img src="https://avatars1.githubusercontent.com/u/8018776?s=400&v=4" width="50px">
|
<img src="https://avatars1.githubusercontent.com/u/8018776?s=400&v=4" width="50px">
|
||||||
|
BIN
assets/公众号 海报.png
Normal file
After Width: | Height: | Size: 506 KiB |
BIN
assets/公众号.jpg
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
assets/公众号1.jpg
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
assets/公众号海报.png
Normal file
After Width: | Height: | Size: 506 KiB |
@ -1,56 +1,63 @@
|
|||||||
|
- [点击订阅面试进阶指南](https://xiaozhuanlan.com/CyC2018)
|
||||||
|
|
||||||
> [点击阅读面试进阶指南](https://github.com/CyC2018/Backend-Interview-Guide)
|
## ✏️ 算法
|
||||||
|
|
||||||
## ✏️ 算法
|
- [剑指 Offer 题解](notes/剑指%20Offer%20题解%20-%20目录1.md) </br>
|
||||||
|
- [Leetcode 题解](notes/Leetcode%20题解%20-%20目录1.md) </br>
|
||||||
> [剑指 Offer 题解](notes/剑指%20offer%20题解.md) </br>
|
- [算法](notes/算法%20-%20目录1.md) </br>
|
||||||
> [Leetcode 题解](notes/Leetcode%20题解) </br>
|
- [点击订阅面试进阶指南](https://xiaozhuanlan.com/CyC2018)
|
||||||
> [算法](notes/算法.md)
|
|
||||||
|
|
||||||
## 💻 操作系统
|
## 💻 操作系统
|
||||||
|
|
||||||
> [计算机操作系统](notes/计算机操作系统.md) </br>
|
- [计算机操作系统](notes/计算机操作系统%20-%20目录1.md) </br>
|
||||||
> [Linux](notes/Linux.md)
|
- [Linux](notes/Linux.md)
|
||||||
|
|
||||||
## ☁️ 网络
|
## ☁️ 网络
|
||||||
|
|
||||||
> [计算机网络](notes/计算机网络.md) </br>
|
- [计算机网络](notes/计算机网络%20-%20目录1.md) </br>
|
||||||
> [HTTP](notes/HTTP.md) </br>
|
- [HTTP](notes/HTTP.md) </br>
|
||||||
> [Socket](notes/Socket.md)
|
- [Socket](notes/Socket.md)
|
||||||
|
|
||||||
## 🔓 面向对象
|
## 🎨 面向对象
|
||||||
|
|
||||||
> [设计模式](notes/设计模式.md) </br>
|
- [设计模式](notes/设计模式.md) </br>
|
||||||
> [面向对象思想](notes/面向对象思想.md)
|
- [面向对象思想](notes/面向对象思想.md)
|
||||||
|
|
||||||
## 💾 数据库
|
## 💾 数据库
|
||||||
|
|
||||||
> [数据库系统原理](notes/数据库系统原理.md) </br>
|
- [数据库系统原理](notes/数据库系统原理.md) </br>
|
||||||
> [SQL](notes/SQL.md) </br>
|
- [SQL](notes/SQL.md) </br>
|
||||||
> [Leetcode-Database 题解](notes/Leetcode-Database%20题解.md) </br>
|
- [Leetcode-Database 题解](notes/Leetcode-Database%20题解.md) </br>
|
||||||
> [MySQL](notes/MySQL.md) </br>
|
- [MySQL](notes/MySQL.md) </br>
|
||||||
> [Redis](notes/Redis.md)
|
- [Redis](notes/Redis.md)
|
||||||
|
|
||||||
## ☕️ Java
|
## ☕️ Java
|
||||||
|
|
||||||
> [Java 基础](notes/Java%20基础.md) </br>
|
- [Java 基础](notes/Java%20基础.md) </br>
|
||||||
> [Java 容器](notes/Java%20容器.md) </br>
|
- [Java 容器](notes/Java%20容器.md) </br>
|
||||||
> [Java 并发](notes/Java%20并发.md) </br>
|
- [Java 并发](notes/Java%20并发.md) </br>
|
||||||
> [Java 虚拟机](notes/Java%20虚拟机.md) </br>
|
- [Java 虚拟机](notes/Java%20虚拟机.md) </br>
|
||||||
> [Java I/O](notes/Java%20IO.md)
|
- [Java I/O](notes/Java%20IO.md)
|
||||||
|
|
||||||
## 💡 系统设计
|
## 💡 系统设计
|
||||||
|
|
||||||
> [系统设计基础](notes/系统设计基础.md) </br>
|
- [系统设计基础](notes/系统设计基础.md) </br>
|
||||||
> [分布式](notes/分布式.md) </br>
|
- [分布式](notes/分布式.md) </br>
|
||||||
> [集群](notes/集群.md) </br>
|
- [集群](notes/集群.md) </br>
|
||||||
> [攻击技术](notes/攻击技术.md) </br>
|
- [攻击技术](notes/攻击技术.md) </br>
|
||||||
> [缓存](notes/缓存.md) </br>
|
- [缓存](notes/缓存.md) </br>
|
||||||
> [消息队列](notes/消息队列.md)
|
- [消息队列](notes/消息队列.md)
|
||||||
|
|
||||||
## 🔧 工具
|
## 🔧 工具
|
||||||
|
|
||||||
> [Git](notes/Git.md) </br>
|
- [Git](notes/Git.md) </br>
|
||||||
> [Docker](notes/Docker.md) </br>
|
- [Docker](notes/Docker.md) </br>
|
||||||
> [正则表达式](notes/正则表达式.md) </br>
|
- [正则表达式](notes/正则表达式.md) </br>
|
||||||
> [构建工具](notes/构建工具.md)
|
- [构建工具](notes/构建工具.md)
|
||||||
|
|
||||||
|
<!--⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。
|
||||||
|
<br/><br/>
|
||||||
|
<div align="center">
|
||||||
|
<img src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg" width="200px">
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
<img width="150px" src="_media/LogoMakr_1J56bI.png">
|
<img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/LogoMakr_1J56bI.png">
|
||||||
|
|
||||||
# CS-Notes
|
# CS-Notes
|
||||||
|
|
||||||
- 本项目包含了技术面试必备的基础知识,浅显易懂,你不需要花很长的时间去阅读和理解成堆的技术书籍就可以快速掌握这些知识,从而节省宝贵的面试复习时间。你也可以阅读 <a href="https://github.com/CyC2018/Backend-Interview-Guide">面试进阶指南</a>,包含了学习指导和面试技巧,让你更轻松拿到满意的 Offer。
|
- 本项目包含了技术面试必备的基础知识,内容浅显易懂,你不需要花很长的时间去阅读和理解成堆的技术书籍就可以快速掌握这些知识,从而节省宝贵的面试复习时间。
|
||||||
|
|
||||||
<span id="busuanzi_container_site_pv">Site View : <span id="busuanzi_value_site_pv">
|
<!--<span id="busuanzi_container_site_pv">Site View : <span id="busuanzi_value_site_pv">-->
|
||||||
|
|
||||||
|
[](https://github.com/CyC2018/CS-Notes) [](https://github.com/CyC2018/CS-Notes)
|
||||||
|
|
||||||
[Get Started](README.md)
|
[Get Started](README.md)
|
||||||
|
|
||||||
|
BIN
docs/_media/公众号.jpg
Normal file
After Width: | Height: | Size: 27 KiB |
2050
docs/_style/bootstrap-4.0.0-dist/css/bootstrap-grid.css
vendored
@ -1,330 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
|
||||||
* Copyright 2011-2018 The Bootstrap Authors
|
|
||||||
* Copyright 2011-2018 Twitter, Inc.
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
|
||||||
*/
|
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: sans-serif;
|
|
||||||
line-height: 1.15;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-ms-text-size-adjust: 100%;
|
|
||||||
-ms-overflow-style: scrollbar;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-ms-viewport {
|
|
||||||
width: device-width;
|
|
||||||
}
|
|
||||||
|
|
||||||
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #212529;
|
|
||||||
text-align: left;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
[tabindex="-1"]:focus {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
box-sizing: content-box;
|
|
||||||
height: 0;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr[title],
|
|
||||||
abbr[data-original-title] {
|
|
||||||
text-decoration: underline;
|
|
||||||
-webkit-text-decoration: underline dotted;
|
|
||||||
text-decoration: underline dotted;
|
|
||||||
cursor: help;
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
address {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
font-style: normal;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
|
||||||
ul,
|
|
||||||
dl {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol ol,
|
|
||||||
ul ul,
|
|
||||||
ol ul,
|
|
||||||
ul ol {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd {
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
dfn {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
position: relative;
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #007bff;
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: transparent;
|
|
||||||
-webkit-text-decoration-skip: objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #0056b3;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]) {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre,
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
samp {
|
|
||||||
font-family: monospace, monospace;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
overflow: auto;
|
|
||||||
-ms-overflow-style: scrollbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
vertical-align: middle;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg:not(:root) {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
caption {
|
|
||||||
padding-top: 0.75rem;
|
|
||||||
padding-bottom: 0.75rem;
|
|
||||||
color: #6c757d;
|
|
||||||
text-align: left;
|
|
||||||
caption-side: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
text-align: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: inline-block;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:focus {
|
|
||||||
outline: 1px dotted;
|
|
||||||
outline: 5px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button,
|
|
||||||
select,
|
|
||||||
optgroup,
|
|
||||||
textarea {
|
|
||||||
margin: 0;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
input {
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
html [type="button"],
|
|
||||||
[type="reset"],
|
|
||||||
[type="submit"] {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
[type="button"]::-moz-focus-inner,
|
|
||||||
[type="reset"]::-moz-focus-inner,
|
|
||||||
[type="submit"]::-moz-focus-inner {
|
|
||||||
padding: 0;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="radio"],
|
|
||||||
input[type="checkbox"] {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="date"],
|
|
||||||
input[type="time"],
|
|
||||||
input[type="datetime-local"],
|
|
||||||
input[type="month"] {
|
|
||||||
-webkit-appearance: listbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto;
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
min-width: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
legend {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
line-height: inherit;
|
|
||||||
color: inherit;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress {
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="number"]::-webkit-inner-spin-button,
|
|
||||||
[type="number"]::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"] {
|
|
||||||
outline-offset: -2px;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"]::-webkit-search-cancel-button,
|
|
||||||
[type="search"]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-file-upload-button {
|
|
||||||
font: inherit;
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
output {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
summary {
|
|
||||||
display: list-item;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
|
@ -1,8 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
|
||||||
* Copyright 2011-2018 The Bootstrap Authors
|
|
||||||
* Copyright 2011-2018 Twitter, Inc.
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
|
||||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
|
||||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
|
8975
docs/_style/bootstrap-4.0.0-dist/css/bootstrap.css
vendored
6328
docs/_style/bootstrap-4.0.0-dist/js/bootstrap.bundle.js
vendored
3894
docs/_style/bootstrap-4.0.0-dist/js/bootstrap.js
vendored
2050
docs/_style/bootstrap/css/bootstrap-grid.css
vendored
330
docs/_style/bootstrap/css/bootstrap-reboot.css
vendored
@ -1,330 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
|
||||||
* Copyright 2011-2018 The Bootstrap Authors
|
|
||||||
* Copyright 2011-2018 Twitter, Inc.
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
|
||||||
*/
|
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: sans-serif;
|
|
||||||
line-height: 1.15;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-ms-text-size-adjust: 100%;
|
|
||||||
-ms-overflow-style: scrollbar;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-ms-viewport {
|
|
||||||
width: device-width;
|
|
||||||
}
|
|
||||||
|
|
||||||
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #212529;
|
|
||||||
text-align: left;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
[tabindex="-1"]:focus {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
box-sizing: content-box;
|
|
||||||
height: 0;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr[title],
|
|
||||||
abbr[data-original-title] {
|
|
||||||
text-decoration: underline;
|
|
||||||
-webkit-text-decoration: underline dotted;
|
|
||||||
text-decoration: underline dotted;
|
|
||||||
cursor: help;
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
address {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
font-style: normal;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
|
||||||
ul,
|
|
||||||
dl {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol ol,
|
|
||||||
ul ul,
|
|
||||||
ol ul,
|
|
||||||
ul ol {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd {
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
dfn {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
position: relative;
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #007bff;
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: transparent;
|
|
||||||
-webkit-text-decoration-skip: objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #0056b3;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]) {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre,
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
samp {
|
|
||||||
font-family: monospace, monospace;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
overflow: auto;
|
|
||||||
-ms-overflow-style: scrollbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
vertical-align: middle;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg:not(:root) {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
caption {
|
|
||||||
padding-top: 0.75rem;
|
|
||||||
padding-bottom: 0.75rem;
|
|
||||||
color: #6c757d;
|
|
||||||
text-align: left;
|
|
||||||
caption-side: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
text-align: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: inline-block;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:focus {
|
|
||||||
outline: 1px dotted;
|
|
||||||
outline: 5px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button,
|
|
||||||
select,
|
|
||||||
optgroup,
|
|
||||||
textarea {
|
|
||||||
margin: 0;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
input {
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
html [type="button"],
|
|
||||||
[type="reset"],
|
|
||||||
[type="submit"] {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
[type="button"]::-moz-focus-inner,
|
|
||||||
[type="reset"]::-moz-focus-inner,
|
|
||||||
[type="submit"]::-moz-focus-inner {
|
|
||||||
padding: 0;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="radio"],
|
|
||||||
input[type="checkbox"] {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="date"],
|
|
||||||
input[type="time"],
|
|
||||||
input[type="datetime-local"],
|
|
||||||
input[type="month"] {
|
|
||||||
-webkit-appearance: listbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto;
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
min-width: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
legend {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
line-height: inherit;
|
|
||||||
color: inherit;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress {
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="number"]::-webkit-inner-spin-button,
|
|
||||||
[type="number"]::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"] {
|
|
||||||
outline-offset: -2px;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"]::-webkit-search-cancel-button,
|
|
||||||
[type="search"]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-file-upload-button {
|
|
||||||
font: inherit;
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
output {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
summary {
|
|
||||||
display: list-item;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
|
@ -1,8 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
|
||||||
* Copyright 2011-2018 The Bootstrap Authors
|
|
||||||
* Copyright 2011-2018 Twitter, Inc.
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
|
||||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
|
||||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
|
8975
docs/_style/bootstrap/css/bootstrap.css
vendored
7
docs/_style/bootstrap/css/bootstrap.min.css
vendored
6328
docs/_style/bootstrap/js/bootstrap.bundle.js
vendored
3894
docs/_style/bootstrap/js/bootstrap.js
vendored
7
docs/_style/bootstrap/js/bootstrap.min.js
vendored
363
docs/index.html
@ -7,12 +7,343 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
<meta name="description" content="Description">
|
<meta name="description" content="Description">
|
||||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||||
<link rel="icon" href="_media/logomakr-3sxxzw-128x128.png">
|
<link rel="icon" href=" https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/LogoMakr_1J56bI.png">
|
||||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
|
<link rel="stylesheet" href="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/vue.css">
|
||||||
<link rel="stylesheet" href="//unpkg.com/gitalk/dist/gitalk.css">
|
<!-- <link rel="stylesheet" href="//unpkg.com/gitalk/dist/gitalk.css"> -->
|
||||||
<link rel="stylesheet" href="_style/style.css">
|
<!-- <link rel="stylesheet" href="_style/style.css"> -->
|
||||||
<!--solarizedlight tomorrow coy-->
|
<!--solarizedlight tomorrow coy-->
|
||||||
<link rel="stylesheet" href="_style/prism-master/themes/prism-coy.css">
|
<!-- <link rel="stylesheet" href="_style/prism-master/themes/prism-coy.css"> -->
|
||||||
|
|
||||||
|
<!-- 将自定义样式放在 Github 上会导致加载速度变得非常慢,所以采取直接内嵌的方式 -->
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
/* 隐藏头部的目录 */
|
||||||
|
#main>ul:nth-child(1) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main>ul:nth-child(2) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-section h1 {
|
||||||
|
margin: 3rem 0 2rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-section h2 {
|
||||||
|
margin: 2rem 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
pre {
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content,
|
||||||
|
.sidebar,
|
||||||
|
.markdown-section,
|
||||||
|
body,
|
||||||
|
.search input {
|
||||||
|
background-color: rgba(243, 242, 238, 1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width:600px) {
|
||||||
|
.sidebar-toggle {
|
||||||
|
background-color: #f3f2ee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.docsify-copy-code-button {
|
||||||
|
background: #f8f8f8 !important;
|
||||||
|
color: #7a7a7a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
/*font-family: Microsoft YaHei, Source Sans Pro, Helvetica Neue, Arial, sans-serif !important;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-section>p {
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-section pre>code {
|
||||||
|
font-family: Consolas, Roboto Mono, Monaco, courier, monospace !important;
|
||||||
|
/*font-size: .9rem !important;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.anchor span {
|
||||||
|
color: rgb(66, 185, 131);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
section.cover h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body>section>div.cover-main>ul>li>a {
|
||||||
|
color: #42b983;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-section img {
|
||||||
|
box-shadow: 7px 9px 10px #aaa !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background-color: #f3f2ee !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width:600px) {
|
||||||
|
pre code {
|
||||||
|
/*box-shadow: 2px 1px 20px 2px #aaa;*/
|
||||||
|
/*border-radius: 10px !important;*/
|
||||||
|
padding-left: 20px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:600px) {
|
||||||
|
pre {
|
||||||
|
padding-left : 0px !important;
|
||||||
|
padding-right : 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-section pre {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
padding-right: 0px !important;
|
||||||
|
box-shadow: 2px 1px 20px 2px #aaa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style type="text/css">
|
||||||
|
/**
|
||||||
|
* prism.js Coy theme for JavaScript, CoffeeScript, CSS and HTML
|
||||||
|
* Based on https://github.com/tshedor/workshop-wp-theme (Example: http://workshop.kansan.com/category/sessions/basics or http://workshop.timshedor.com/category/sessions/basics);
|
||||||
|
* @author Tim Shedor
|
||||||
|
*/
|
||||||
|
|
||||||
|
code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
color: black;
|
||||||
|
background: none;
|
||||||
|
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
word-spacing: normal;
|
||||||
|
word-break: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
|
||||||
|
-webkit-hyphens: none;
|
||||||
|
-moz-hyphens: none;
|
||||||
|
-ms-hyphens: none;
|
||||||
|
hyphens: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code blocks */
|
||||||
|
pre[class*="language-"] {
|
||||||
|
position: relative;
|
||||||
|
margin: .5em 0;
|
||||||
|
overflow: visible;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"]>code {
|
||||||
|
position: relative;
|
||||||
|
border-left: 10px solid #358ccb;
|
||||||
|
box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
|
||||||
|
background-color: #fdfdfd;
|
||||||
|
background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
|
||||||
|
background-size: 3em 3em;
|
||||||
|
background-origin: content-box;
|
||||||
|
background-attachment: local;
|
||||||
|
}
|
||||||
|
|
||||||
|
code[class*="language"] {
|
||||||
|
max-height: inherit;
|
||||||
|
height: inherit;
|
||||||
|
padding: 0 1em;
|
||||||
|
display: block;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Margin bottom to accommodate shadow */
|
||||||
|
:not(pre)>code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
background-color: #fdfdfd;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
:not(pre)>code[class*="language-"] {
|
||||||
|
position: relative;
|
||||||
|
padding: .2em;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
color: #c92c2c;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
display: inline;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"]:before,
|
||||||
|
pre[class*="language-"]:after {
|
||||||
|
content: '';
|
||||||
|
z-index: -2;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0.75em;
|
||||||
|
left: 0.18em;
|
||||||
|
width: 40%;
|
||||||
|
height: 20%;
|
||||||
|
max-height: 13em;
|
||||||
|
box-shadow: 0px 13px 8px #979797;
|
||||||
|
-webkit-transform: rotate(-2deg);
|
||||||
|
-moz-transform: rotate(-2deg);
|
||||||
|
-ms-transform: rotate(-2deg);
|
||||||
|
-o-transform: rotate(-2deg);
|
||||||
|
transform: rotate(-2deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(pre)>code[class*="language-"]:after,
|
||||||
|
pre[class*="language-"]:after {
|
||||||
|
right: 0.75em;
|
||||||
|
left: auto;
|
||||||
|
-webkit-transform: rotate(2deg);
|
||||||
|
-moz-transform: rotate(2deg);
|
||||||
|
-ms-transform: rotate(2deg);
|
||||||
|
-o-transform: rotate(2deg);
|
||||||
|
transform: rotate(2deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.comment,
|
||||||
|
.token.block-comment,
|
||||||
|
.token.prolog,
|
||||||
|
.token.doctype,
|
||||||
|
.token.cdata {
|
||||||
|
color: #7D8B99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.punctuation {
|
||||||
|
color: #5F6364;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.property,
|
||||||
|
.token.tag,
|
||||||
|
.token.boolean,
|
||||||
|
.token.number,
|
||||||
|
.token.function-name,
|
||||||
|
.token.constant,
|
||||||
|
.token.symbol,
|
||||||
|
.token.deleted {
|
||||||
|
color: #c92c2c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.selector,
|
||||||
|
.token.attr-name,
|
||||||
|
.token.string,
|
||||||
|
.token.char,
|
||||||
|
.token.function,
|
||||||
|
.token.builtin,
|
||||||
|
.token.inserted {
|
||||||
|
color: #2f9c0a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.operator,
|
||||||
|
.token.entity,
|
||||||
|
.token.url,
|
||||||
|
.token.variable {
|
||||||
|
color: #a67f59;
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.atrule,
|
||||||
|
.token.attr-value,
|
||||||
|
.token.keyword,
|
||||||
|
.token.class-name {
|
||||||
|
color: #1990b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.regex,
|
||||||
|
.token.important {
|
||||||
|
color: #e90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-css .token.string,
|
||||||
|
.style .token.string {
|
||||||
|
color: #a67f59;
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.important {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.entity {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
|
.namespace {
|
||||||
|
opacity: .7;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 767px) {
|
||||||
|
|
||||||
|
pre[class*="language-"]:before,
|
||||||
|
pre[class*="language-"]:after {
|
||||||
|
bottom: 14px;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Plugin styles */
|
||||||
|
.token.tab:not(:empty):before,
|
||||||
|
.token.cr:before,
|
||||||
|
.token.lf:before {
|
||||||
|
color: #e0d7d1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Plugin styles: Line Numbers */
|
||||||
|
pre[class*="language-"].line-numbers.line-numbers {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"].line-numbers.line-numbers code {
|
||||||
|
padding-left: 3.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"].line-numbers.line-numbers .line-numbers-rows {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Plugin styles: Line Highlight */
|
||||||
|
pre[class*="language-"][data-line] {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[data-line] code {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre .line-highlight {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@ -25,7 +356,7 @@
|
|||||||
maxAge: 100,
|
maxAge: 100,
|
||||||
name: 'CS-Notes',
|
name: 'CS-Notes',
|
||||||
repo: 'https://github.com/CyC2018/CS-Notes',
|
repo: 'https://github.com/CyC2018/CS-Notes',
|
||||||
ga: 'UA-121566133-2',
|
// ga: 'UA-121566133-2',
|
||||||
search: {
|
search: {
|
||||||
paths: 'auto',
|
paths: 'auto',
|
||||||
placeholder: '🔍 Type to search ',
|
placeholder: '🔍 Type to search ',
|
||||||
@ -37,20 +368,20 @@
|
|||||||
coverpage: true
|
coverpage: true
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
<script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/docsify.min.js"></script>
|
||||||
<!-- <script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script> -->
|
<!-- <script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script> -->
|
||||||
<!-- 上面的基本不可用,无法搜索 -->
|
<!-- 上面的基本不可用,无法搜索 -->
|
||||||
<script src="https://cdn.bootcss.com/docsify/4.5.9/plugins/search.min.js"></script>
|
<script src="https://cdn.bootcss.com/docsify/4.5.9/plugins/search.min.js"></script>
|
||||||
<script src="//unpkg.com/docsify/lib/plugins/gitalk.min.js"></script>
|
<!-- <script src="//unpkg.com/docsify/lib/plugins/gitalk.min.js"></script> -->
|
||||||
<script src="//unpkg.com/gitalk/dist/gitalk.min.js"></script>
|
<!-- <script src="//unpkg.com/gitalk/dist/gitalk.min.js"></script> -->
|
||||||
<script src="//unpkg.com/docsify-copy-code"></script>
|
<script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/docsify-copy-code.min.js"></script>
|
||||||
<script src="//unpkg.com/prismjs/components/prism-java.min.js"></script>
|
<script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/prism-java.min.js"></script>
|
||||||
<script src="//unpkg.com/prismjs/components/prism-c.min.js"></script>
|
<script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/prism-c.min.js"></script>
|
||||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
<script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/prism-bash.min.js"></script>
|
||||||
<script src="//unpkg.com/prismjs/components/prism-sql.min.js"></script>
|
<script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/prism-sql.min.js"></script>
|
||||||
<script src="//unpkg.com/docsify/lib/plugins/zoom-image.min.js"></script>
|
<script src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/zoom-image.min.js"></script>
|
||||||
<!-- <script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script> -->
|
<!-- <script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script> -->
|
||||||
<script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
|
<!-- <script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script> -->
|
||||||
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
|
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const gitalk = new Gitalk({
|
const gitalk = new Gitalk({
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一、解决的问题](#一解决的问题)
|
* [一、解决的问题](#一解决的问题)
|
||||||
* [二、与虚拟机的比较](#二与虚拟机的比较)
|
* [二、与虚拟机的比较](#二与虚拟机的比较)
|
||||||
@ -13,27 +12,25 @@
|
|||||||
|
|
||||||
由于不同的机器有不同的操作系统,以及不同的库和组件,在将一个应用部署到多台机器上需要进行大量的环境配置操作。
|
由于不同的机器有不同的操作系统,以及不同的库和组件,在将一个应用部署到多台机器上需要进行大量的环境配置操作。
|
||||||
|
|
||||||
Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用 Docker 可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其他机器中。
|
Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程进行隔离,被隔离的进程独立于宿主操作系统和其它隔离的进程。使用 Docker 可以不修改应用程序代码,不需要开发人员学习特定环境下的技术,就能够将现有的应用程序部署在其它机器上。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png" width="400px"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png" width="400px"/> </div><br>
|
||||||
|
|
||||||
# 二、与虚拟机的比较
|
# 二、与虚拟机的比较
|
||||||
|
|
||||||
虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
|
虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png" width="250px"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/be608a77-7b7f-4f8e-87cc-f2237270bf69.png" width="500"/> </div><br>
|
||||||
|
|
||||||
<div align="center"> <img src="pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png" width="250"/> </div><br>
|
|
||||||
|
|
||||||
## 启动速度
|
## 启动速度
|
||||||
|
|
||||||
启动虚拟机需要启动虚拟机的操作系统,再启动应用,这个过程非常慢;
|
启动虚拟机需要先启动虚拟机的操作系统,再启动应用,这个过程非常慢;
|
||||||
|
|
||||||
而启动 Docker 相当于启动宿主操作系统上的一个进程。
|
而启动 Docker 相当于启动宿主操作系统上的一个进程。
|
||||||
|
|
||||||
## 占用资源
|
## 占用资源
|
||||||
|
|
||||||
虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU,一台机器只能开启几十个的虚拟机。
|
虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU 资源,一台机器只能开启几十个的虚拟机。
|
||||||
|
|
||||||
而 Docker 只是一个进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以开启成千上万个 Docker。
|
而 Docker 只是一个进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以开启成千上万个 Docker。
|
||||||
|
|
||||||
@ -43,11 +40,11 @@ Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程
|
|||||||
|
|
||||||
## 更容易迁移
|
## 更容易迁移
|
||||||
|
|
||||||
提供一致性的运行环境,可以在不同的机器上进行迁移,而不用担心环境变化导致无法运行。
|
提供一致性的运行环境。已经打包好的应用可以在不同的机器上进行迁移,而不用担心环境变化导致无法运行。
|
||||||
|
|
||||||
## 更容易维护
|
## 更容易维护
|
||||||
|
|
||||||
使用分层技术和镜像,使得应用可以更容易复用重复部分。复用程度越高,维护工作也越容易。
|
使用分层技术和镜像,使得应用可以更容易复用重复的部分。复用程度越高,维护工作也越容易。
|
||||||
|
|
||||||
## 更容易扩展
|
## 更容易扩展
|
||||||
|
|
||||||
@ -77,7 +74,7 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
|
|||||||
|
|
||||||
构建容器时,通过在镜像的基础上添加一个可写层(writable layer),用来保存着容器运行过程中的修改。
|
构建容器时,通过在镜像的基础上添加一个可写层(writable layer),用来保存着容器运行过程中的修改。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/docker-filesystems-busyboxrw.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/docker-filesystems-busyboxrw.png"/> </div><br>
|
||||||
|
|
||||||
# 参考资料
|
# 参考资料
|
||||||
|
|
||||||
@ -90,3 +87,9 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
|
|||||||
- [What is Docker](https://www.docker.com/what-docker)
|
- [What is Docker](https://www.docker.com/what-docker)
|
||||||
- [持续集成是什么?](http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html)
|
- [持续集成是什么?](http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [集中式与分布式](#集中式与分布式)
|
* [集中式与分布式](#集中式与分布式)
|
||||||
* [中心服务器](#中心服务器)
|
* [中心服务器](#中心服务器)
|
||||||
@ -19,7 +18,7 @@
|
|||||||
|
|
||||||
Git 属于分布式版本控制系统,而 SVN 属于集中式。
|
Git 属于分布式版本控制系统,而 SVN 属于集中式。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/fac3dfd6-1656-4329-9a80-7f6c51ef30c5_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fac3dfd6-1656-4329-9a80-7f6c51ef30c5_200.png"/> </div><br>
|
||||||
|
|
||||||
集中式版本控制只有中心服务器拥有一份代码,而分布式版本控制每个人的电脑上就有一份完整的代码。
|
集中式版本控制只有中心服务器拥有一份代码,而分布式版本控制每个人的电脑上就有一份完整的代码。
|
||||||
|
|
||||||
@ -41,45 +40,45 @@ Github 就是一个中心服务器。
|
|||||||
|
|
||||||
Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库,History 中存有所有分支,使用一个 HEAD 指针指向当前分支。
|
Git 的版本库有一个称为 Stage 的暂存区以及最后的 History 版本库,History 中存有所有分支,使用一个 HEAD 指针指向当前分支。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/0f9b9d2a-c5cc-4a3f-b138-2c1035950f39_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0f9b9d2a-c5cc-4a3f-b138-2c1035950f39_200.png"/> </div><br>
|
||||||
|
|
||||||
- git add files 把文件的修改添加到暂存区
|
- git add files 把文件的修改添加到暂存区
|
||||||
- git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了
|
- git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了
|
||||||
- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
|
- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
|
||||||
- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
|
- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
|
||||||
|
|
||||||
<div align="center"> <img src="pics/11a786f0-5e02-46a6-92f0-f302c9cf6ca3_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/11a786f0-5e02-46a6-92f0-f302c9cf6ca3_200.png" width="400px"> </div><br>
|
||||||
|
|
||||||
可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
|
可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
|
||||||
|
|
||||||
- git commit -a 直接把所有文件的修改添加到暂存区然后执行提交
|
- git commit -a 直接把所有文件的修改添加到暂存区然后执行提交
|
||||||
- git checkout HEAD -- files 取出最后一次修改,可以用来进行回滚操作
|
- git checkout HEAD -- files 取出最后一次修改,可以用来进行回滚操作
|
||||||
|
|
||||||
<div align="center"> <img src="pics/b48b9a7a-f9f8-4cf9-90f1-5cddd685b782_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b48b9a7a-f9f8-4cf9-90f1-5cddd685b782_200.png" width="600px"> </div><br>
|
||||||
|
|
||||||
# 分支实现
|
# 分支实现
|
||||||
|
|
||||||
使用指针将每个提交连接成一条时间线,HEAD 指针指向当前分支指针。
|
使用指针将每个提交连接成一条时间线,HEAD 指针指向当前分支指针。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/84d496d7-54b0-4a9b-9499-ce232057e499_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/84d496d7-54b0-4a9b-9499-ce232057e499_200.png"/> </div><br>
|
||||||
|
|
||||||
新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
|
新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/7c5bcdbf-e656-4b7c-be82-b247a3589ed5_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7c5bcdbf-e656-4b7c-be82-b247a3589ed5_200.png"/> </div><br>
|
||||||
|
|
||||||
每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。
|
每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/13783e94-b481-4aea-9fa2-9d1973abd47e_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/13783e94-b481-4aea-9fa2-9d1973abd47e_200.png"/> </div><br>
|
||||||
|
|
||||||
合并分支也只需要改变指针即可。
|
合并分支也只需要改变指针即可。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/15699a17-5a69-4fbe-852e-9d2b7cf05e80_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/15699a17-5a69-4fbe-852e-9d2b7cf05e80_200.png"/> </div><br>
|
||||||
|
|
||||||
# 冲突
|
# 冲突
|
||||||
|
|
||||||
当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。
|
当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/7e82ce01-2afb-4c15-b720-b81049c875c2_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7e82ce01-2afb-4c15-b720-b81049c875c2_200.png"/> </div><br>
|
||||||
|
|
||||||
Git 会使用 <<<<<<< ,======= ,>>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。
|
Git 会使用 <<<<<<< ,======= ,>>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。
|
||||||
|
|
||||||
@ -101,7 +100,7 @@ Creating a new branch is quick AND simple.
|
|||||||
$ git merge --no-ff -m "merge with no-ff" dev
|
$ git merge --no-ff -m "merge with no-ff" dev
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center"> <img src="pics/fa1dc552-8501-439e-b85a-3d9eac704880_200.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fa1dc552-8501-439e-b85a-3d9eac704880_200.png"/> </div><br>
|
||||||
|
|
||||||
# 分支管理策略
|
# 分支管理策略
|
||||||
|
|
||||||
@ -109,7 +108,7 @@ master 分支应该是非常稳定的,只用来发布新版本;
|
|||||||
|
|
||||||
日常开发在开发分支 dev 上进行。
|
日常开发在开发分支 dev 上进行。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br>
|
||||||
|
|
||||||
# 储藏(Stashing)
|
# 储藏(Stashing)
|
||||||
|
|
||||||
@ -149,7 +148,7 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
|
|||||||
|
|
||||||
# Git 命令一览
|
# Git 命令一览
|
||||||
|
|
||||||
<div align="center"> <img src="pics/7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br>
|
||||||
|
|
||||||
比较详细的地址:http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf
|
比较详细的地址:http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf
|
||||||
|
|
||||||
@ -159,3 +158,9 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
|
|||||||
- [图解 Git](http://marklodato.github.io/visual-git-guide/index-zh-cn.html)
|
- [图解 Git](http://marklodato.github.io/visual-git-guide/index-zh-cn.html)
|
||||||
- [廖雪峰 : Git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
|
- [廖雪峰 : Git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
|
||||||
- [Learn Git Branching](https://learngitbranching.js.org/)
|
- [Learn Git Branching](https://learngitbranching.js.org/)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一 、基础概念](#一-基础概念)
|
* [一 、基础概念](#一-基础概念)
|
||||||
* [URI](#uri)
|
* [URI](#uri)
|
||||||
@ -63,21 +62,17 @@
|
|||||||
|
|
||||||
URI 包含 URL 和 URN。
|
URI 包含 URL 和 URN。
|
||||||
|
|
||||||
- URI(Uniform Resource Identifier,统一资源标识符)
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/417cb02e-853d-4288-a36e-9161ded2c9fd_200.png" width="600px"> </div><br>
|
||||||
- URL(Uniform Resource Locator,统一资源定位符)
|
|
||||||
- URN(Uniform Resource Name,统一资源名称)
|
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1_2001550415765493.png" width="500px"> </div><br>
|
|
||||||
|
|
||||||
## 请求和响应报文
|
## 请求和响应报文
|
||||||
|
|
||||||
### 1. 请求报文
|
### 1. 请求报文
|
||||||
|
|
||||||
<div align="center"> <img src="pics/HTTP_RequestMessageExample.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/HTTP_RequestMessageExample.png" width=""/> </div><br>
|
||||||
|
|
||||||
### 2. 响应报文
|
### 2. 响应报文
|
||||||
|
|
||||||
<div align="center"> <img src="pics/HTTP_ResponseMessageExample.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/HTTP_ResponseMessageExample.png" width=""/> </div><br>
|
||||||
|
|
||||||
# 二、HTTP 方法
|
# 二、HTTP 方法
|
||||||
|
|
||||||
@ -164,7 +159,7 @@ DELETE /file.html HTTP/1.1
|
|||||||
CONNECT www.example.com:443 HTTP/1.1
|
CONNECT www.example.com:443 HTTP/1.1
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center"> <img src="pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
## TRACE
|
## TRACE
|
||||||
|
|
||||||
@ -307,7 +302,7 @@ CONNECT www.example.com:443 HTTP/1.1
|
|||||||
|
|
||||||
## 连接管理
|
## 连接管理
|
||||||
|
|
||||||
<div align="center"> <img src="pics/HTTP1_x_Connections.png" width="800"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/HTTP1_x_Connections.png" width="800"/> </div><br>
|
||||||
|
|
||||||
### 1. 短连接与长连接
|
### 1. 短连接与长连接
|
||||||
|
|
||||||
@ -636,11 +631,11 @@ HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,
|
|||||||
|
|
||||||
- 用户察觉得到正向代理的存在。
|
- 用户察觉得到正向代理的存在。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
|
||||||
|
|
||||||
- 而反向代理一般位于内部网络中,用户察觉不到。
|
- 而反向代理一般位于内部网络中,用户察觉不到。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
|
||||||
|
|
||||||
### 2. 网关
|
### 2. 网关
|
||||||
|
|
||||||
@ -662,7 +657,7 @@ HTTPS 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)
|
|||||||
|
|
||||||
通过使用 SSL,HTTPS 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
|
通过使用 SSL,HTTPS 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/ssl-offloading.jpg" width="700"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ssl-offloading.jpg" width="700"/> </div><br>
|
||||||
|
|
||||||
## 加密
|
## 加密
|
||||||
|
|
||||||
@ -673,7 +668,7 @@ HTTPS 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)
|
|||||||
- 优点:运算速度快;
|
- 优点:运算速度快;
|
||||||
- 缺点:无法安全地将密钥传输给通信方。
|
- 缺点:无法安全地将密钥传输给通信方。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
|
||||||
|
|
||||||
### 2.非对称密钥加密
|
### 2.非对称密钥加密
|
||||||
|
|
||||||
@ -686,13 +681,13 @@ HTTPS 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)
|
|||||||
- 优点:可以更安全地将公开密钥传输给通信发送方;
|
- 优点:可以更安全地将公开密钥传输给通信发送方;
|
||||||
- 缺点:运算速度慢。
|
- 缺点:运算速度慢。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
|
||||||
|
|
||||||
### 3. HTTPS 采用的加密方式
|
### 3. HTTPS 采用的加密方式
|
||||||
|
|
||||||
HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)
|
HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)
|
||||||
|
|
||||||
<div align="center"> <img src="pics/How-HTTPS-Works.png" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/How-HTTPS-Works.png" width="600"/> </div><br>
|
||||||
|
|
||||||
## 认证
|
## 认证
|
||||||
|
|
||||||
@ -704,7 +699,7 @@ HTTPS 采用混合的加密机制,使用非对称密钥加密用于传输对
|
|||||||
|
|
||||||
进行 HTTPS 通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。
|
进行 HTTPS 通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/2017-06-11-ca.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2017-06-11-ca.png" width=""/> </div><br>
|
||||||
|
|
||||||
## 完整性保护
|
## 完整性保护
|
||||||
|
|
||||||
@ -733,7 +728,7 @@ HTTP/1.x 实现简单是以牺牲性能为代价的:
|
|||||||
|
|
||||||
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。
|
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
|
||||||
|
|
||||||
在通信过程中,只会有一个 TCP 连接存在,它承载了任意数量的双向数据流(Stream)。
|
在通信过程中,只会有一个 TCP 连接存在,它承载了任意数量的双向数据流(Stream)。
|
||||||
|
|
||||||
@ -741,13 +736,13 @@ HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式
|
|||||||
- 消息(Message)是与逻辑请求或响应对应的完整的一系列帧。
|
- 消息(Message)是与逻辑请求或响应对应的完整的一系列帧。
|
||||||
- 帧(Frame)是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
|
- 帧(Frame)是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
|
||||||
|
|
||||||
## 服务端推送
|
## 服务端推送
|
||||||
|
|
||||||
HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
|
HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
|
||||||
|
|
||||||
## 首部压缩
|
## 首部压缩
|
||||||
|
|
||||||
@ -757,7 +752,7 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见
|
|||||||
|
|
||||||
不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
|
不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/_u4E0B_u8F7D.png" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/_u4E0B_u8F7D.png" width="600"/> </div><br>
|
||||||
|
|
||||||
# 八、HTTP/1.1 新特性
|
# 八、HTTP/1.1 新特性
|
||||||
|
|
||||||
@ -882,3 +877,9 @@ DELETE /idX/delete HTTP/1.1 -> Returns 404
|
|||||||
- [Symmetric vs. Asymmetric Encryption – What are differences?](https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences)
|
- [Symmetric vs. Asymmetric Encryption – What are differences?](https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences)
|
||||||
- [Web 性能优化与 HTTP/2](https://www.kancloud.cn/digest/web-performance-http2)
|
- [Web 性能优化与 HTTP/2](https://www.kancloud.cn/digest/web-performance-http2)
|
||||||
- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
|
- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一、概览](#一概览)
|
* [一、概览](#一概览)
|
||||||
* [二、磁盘操作](#二磁盘操作)
|
* [二、磁盘操作](#二磁盘操作)
|
||||||
@ -98,7 +97,7 @@ Java I/O 使用了装饰者模式来实现。以 InputStream 为例,
|
|||||||
- FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作;
|
- FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作;
|
||||||
- FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
|
- FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/c2c2b633-c03a-426e-b436-5719a194667b.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c2c2b633-c03a-426e-b436-5719a194667b.png"/> </div><br>
|
||||||
|
|
||||||
实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
|
实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
|
||||||
|
|
||||||
@ -278,7 +277,7 @@ public static void main(String[] args) throws IOException {
|
|||||||
- Socket:客户端类
|
- Socket:客户端类
|
||||||
- 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
|
- 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/f77f06b6-7359-4066-b85d-3f6c09ddf425.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f77f06b6-7359-4066-b85d-3f6c09ddf425.jpg"/> </div><br>
|
||||||
|
|
||||||
## Datagram
|
## Datagram
|
||||||
|
|
||||||
@ -340,23 +339,23 @@ I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重
|
|||||||
|
|
||||||
① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0,而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。
|
① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0,而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
|
||||||
|
|
||||||
② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5,limit 保持不变。
|
② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5,limit 保持不变。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
|
||||||
|
|
||||||
③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position,并将 position 设置为 0。
|
③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position,并将 position 设置为 0。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
|
||||||
|
|
||||||
④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
|
④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
|
||||||
|
|
||||||
⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
|
⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
|
||||||
|
|
||||||
## 文件 NIO 实例
|
## 文件 NIO 实例
|
||||||
|
|
||||||
@ -414,7 +413,7 @@ NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用
|
|||||||
|
|
||||||
应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。
|
应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/8fdbb8f5-2cf8-41dc-b5f1-99d98abb52d9.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8fdbb8f5-2cf8-41dc-b5f1-99d98abb52d9.jpg"/> </div><br>
|
||||||
|
|
||||||
### 1. 创建选择器
|
### 1. 创建选择器
|
||||||
|
|
||||||
@ -619,3 +618,9 @@ NIO 与普通 I/O 的区别主要有以下两点:
|
|||||||
- [NIO 与传统 IO 的区别](http://blog.csdn.net/shimiso/article/details/24990499)
|
- [NIO 与传统 IO 的区别](http://blog.csdn.net/shimiso/article/details/24990499)
|
||||||
- [Decorator Design Pattern](http://stg-tud.github.io/sedc/Lecture/ws13-14/5.3-Decorator.html#mode=document)
|
- [Decorator Design Pattern](http://stg-tud.github.io/sedc/Lecture/ws13-14/5.3-Decorator.html#mode=document)
|
||||||
- [Socket Multicast](http://labojava.blogspot.com/2012/12/socket-multicast.html)
|
- [Socket Multicast](http://labojava.blogspot.com/2012/12/socket-multicast.html)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一、数据类型](#一数据类型)
|
* [一、数据类型](#一数据类型)
|
||||||
* [基本类型](#基本类型)
|
* [基本类型](#基本类型)
|
||||||
@ -54,7 +53,7 @@
|
|||||||
- double/64
|
- double/64
|
||||||
- boolean/\~
|
- boolean/\~
|
||||||
|
|
||||||
boolean 只有两个值:true、false,可以使用 1 bit 来存储,但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM 并不支持 boolean 数组,而是使用 byte 数组来表示 int 数组来表示。
|
boolean 只有两个值:true、false,可以使用 1 bit 来存储,但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM 支持 boolean 数组,但是是通过读写 byte 数组来实现的。
|
||||||
|
|
||||||
- [Primitive Data Types](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)
|
- [Primitive Data Types](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)
|
||||||
- [The Java® Virtual Machine Specification](https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf)
|
- [The Java® Virtual Machine Specification](https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf)
|
||||||
@ -128,7 +127,7 @@ static {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
编译器会在自动装箱过程调用 valueOf() 方法,因此多个 Integer 实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。
|
编译器会在自动装箱过程调用 valueOf() 方法,因此多个值相同且值在缓存池范围内的 Integer 实例使用自动装箱来创建,那么就会引用相同的对象。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Integer m = 123;
|
Integer m = 123;
|
||||||
@ -190,7 +189,7 @@ value 数组被声明为 final,这意味着 value 数组初始化之后就不
|
|||||||
|
|
||||||
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
|
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/474e5579-38b1-47d2-8f76-a13ae086b039.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/474e5579-38b1-47d2-8f76-a13ae086b039.jpg"/> </div><br>
|
||||||
|
|
||||||
**3. 安全性**
|
**3. 安全性**
|
||||||
|
|
||||||
@ -669,12 +668,35 @@ SuperExtendExample.func()
|
|||||||
|
|
||||||
存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。
|
存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。
|
||||||
|
|
||||||
为了满足里式替换原则,重写有有以下两个限制:
|
为了满足里式替换原则,重写有以下三个限制:
|
||||||
|
|
||||||
- 子类方法的访问权限必须大于等于父类方法;
|
- 子类方法的访问权限必须大于等于父类方法;
|
||||||
- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
|
- 子类方法的返回类型必须是父类方法返回类型或为其子类型。
|
||||||
|
- 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。
|
||||||
|
|
||||||
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的两个限制条件。
|
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。
|
||||||
|
|
||||||
|
下面的示例中,SubClass 为 SuperClass 的子类,SubClass 重写了 SuperClass 的 func() 方法。其中:
|
||||||
|
|
||||||
|
- 子类方法访问权限为 public,大于父类的 protected。
|
||||||
|
- 子类的返回类型为 ArrayList<Integer>,是父类返回类型 List<Integer> 的子类。
|
||||||
|
- 子类抛出的异常类型为 Exception,是父类抛出异常 Throwable 的子类。
|
||||||
|
- 子类重写方法使用 @Override 注解,从而让编译器自动检查是否满足限制条件。
|
||||||
|
|
||||||
|
```java
|
||||||
|
class SuperClass {
|
||||||
|
protected List<Integer> func() throws Throwable {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubClass extends SuperClass {
|
||||||
|
@Override
|
||||||
|
public ArrayList<Integer> func() throws Exception {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
**2. 重载(Overload)**
|
**2. 重载(Overload)**
|
||||||
|
|
||||||
@ -1318,7 +1340,7 @@ Throwable 可以用来表示任何可以作为异常抛出的类,分为两种
|
|||||||
- **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
|
- **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
|
||||||
- **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。
|
- **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/PPjwP.png" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/PPjwP.png" width="600"/> </div><br>
|
||||||
|
|
||||||
- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
|
- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
|
||||||
- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
|
- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
|
||||||
@ -1395,3 +1417,9 @@ Java 注解是附加在代码中的一些元信息,用于一些工具在编译
|
|||||||
|
|
||||||
- Eckel B. Java 编程思想[M]. 机械工业出版社, 2002.
|
- Eckel B. Java 编程思想[M]. 机械工业出版社, 2002.
|
||||||
- Bloch J. Effective java[M]. Addison-Wesley Professional, 2017.
|
- Bloch J. Effective java[M]. Addison-Wesley Professional, 2017.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一、概览](#一概览)
|
* [一、概览](#一概览)
|
||||||
* [Collection](#collection)
|
* [Collection](#collection)
|
||||||
@ -25,7 +24,7 @@
|
|||||||
|
|
||||||
## Collection
|
## Collection
|
||||||
|
|
||||||
<div align="center"> <img src="pics/6_2001550476096035.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6_2001550476096035.png"/> </div><br>
|
||||||
|
|
||||||
|
|
||||||
### 1. Set
|
### 1. Set
|
||||||
@ -52,7 +51,7 @@
|
|||||||
|
|
||||||
## Map
|
## Map
|
||||||
|
|
||||||
<div align="center"> <img src="pics/2_2001550426232419.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550426232419.png"/> </div><br>
|
||||||
|
|
||||||
- TreeMap:基于红黑树实现。
|
- TreeMap:基于红黑树实现。
|
||||||
|
|
||||||
@ -67,7 +66,7 @@
|
|||||||
|
|
||||||
## 迭代器模式
|
## 迭代器模式
|
||||||
|
|
||||||
<div align="center"> <img src="pics/91aa7c29-438f-4fcc-8c63-2a75899139de.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/91aa7c29-438f-4fcc-8c63-2a75899139de.png"/> </div><br>
|
||||||
|
|
||||||
Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
|
Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
|
||||||
|
|
||||||
@ -115,7 +114,7 @@ List list = Arrays.asList(1, 2, 3);
|
|||||||
|
|
||||||
### 1. 概览
|
### 1. 概览
|
||||||
|
|
||||||
实现了 RandomAccess 接口,因此支持随机访问。这是理所当然的,因为 ArrayList 是基于数组实现的。
|
因为 ArrayList 是基于数组实现的,所以支持快速随机访问。RandomAccess接口标识着该类支持快速随机访问。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class ArrayList<E> extends AbstractList<E>
|
public class ArrayList<E> extends AbstractList<E>
|
||||||
@ -128,7 +127,7 @@ public class ArrayList<E> extends AbstractList<E>
|
|||||||
private static final int DEFAULT_CAPACITY = 10;
|
private static final int DEFAULT_CAPACITY = 10;
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center"> <img src="pics/7935be3d-c2b3-4213-90c9-1e68ec4ac4e7.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7935be3d-c2b3-4213-90c9-1e68ec4ac4e7.png"/> </div><br>
|
||||||
|
|
||||||
|
|
||||||
### 2. 扩容
|
### 2. 扩容
|
||||||
@ -392,7 +391,7 @@ transient Node<E> first;
|
|||||||
transient Node<E> last;
|
transient Node<E> last;
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center"> <img src="pics/09184175-9bf2-40ff-8a68-3b467c77216a.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/09184175-9bf2-40ff-8a68-3b467c77216a.png"/> </div><br>
|
||||||
|
|
||||||
### 2. 与 ArrayList 的比较
|
### 2. 与 ArrayList 的比较
|
||||||
|
|
||||||
@ -414,7 +413,7 @@ transient Entry[] table;
|
|||||||
|
|
||||||
Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶,一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。
|
Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶,一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1d2719d5-8d60-4c9b-a4ad-b2df7c7615af.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1d2719d5-8d60-4c9b-a4ad-b2df7c7615af.jpg"/> </div><br>
|
||||||
|
|
||||||
```java
|
```java
|
||||||
static class Entry<K,V> implements Map.Entry<K,V> {
|
static class Entry<K,V> implements Map.Entry<K,V> {
|
||||||
@ -490,7 +489,7 @@ map.put("K3", "V3");
|
|||||||
- 计算键值对所在的桶;
|
- 计算键值对所在的桶;
|
||||||
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
|
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/cf779e26-0382-4495-8463-f1e19e2e38a0.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cf779e26-0382-4495-8463-f1e19e2e38a0.jpg"/> </div><br>
|
||||||
|
|
||||||
### 3. put 操作
|
### 3. put 操作
|
||||||
|
|
||||||
@ -826,7 +825,7 @@ final Segment<K,V>[] segments;
|
|||||||
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
|
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center"> <img src="pics/deb18bdb-b3b3-4660-b778-b0823a48db12.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/deb18bdb-b3b3-4660-b778-b0823a48db12.jpg"/> </div><br>
|
||||||
|
|
||||||
### 2. size 操作
|
### 2. size 操作
|
||||||
|
|
||||||
@ -1112,3 +1111,9 @@ public final class ConcurrentCache<K, V> {
|
|||||||
- [Java 集合细节(二):asList 的缺陷](http://wiki.jikexueyuan.com/project/java-enhancement/java-thirtysix.html)
|
- [Java 集合细节(二):asList 的缺陷](http://wiki.jikexueyuan.com/project/java-enhancement/java-thirtysix.html)
|
||||||
- [Java Collection Framework – The LinkedList Class](http://javaconceptoftheday.com/java-collection-framework-linkedlist-class/)
|
- [Java Collection Framework – The LinkedList Class](http://javaconceptoftheday.com/java-collection-framework-linkedlist-class/)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
<!-- GFM-TOC -->
|
||||||
<!-- GFM-TOC -->
|
|
||||||
* [一、线程状态转换](#一线程状态转换)
|
* [一、线程状态转换](#一线程状态转换)
|
||||||
* [新建(New)](#新建new)
|
* [新建(New)](#新建new)
|
||||||
* [可运行(Runnable)](#可运行runnable)
|
* [可运行(Runnable)](#可运行runnable)
|
||||||
@ -62,7 +61,7 @@
|
|||||||
|
|
||||||
# 一、线程状态转换
|
# 一、线程状态转换
|
||||||
|
|
||||||
<div align="center"> <img src="pics/96706658-b3f8-4f32-8eb3-dcb7fc8d5381.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/96706658-b3f8-4f32-8eb3-dcb7fc8d5381.jpg"/> </div><br>
|
||||||
|
|
||||||
## 新建(New)
|
## 新建(New)
|
||||||
|
|
||||||
@ -265,7 +264,7 @@ public void run() {
|
|||||||
|
|
||||||
## InterruptedException
|
## InterruptedException
|
||||||
|
|
||||||
通过调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞、限期等待或者无限期等待状态,那么就会抛出 InterruptedException,从而提前结束该线程。但是不能中断 I/O 阻塞和 synchronized 锁阻塞。
|
通过调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞、有限期等待或者无限期等待状态,那么就会抛出 InterruptedException,从而提前结束该线程。但是不能中断 I/O 阻塞和 synchronized 锁阻塞。
|
||||||
|
|
||||||
对于以下代码,在 main() 中启动一个线程之后再中断它,由于线程中调用了 Thread.sleep() 方法,因此会抛出一个 InterruptedException,从而提前结束线程,不执行之后的语句。
|
对于以下代码,在 main() 中启动一个线程之后再中断它,由于线程中调用了 Thread.sleep() 方法,因此会抛出一个 InterruptedException,从而提前结束线程,不执行之后的语句。
|
||||||
|
|
||||||
@ -737,7 +736,7 @@ java.util.concurrent(J.U.C)大大提高了并发性能,AQS 被认为是 J.
|
|||||||
|
|
||||||
维护了一个计数器 cnt,每次调用 countDown() 方法会让计数器的值减 1,减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
|
维护了一个计数器 cnt,每次调用 countDown() 方法会让计数器的值减 1,减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/912a7886-fb1d-4a05-902d-ab17ea17007f.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/912a7886-fb1d-4a05-902d-ab17ea17007f.jpg"/> </div><br>
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class CountdownLatchExample {
|
public class CountdownLatchExample {
|
||||||
@ -786,7 +785,7 @@ public CyclicBarrier(int parties) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center"> <img src="pics/f944fac3-482b-4ca3-9447-17aec4a3cca0.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f944fac3-482b-4ca3-9447-17aec4a3cca0.png"/> </div><br>
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class CyclicBarrierExample {
|
public class CyclicBarrierExample {
|
||||||
@ -1023,7 +1022,7 @@ public class ForkJoinPool extends AbstractExecutorService
|
|||||||
|
|
||||||
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列,用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务,避免和队列所属线程发生竞争。例如下图中,Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务,Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。
|
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列,用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务,避免和队列所属线程发生竞争。例如下图中,Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务,Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/e19452dd-220a-4a6b-bcb0-91ad5e5c4706.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e19452dd-220a-4a6b-bcb0-91ad5e5c4706.png"/> </div><br>
|
||||||
|
|
||||||
# 九、线程不安全示例
|
# 九、线程不安全示例
|
||||||
|
|
||||||
@ -1078,19 +1077,19 @@ Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,
|
|||||||
|
|
||||||
加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
|
加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/d2a12961-2b36-4463-b017-ca46a3308b8e.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/d2a12961-2b36-4463-b017-ca46a3308b8e.png"/> </div><br>
|
||||||
|
|
||||||
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
|
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
|
||||||
|
|
||||||
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
|
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/8162aebb-8fd2-4620-b771-e65751ba7e41.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8162aebb-8fd2-4620-b771-e65751ba7e41.png"/> </div><br>
|
||||||
|
|
||||||
## 内存间交互操作
|
## 内存间交互操作
|
||||||
|
|
||||||
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
|
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/b6a7e8af-91bf-44b2-8874-ccc6d9d52afc.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b6a7e8af-91bf-44b2-8874-ccc6d9d52afc.jpg"/> </div><br>
|
||||||
|
|
||||||
- read:把一个变量的值从主内存传输到工作内存中
|
- read:把一个变量的值从主内存传输到工作内存中
|
||||||
- load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
|
- load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
|
||||||
@ -1113,11 +1112,11 @@ Java 内存模型保证了 read、load、use、assign、store、write、lock 和
|
|||||||
|
|
||||||
下图演示了两个线程同时对 cnt 进行操作,load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存,T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。
|
下图演示了两个线程同时对 cnt 进行操作,load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存,T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/847b9ba1-b3cd-4e52-aa72-dee0222ae09f.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/847b9ba1-b3cd-4e52-aa72-dee0222ae09f.jpg"/> </div><br>
|
||||||
|
|
||||||
AtomicInteger 能保证多个线程修改的原子性。
|
AtomicInteger 能保证多个线程修改的原子性。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/3144015c-dcfb-47ac-94a5-bab3b78b0f14.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3144015c-dcfb-47ac-94a5-bab3b78b0f14.jpg"/> </div><br>
|
||||||
|
|
||||||
使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:
|
使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:
|
||||||
|
|
||||||
@ -1199,7 +1198,7 @@ public static void main(String[] args) throws InterruptedException {
|
|||||||
|
|
||||||
可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。
|
可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。
|
||||||
|
|
||||||
主要有有三种实现可见性的方式:
|
主要有三种实现可见性的方式:
|
||||||
|
|
||||||
- volatile
|
- volatile
|
||||||
- synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
|
- synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
|
||||||
@ -1225,7 +1224,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
|
|||||||
|
|
||||||
在一个线程内,在程序前面的操作先行发生于后面的操作。
|
在一个线程内,在程序前面的操作先行发生于后面的操作。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/94414cd3-5db9-4aca-a2af-539140955c62.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/94414cd3-5db9-4aca-a2af-539140955c62.jpg"/> </div><br>
|
||||||
|
|
||||||
### 2. 管程锁定规则
|
### 2. 管程锁定规则
|
||||||
|
|
||||||
@ -1233,7 +1232,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
|
|||||||
|
|
||||||
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
|
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/de9d8133-4c98-4e07-b39c-302e162784ea.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/de9d8133-4c98-4e07-b39c-302e162784ea.jpg"/> </div><br>
|
||||||
|
|
||||||
### 3. volatile 变量规则
|
### 3. volatile 变量规则
|
||||||
|
|
||||||
@ -1241,7 +1240,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
|
|||||||
|
|
||||||
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
|
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/5e6e05d6-1028-4f5c-b9bd-1a40b90d6070.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5e6e05d6-1028-4f5c-b9bd-1a40b90d6070.jpg"/> </div><br>
|
||||||
|
|
||||||
### 4. 线程启动规则
|
### 4. 线程启动规则
|
||||||
|
|
||||||
@ -1249,7 +1248,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
|
|||||||
|
|
||||||
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
|
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/bc5826f5-014d-47b4-9a76-d86b80968643.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bc5826f5-014d-47b4-9a76-d86b80968643.jpg"/> </div><br>
|
||||||
|
|
||||||
### 5. 线程加入规则
|
### 5. 线程加入规则
|
||||||
|
|
||||||
@ -1257,7 +1256,7 @@ Thread 对象的 start() 方法调用先行发生于此线程的每一个动作
|
|||||||
|
|
||||||
Thread 对象的结束先行发生于 join() 方法返回。
|
Thread 对象的结束先行发生于 join() 方法返回。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/54e6d499-80df-488e-aa7e-081766c41538.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/54e6d499-80df-488e-aa7e-081766c41538.jpg"/> </div><br>
|
||||||
|
|
||||||
### 6. 线程中断规则
|
### 6. 线程中断规则
|
||||||
|
|
||||||
@ -1475,7 +1474,7 @@ public class ThreadLocalExample1 {
|
|||||||
|
|
||||||
它所对应的底层结构图为:
|
它所对应的底层结构图为:
|
||||||
|
|
||||||
<div align="center"> <img src="pics/066f9c11-0154-42c3-8685-301a70e9bd39.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/066f9c11-0154-42c3-8685-301a70e9bd39.jpg"/> </div><br>
|
||||||
|
|
||||||
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。
|
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。
|
||||||
|
|
||||||
@ -1574,21 +1573,21 @@ public static String concatString(String s1, String s2, String s3) {
|
|||||||
|
|
||||||
## 轻量级锁
|
## 轻量级锁
|
||||||
|
|
||||||
JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:无锁状态(unlocked)、偏向锁状态(biasble)、轻量级锁状态(lightweight locked)和重量级锁状态(inflated)。
|
JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:无锁状态(unlocked)、偏向锁状态(biased)、轻量级锁状态(lightweight locked)和重量级锁状态(inflated)。
|
||||||
|
|
||||||
以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。
|
以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
|
||||||
|
|
||||||
下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象,包含了 Mark Word 和其它信息。
|
下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象,包含了 Mark Word 和其它信息。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
|
||||||
|
|
||||||
轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。
|
轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。
|
||||||
|
|
||||||
当尝试获取一个锁对象时,如果锁对象标记为 0 01,说明锁对象的锁未锁定(unlocked)状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record,然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00,表示该对象处于轻量级锁状态。
|
当尝试获取一个锁对象时,如果锁对象标记为 0 01,说明锁对象的锁未锁定(unlocked)状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record,然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00,表示该对象处于轻量级锁状态。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
|
||||||
|
|
||||||
如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。
|
如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。
|
||||||
|
|
||||||
@ -1600,7 +1599,7 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
|
|||||||
|
|
||||||
当有另外一个线程去尝试获取这个锁对象时,偏向状态就宣告结束,此时撤销偏向(Revoke Bias)后恢复到未锁定状态或者轻量级锁状态。
|
当有另外一个线程去尝试获取这个锁对象时,偏向状态就宣告结束,此时撤销偏向(Revoke Bias)后恢复到未锁定状态或者轻量级锁状态。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
|
||||||
|
|
||||||
# 十三、多线程开发良好的实践
|
# 十三、多线程开发良好的实践
|
||||||
|
|
||||||
@ -1635,3 +1634,9 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
|
|||||||
- [JAVA FORK JOIN EXAMPLE](http://www.javacreed.com/java-fork-join-example/ "Java Fork Join Example")
|
- [JAVA FORK JOIN EXAMPLE](http://www.javacreed.com/java-fork-join-example/ "Java Fork Join Example")
|
||||||
- [聊聊并发(八)——Fork/Join 框架介绍](http://ifeve.com/talk-concurrency-forkjoin/)
|
- [聊聊并发(八)——Fork/Join 框架介绍](http://ifeve.com/talk-concurrency-forkjoin/)
|
||||||
- [Eliminating SynchronizationRelated Atomic Operations with Biased Locking and Bulk Rebiasing](http://www.oracle.com/technetwork/java/javase/tech/biasedlocking-oopsla2006-preso-150106.pdf)
|
- [Eliminating SynchronizationRelated Atomic Operations with Biased Locking and Bulk Rebiasing](http://www.oracle.com/technetwork/java/javase/tech/biasedlocking-oopsla2006-preso-150106.pdf)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一、运行时数据区域](#一运行时数据区域)
|
* [一、运行时数据区域](#一运行时数据区域)
|
||||||
* [程序计数器](#程序计数器)
|
* [程序计数器](#程序计数器)
|
||||||
@ -31,7 +30,7 @@
|
|||||||
|
|
||||||
# 一、运行时数据区域
|
# 一、运行时数据区域
|
||||||
|
|
||||||
<div align="center"> <img src="pics/83e9c5ed-35a1-41fd-b0dd-ce571969b5f3_200.png" width="500px"> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/83e9c5ed-35a1-41fd-b0dd-ce571969b5f3_200.png" width="500px"> </div><br>
|
||||||
|
|
||||||
## 程序计数器
|
## 程序计数器
|
||||||
|
|
||||||
@ -41,7 +40,7 @@
|
|||||||
|
|
||||||
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
|
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/ff5b89ac-798e-4fbc-b0ce-da2fc2358570.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ff5b89ac-798e-4fbc-b0ce-da2fc2358570.jpg"/> </div><br>
|
||||||
|
|
||||||
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
|
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
|
||||||
|
|
||||||
@ -60,7 +59,7 @@ java -Xss512M HackTheJava
|
|||||||
|
|
||||||
本地方法一般是用其它语言(C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
|
本地方法一般是用其它语言(C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1_2001550547261811.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1_2001550547261811.png"/> </div><br>
|
||||||
|
|
||||||
## 堆
|
## 堆
|
||||||
|
|
||||||
@ -123,10 +122,15 @@ public class Test {
|
|||||||
Test b = new Test();
|
Test b = new Test();
|
||||||
a.instance = b;
|
a.instance = b;
|
||||||
b.instance = a;
|
b.instance = a;
|
||||||
|
a = null;
|
||||||
|
b = null;
|
||||||
|
doSomething();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
在上述代码中,a 与 b 引用的对象实例互相持有了对象的引用,因此当我们把对 a 对象与 b 对象的引用去除之后,由于两个对象还存在互相之间的引用,导致两个 Test 对象无法被回收。
|
||||||
|
|
||||||
### 2. 可达性分析算法
|
### 2. 可达性分析算法
|
||||||
|
|
||||||
以 GC Roots 为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收。
|
以 GC Roots 为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收。
|
||||||
@ -138,7 +142,7 @@ Java 虚拟机使用该算法来判断对象是否可被回收,GC Roots 一般
|
|||||||
- 方法区中类静态属性引用的对象
|
- 方法区中类静态属性引用的对象
|
||||||
- 方法区中的常量引用的对象
|
- 方法区中的常量引用的对象
|
||||||
|
|
||||||
<div align="center"> <img src="pics/6dd28bfc-6ef7-47cb-af50-a681ebc1bbaa.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6dd28bfc-6ef7-47cb-af50-a681ebc1bbaa.png"/> </div><br>
|
||||||
|
|
||||||
### 3. 方法区的回收
|
### 3. 方法区的回收
|
||||||
|
|
||||||
@ -210,7 +214,7 @@ obj = null;
|
|||||||
|
|
||||||
```java
|
```java
|
||||||
Object obj = new Object();
|
Object obj = new Object();
|
||||||
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
|
PhantomReference<Object> pf = new PhantomReference<Object>(obj, null);
|
||||||
obj = null;
|
obj = null;
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -218,7 +222,7 @@ obj = null;
|
|||||||
|
|
||||||
### 1. 标记 - 清除
|
### 1. 标记 - 清除
|
||||||
|
|
||||||
<div align="center"> <img src="pics/3_2001550547558008.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/3_2001550547558008.png"/> </div><br>
|
||||||
|
|
||||||
|
|
||||||
标记要回收的对象,然后清除。
|
标记要回收的对象,然后清除。
|
||||||
@ -231,14 +235,22 @@ obj = null;
|
|||||||
### 2. 标记 - 整理
|
### 2. 标记 - 整理
|
||||||
|
|
||||||
|
|
||||||
<div align="center"> <img src="pics/2_2001550547456403.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2_2001550547456403.png"/> </div><br>
|
||||||
|
|
||||||
|
|
||||||
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
|
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
|
||||||
|
|
||||||
|
优点:
|
||||||
|
|
||||||
|
- 不会产生内存碎片
|
||||||
|
|
||||||
|
不足:
|
||||||
|
|
||||||
|
- 在标记-清除的基础上还需进行对象的移动,成本相对较高
|
||||||
|
|
||||||
### 3. 复制
|
### 3. 复制
|
||||||
|
|
||||||
<div align="center"> <img src="pics/4_2001550547640585.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4_2001550547640585.png"/> </div><br>
|
||||||
|
|
||||||
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
|
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
|
||||||
|
|
||||||
@ -259,7 +271,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1,保证了内
|
|||||||
|
|
||||||
## 垃圾收集器
|
## 垃圾收集器
|
||||||
|
|
||||||
<div align="center"> <img src="pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。
|
以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。
|
||||||
|
|
||||||
@ -268,7 +280,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1,保证了内
|
|||||||
|
|
||||||
### 1. Serial 收集器
|
### 1. Serial 收集器
|
||||||
|
|
||||||
<div align="center"> <img src="pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
Serial 翻译为串行,也就是说它以串行的方式执行。
|
Serial 翻译为串行,也就是说它以串行的方式执行。
|
||||||
|
|
||||||
@ -280,7 +292,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
|
|||||||
|
|
||||||
### 2. ParNew 收集器
|
### 2. ParNew 收集器
|
||||||
|
|
||||||
<div align="center"> <img src="pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
它是 Serial 收集器的多线程版本。
|
它是 Serial 收集器的多线程版本。
|
||||||
|
|
||||||
@ -300,7 +312,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
|
|||||||
|
|
||||||
### 4. Serial Old 收集器
|
### 4. Serial Old 收集器
|
||||||
|
|
||||||
<div align="center"> <img src="pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
是 Serial 收集器的老年代版本,也是给 Client 场景下的虚拟机使用。如果用在 Server 场景下,它有两大用途:
|
是 Serial 收集器的老年代版本,也是给 Client 场景下的虚拟机使用。如果用在 Server 场景下,它有两大用途:
|
||||||
|
|
||||||
@ -309,7 +321,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
|
|||||||
|
|
||||||
### 5. Parallel Old 收集器
|
### 5. Parallel Old 收集器
|
||||||
|
|
||||||
<div align="center"> <img src="pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
是 Parallel Scavenge 收集器的老年代版本。
|
是 Parallel Scavenge 收集器的老年代版本。
|
||||||
|
|
||||||
@ -317,7 +329,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
|
|||||||
|
|
||||||
### 6. CMS 收集器
|
### 6. CMS 收集器
|
||||||
|
|
||||||
<div align="center"> <img src="pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。
|
CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。
|
||||||
|
|
||||||
@ -342,17 +354,17 @@ G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,
|
|||||||
|
|
||||||
堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。
|
堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
|
||||||
|
|
||||||
G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。
|
G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
|
||||||
|
|
||||||
通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。
|
通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。
|
||||||
|
|
||||||
每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set,在做可达性分析的时候就可以避免全堆扫描。
|
每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set,在做可达性分析的时候就可以避免全堆扫描。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
如果不计算维护 Remembered Set 的操作,G1 收集器的运作大致可划分为以下几个步骤:
|
如果不计算维护 Remembered Set 的操作,G1 收集器的运作大致可划分为以下几个步骤:
|
||||||
|
|
||||||
@ -370,7 +382,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
|
|||||||
|
|
||||||
## Minor GC 和 Full GC
|
## Minor GC 和 Full GC
|
||||||
|
|
||||||
- Minor GC:回收新生代上,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快。
|
- Minor GC:回收新生代,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快。
|
||||||
|
|
||||||
- Full GC:回收老年代和新生代,老年代对象其存活时间长,因此 Full GC 很少执行,执行速度会比 Minor GC 慢很多。
|
- Full GC:回收老年代和新生代,老年代对象其存活时间长,因此 Full GC 很少执行,执行速度会比 Minor GC 慢很多。
|
||||||
|
|
||||||
@ -378,7 +390,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
|
|||||||
|
|
||||||
### 1. 对象优先在 Eden 分配
|
### 1. 对象优先在 Eden 分配
|
||||||
|
|
||||||
大多数情况下,对象在新生代 Eden 区分配,当 Eden 区空间不够时,发起 Minor GC。
|
大多数情况下,对象在新生代 Eden 上分配,当 Eden 空间不够时,发起 Minor GC。
|
||||||
|
|
||||||
### 2. 大对象直接进入老年代
|
### 2. 大对象直接进入老年代
|
||||||
|
|
||||||
@ -386,7 +398,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
|
|||||||
|
|
||||||
经常出现大对象会提前触发垃圾收集以获取足够的连续空间分配给大对象。
|
经常出现大对象会提前触发垃圾收集以获取足够的连续空间分配给大对象。
|
||||||
|
|
||||||
-XX:PretenureSizeThreshold,大于此值的对象直接在老年代分配,避免在 Eden 区和 Survivor 区之间的大量内存复制。
|
-XX:PretenureSizeThreshold,大于此值的对象直接在老年代分配,避免在 Eden 和 Survivor 之间的大量内存复制。
|
||||||
|
|
||||||
### 3. 长期存活的对象进入老年代
|
### 3. 长期存活的对象进入老年代
|
||||||
|
|
||||||
@ -396,13 +408,13 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
|
|||||||
|
|
||||||
### 4. 动态对象年龄判定
|
### 4. 动态对象年龄判定
|
||||||
|
|
||||||
虚拟机并不是永远地要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄。
|
虚拟机并不是永远要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄。
|
||||||
|
|
||||||
### 5. 空间分配担保
|
### 5. 空间分配担保
|
||||||
|
|
||||||
在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果条件成立的话,那么 Minor GC 可以确认是安全的。
|
在发生 Minor GC 之前,虚拟机先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果条件成立的话,那么 Minor GC 可以确认是安全的。
|
||||||
|
|
||||||
如果不成立的话虚拟机会查看 HandlePromotionFailure 设置值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC;如果小于,或者 HandlePromotionFailure 设置不允许冒险,那么就要进行一次 Full GC。
|
如果不成立的话虚拟机会查看 HandlePromotionFailure 的值是否允许担保失败,如果允许那么就会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次 Minor GC;如果小于,或者 HandlePromotionFailure 的值不允许冒险,那么就要进行一次 Full GC。
|
||||||
|
|
||||||
## Full GC 的触发条件
|
## Full GC 的触发条件
|
||||||
|
|
||||||
@ -420,7 +432,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
|
|||||||
|
|
||||||
### 3. 空间分配担保失败
|
### 3. 空间分配担保失败
|
||||||
|
|
||||||
使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。具体内容请参考上面的第五小节。
|
使用复制算法的 Minor GC 需要老年代的内存空间作担保,如果担保失败会执行一次 Full GC。具体内容请参考上面的第 5 小节。
|
||||||
|
|
||||||
### 4. JDK 1.7 及以前的永久代空间不足
|
### 4. JDK 1.7 及以前的永久代空间不足
|
||||||
|
|
||||||
@ -436,11 +448,11 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
|
|||||||
|
|
||||||
# 四、类加载机制
|
# 四、类加载机制
|
||||||
|
|
||||||
类是在运行期间第一次使用时动态加载的,而不是一次性加载。因为如果一次性加载,那么会占用很多的内存。
|
类是在运行期间第一次使用时动态加载的,而不是一次性加载所有类。因为如果一次性加载,那么会占用很多的内存。
|
||||||
|
|
||||||
## 类的生命周期
|
## 类的生命周期
|
||||||
|
|
||||||
<div align="center"> <img src="pics/303873db-0d11-4683-a43c-f319b7aef2b6.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/303873db-0d11-4683-a43c-f319b7aef2b6.jpg"/> </div><br>
|
||||||
|
|
||||||
包括以下 7 个阶段:
|
包括以下 7 个阶段:
|
||||||
|
|
||||||
@ -510,8 +522,6 @@ public static final int value = 123;
|
|||||||
|
|
||||||
初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段是虚拟机执行类构造器 <clinit>() 方法的过程。在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
|
初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段是虚拟机执行类构造器 <clinit>() 方法的过程。在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
|
||||||
|
|
||||||
在准备阶段,已经为类变量分配了系统所需的初始值,并且在初始化阶段,根据程序员通过程序进行的主观计划来初始化类变量和其他资源。
|
|
||||||
|
|
||||||
<clinit>() 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
|
<clinit>() 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@ -613,9 +623,9 @@ System.out.println(ConstClass.HELLOWORLD);
|
|||||||
|
|
||||||
应用程序是由三种类加载器互相配合从而实现类加载,除此之外还可以加入自己定义的类加载器。
|
应用程序是由三种类加载器互相配合从而实现类加载,除此之外还可以加入自己定义的类加载器。
|
||||||
|
|
||||||
下图展示了类加载器之间的层次关系,称为双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其它的类加载器都要有自己的父类加载器。类加载器之间的父子关系一般通过组合关系(Composition)来实现,而不是继承关系(Inheritance)。
|
下图展示了类加载器之间的层次关系,称为双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其它的类加载器都要有自己的父类加载器。这里的父子关系一般通过组合关系(Composition)来实现,而不是继承关系(Inheritance)。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/805812fa-6ab5-4b8f-a0aa-3bdcadaa829d.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/805812fa-6ab5-4b8f-a0aa-3bdcadaa829d.png"/> </div><br>
|
||||||
|
|
||||||
### 1. 工作过程
|
### 1. 工作过程
|
||||||
|
|
||||||
@ -677,7 +687,7 @@ public abstract class ClassLoader {
|
|||||||
|
|
||||||
## 自定义类加载器实现
|
## 自定义类加载器实现
|
||||||
|
|
||||||
FileSystemClassLoader 是自定义类加载器,继承自 java.lang.ClassLoader,用于加载文件系统上的类。它首先根据类的全名在文件系统上查找类的字节代码文件(.class 文件),然后读取该文件内容,最后通过 defineClass() 方法来把这些字节代码转换成 java.lang.Class 类的实例。
|
以下代码中的 FileSystemClassLoader 是自定义类加载器,继承自 java.lang.ClassLoader,用于加载文件系统上的类。它首先根据类的全名在文件系统上查找类的字节代码文件(.class 文件),然后读取该文件内容,最后通过 defineClass() 方法来把这些字节代码转换成 java.lang.Class 类的实例。
|
||||||
|
|
||||||
java.lang.ClassLoader 的 loadClass() 实现了双亲委派模型的逻辑,自定义类加载器一般不去重写它,但是需要重写 findClass() 方法。
|
java.lang.ClassLoader 的 loadClass() 实现了双亲委派模型的逻辑,自定义类加载器一般不去重写它,但是需要重写 findClass() 方法。
|
||||||
|
|
||||||
@ -740,3 +750,9 @@ public class FileSystemClassLoader extends ClassLoader {
|
|||||||
- [深入探讨 Java 类加载器](https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#code6)
|
- [深入探讨 Java 类加载器](https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html#code6)
|
||||||
- [Guide to WeakHashMap in Java](http://www.baeldung.com/java-weakhashmap)
|
- [Guide to WeakHashMap in Java](http://www.baeldung.com/java-weakhashmap)
|
||||||
- [Tomcat example source code file (ConcurrentCache.java)](https://alvinalexander.com/java/jwarehouse/apache-tomcat-6.0.16/java/org/apache/el/util/ConcurrentCache.java.shtml)
|
- [Tomcat example source code file (ConcurrentCache.java)](https://alvinalexander.com/java/jwarehouse/apache-tomcat-6.0.16/java/org/apache/el/util/ConcurrentCache.java.shtml)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
300
docs/notes/Leetcode 题解 - 二分查找.md
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [原理](#原理)
|
||||||
|
* [1. 正常实现](#1-正常实现)
|
||||||
|
* [2. 时间复杂度](#2-时间复杂度)
|
||||||
|
* [3. m 计算](#3-m-计算)
|
||||||
|
* [4. 返回值](#4-返回值)
|
||||||
|
* [5. 变种](#5-变种)
|
||||||
|
* [例题](#例题)
|
||||||
|
* [1. 求开方](#1-求开方)
|
||||||
|
* [2. 大于给定元素的最小元素](#2-大于给定元素的最小元素)
|
||||||
|
* [3. 有序数组的 Single Element](#3-有序数组的-single-element)
|
||||||
|
* [4. 第一个错误的版本](#4-第一个错误的版本)
|
||||||
|
* [5. 旋转数组的最小数字](#5-旋转数组的最小数字)
|
||||||
|
* [6. 查找区间](#6-查找区间)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 原理
|
||||||
|
|
||||||
|
## 1. 正常实现
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int binarySearch(int[] nums, int key) {
|
||||||
|
int l = 0, h = nums.length - 1;
|
||||||
|
while (l <= h) {
|
||||||
|
int m = l + (h - l) / 2;
|
||||||
|
if (nums[m] == key) {
|
||||||
|
return m;
|
||||||
|
} else if (nums[m] > key) {
|
||||||
|
h = m - 1;
|
||||||
|
} else {
|
||||||
|
l = m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 时间复杂度
|
||||||
|
|
||||||
|
二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度为 O(logN)。
|
||||||
|
|
||||||
|
## 3. m 计算
|
||||||
|
|
||||||
|
有两种计算中值 m 的方式:
|
||||||
|
|
||||||
|
- m = (l + h) / 2
|
||||||
|
- m = l + (h - l) / 2
|
||||||
|
|
||||||
|
l + h 可能出现加法溢出,最好使用第二种方式。
|
||||||
|
|
||||||
|
## 4. 返回值
|
||||||
|
|
||||||
|
循环退出时如果仍然没有查找到 key,那么表示查找失败。可以有两种返回值:
|
||||||
|
|
||||||
|
- -1:以一个错误码表示没有查找到 key
|
||||||
|
- l:将 key 插入到 nums 中的正确位置
|
||||||
|
|
||||||
|
## 5. 变种
|
||||||
|
|
||||||
|
二分查找可以有很多变种,变种实现要注意边界值的判断。例如在一个有重复元素的数组中查找 key 的最左位置的实现如下:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int binarySearch(int[] nums, int key) {
|
||||||
|
int l = 0, h = nums.length - 1;
|
||||||
|
while (l < h) {
|
||||||
|
int m = l + (h - l) / 2;
|
||||||
|
if (nums[m] >= key) {
|
||||||
|
h = m;
|
||||||
|
} else {
|
||||||
|
l = m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
该实现和正常实现有以下不同:
|
||||||
|
|
||||||
|
- 循环条件为 l < h
|
||||||
|
- h 的赋值表达式为 h = m
|
||||||
|
- 最后返回 l 而不是 -1
|
||||||
|
|
||||||
|
在 nums[m] >= key 的情况下,可以推导出最左 key 位于 [l, m] 区间中,这是一个闭区间。h 的赋值表达式为 h = m,因为 m 位置也可能是解。
|
||||||
|
|
||||||
|
在 h 的赋值表达式为 h = mid 的情况下,如果循环条件为 l <= h,那么会出现循环无法退出的情况,因此循环条件只能是 l < h。以下演示了循环条件为 l <= h 时循环无法退出的情况:
|
||||||
|
|
||||||
|
```text
|
||||||
|
nums = {0, 1, 2}, key = 1
|
||||||
|
l m h
|
||||||
|
0 1 2 nums[m] >= key
|
||||||
|
0 0 1 nums[m] < key
|
||||||
|
1 1 1 nums[m] >= key
|
||||||
|
1 1 1 nums[m] >= key
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
当循环体退出时,不表示没有查找到 key,因此最后返回的结果不应该为 -1。为了验证有没有查找到,需要在调用端判断一下返回位置上的值和 key 是否相等。
|
||||||
|
|
||||||
|
# 例题
|
||||||
|
|
||||||
|
## 1. 求开方
|
||||||
|
|
||||||
|
[69. Sqrt(x) (Easy)](https://leetcode.com/problems/sqrtx/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: 4
|
||||||
|
Output: 2
|
||||||
|
|
||||||
|
Input: 8
|
||||||
|
Output: 2
|
||||||
|
Explanation: The square root of 8 is 2.82842..., and since we want to return an integer, the decimal part will be truncated.
|
||||||
|
```
|
||||||
|
|
||||||
|
一个数 x 的开方 sqrt 一定在 0 \~ x 之间,并且满足 sqrt == x / sqrt。可以利用二分查找在 0 \~ x 之间查找 sqrt。
|
||||||
|
|
||||||
|
对于 x = 8,它的开方是 2.82842...,最后应该返回 2 而不是 3。在循环条件为 l <= h 并且循环退出时,h 总是比 l 小 1,也就是说 h = 2,l = 3,因此最后的返回值应该为 h 而不是 l。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int mySqrt(int x) {
|
||||||
|
if (x <= 1) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
int l = 1, h = x;
|
||||||
|
while (l <= h) {
|
||||||
|
int mid = l + (h - l) / 2;
|
||||||
|
int sqrt = x / mid;
|
||||||
|
if (sqrt == mid) {
|
||||||
|
return mid;
|
||||||
|
} else if (mid > sqrt) {
|
||||||
|
h = mid - 1;
|
||||||
|
} else {
|
||||||
|
l = mid + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 大于给定元素的最小元素
|
||||||
|
|
||||||
|
[744. Find Smallest Letter Greater Than Target (Easy)](https://leetcode.com/problems/find-smallest-letter-greater-than-target/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input:
|
||||||
|
letters = ["c", "f", "j"]
|
||||||
|
target = "d"
|
||||||
|
Output: "f"
|
||||||
|
|
||||||
|
Input:
|
||||||
|
letters = ["c", "f", "j"]
|
||||||
|
target = "k"
|
||||||
|
Output: "c"
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:给定一个有序的字符数组 letters 和一个字符 target,要求找出 letters 中大于 target 的最小字符,如果找不到就返回第 1 个字符。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public char nextGreatestLetter(char[] letters, char target) {
|
||||||
|
int n = letters.length;
|
||||||
|
int l = 0, h = n - 1;
|
||||||
|
while (l <= h) {
|
||||||
|
int m = l + (h - l) / 2;
|
||||||
|
if (letters[m] <= target) {
|
||||||
|
l = m + 1;
|
||||||
|
} else {
|
||||||
|
h = m - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l < n ? letters[l] : letters[0];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 有序数组的 Single Element
|
||||||
|
|
||||||
|
[540. Single Element in a Sorted Array (Medium)](https://leetcode.com/problems/single-element-in-a-sorted-array/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [1, 1, 2, 3, 3, 4, 4, 8, 8]
|
||||||
|
Output: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:一个有序数组只有一个数不出现两次,找出这个数。要求以 O(logN) 时间复杂度进行求解。
|
||||||
|
|
||||||
|
令 index 为 Single Element 在数组中的位置。如果 m 为偶数,并且 m + 1 < index,那么 nums[m] == nums[m + 1];m + 1 >= index,那么 nums[m] != nums[m + 1]。
|
||||||
|
|
||||||
|
从上面的规律可以知道,如果 nums[m] == nums[m + 1],那么 index 所在的数组位置为 [m + 2, h],此时令 l = m + 2;如果 nums[m] != nums[m + 1],那么 index 所在的数组位置为 [l, m],此时令 h = m。
|
||||||
|
|
||||||
|
因为 h 的赋值表达式为 h = m,那么循环条件也就只能使用 l < h 这种形式。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int singleNonDuplicate(int[] nums) {
|
||||||
|
int l = 0, h = nums.length - 1;
|
||||||
|
while (l < h) {
|
||||||
|
int m = l + (h - l) / 2;
|
||||||
|
if (m % 2 == 1) {
|
||||||
|
m--; // 保证 l/h/m 都在偶数位,使得查找区间大小一直都是奇数
|
||||||
|
}
|
||||||
|
if (nums[m] == nums[m + 1]) {
|
||||||
|
l = m + 2;
|
||||||
|
} else {
|
||||||
|
h = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nums[l];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 第一个错误的版本
|
||||||
|
|
||||||
|
[278. First Bad Version (Easy)](https://leetcode.com/problems/first-bad-version/description/)
|
||||||
|
|
||||||
|
题目描述:给定一个元素 n 代表有 [1, 2, ..., n] 版本,可以调用 isBadVersion(int x) 知道某个版本是否错误,要求找到第一个错误的版本。
|
||||||
|
|
||||||
|
如果第 m 个版本出错,则表示第一个错误的版本在 [l, m] 之间,令 h = m;否则第一个错误的版本在 [m + 1, h] 之间,令 l = m + 1。
|
||||||
|
|
||||||
|
因为 h 的赋值表达式为 h = m,因此循环条件为 l < h。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int firstBadVersion(int n) {
|
||||||
|
int l = 1, h = n;
|
||||||
|
while (l < h) {
|
||||||
|
int mid = l + (h - l) / 2;
|
||||||
|
if (isBadVersion(mid)) {
|
||||||
|
h = mid;
|
||||||
|
} else {
|
||||||
|
l = mid + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 旋转数组的最小数字
|
||||||
|
|
||||||
|
[153. Find Minimum in Rotated Sorted Array (Medium)](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [3,4,5,1,2],
|
||||||
|
Output: 1
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findMin(int[] nums) {
|
||||||
|
int l = 0, h = nums.length - 1;
|
||||||
|
while (l < h) {
|
||||||
|
int m = l + (h - l) / 2;
|
||||||
|
if (nums[m] <= nums[h]) {
|
||||||
|
h = m;
|
||||||
|
} else {
|
||||||
|
l = m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nums[l];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 查找区间
|
||||||
|
|
||||||
|
[34. Search for a Range (Medium)](https://leetcode.com/problems/search-for-a-range/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: nums = [5,7,7,8,8,10], target = 8
|
||||||
|
Output: [3,4]
|
||||||
|
|
||||||
|
Input: nums = [5,7,7,8,8,10], target = 6
|
||||||
|
Output: [-1,-1]
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] searchRange(int[] nums, int target) {
|
||||||
|
int first = binarySearch(nums, target);
|
||||||
|
int last = binarySearch(nums, target + 1) - 1;
|
||||||
|
if (first == nums.length || nums[first] != target) {
|
||||||
|
return new int[]{-1, -1};
|
||||||
|
} else {
|
||||||
|
return new int[]{first, Math.max(first, last)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int binarySearch(int[] nums, int target) {
|
||||||
|
int l = 0, h = nums.length; // 注意 h 的初始值
|
||||||
|
while (l < h) {
|
||||||
|
int m = l + (h - l) / 2;
|
||||||
|
if (nums[m] >= target) {
|
||||||
|
h = m;
|
||||||
|
} else {
|
||||||
|
l = m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
433
docs/notes/Leetcode 题解 - 位运算.md
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [原理](#原理)
|
||||||
|
* [1. 基本原理](#1-基本原理)
|
||||||
|
* [2. mask 计算](#2-mask-计算)
|
||||||
|
* [3. Java 中的位操作](#3-java-中的位操作)
|
||||||
|
* [例题](#例题)
|
||||||
|
* [统计两个数的二进制表示有多少位不同](#统计两个数的二进制表示有多少位不同)
|
||||||
|
* [数组中唯一一个不重复的元素](#数组中唯一一个不重复的元素)
|
||||||
|
* [找出数组中缺失的那个数](#找出数组中缺失的那个数)
|
||||||
|
* [数组中不重复的两个元素](#数组中不重复的两个元素)
|
||||||
|
* [翻转一个数的比特位](#翻转一个数的比特位)
|
||||||
|
* [不用额外变量交换两个整数](#不用额外变量交换两个整数)
|
||||||
|
* [判断一个数是不是 2 的 n 次方](#判断一个数是不是-2-的-n-次方)
|
||||||
|
* [判断一个数是不是 4 的 n 次方](#判断一个数是不是-4-的-n-次方)
|
||||||
|
* [判断一个数的位级表示是否不会出现连续的 0 和 1](#判断一个数的位级表示是否不会出现连续的-0-和-1)
|
||||||
|
* [求一个数的补码](#求一个数的补码)
|
||||||
|
* [实现整数的加法](#实现整数的加法)
|
||||||
|
* [字符串数组最大乘积](#字符串数组最大乘积)
|
||||||
|
* [统计从 0 \~ n 每个数的二进制表示中 1 的个数](#统计从-0-\~-n-每个数的二进制表示中-1-的个数)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 原理
|
||||||
|
|
||||||
|
## 1. 基本原理
|
||||||
|
|
||||||
|
0s 表示一串 0,1s 表示一串 1。
|
||||||
|
|
||||||
|
```
|
||||||
|
x ^ 0s = x x & 0s = 0 x | 0s = x
|
||||||
|
x ^ 1s = ~x x & 1s = x x | 1s = 1s
|
||||||
|
x ^ x = 0 x & x = x x | x = x
|
||||||
|
```
|
||||||
|
|
||||||
|
- 利用 x ^ 1s = \~x 的特点,可以将位级表示翻转;利用 x ^ x = 0 的特点,可以将三个数中重复的两个数去除,只留下另一个数。
|
||||||
|
- 利用 x & 0s = 0 和 x & 1s = x 的特点,可以实现掩码操作。一个数 num 与 mask:00111100 进行位与操作,只保留 num 中与 mask 的 1 部分相对应的位。
|
||||||
|
- 利用 x | 0s = x 和 x | 1s = 1s 的特点,可以实现设值操作。一个数 num 与 mask:00111100 进行位或操作,将 num 中与 mask 的 1 部分相对应的位都设置为 1。
|
||||||
|
|
||||||
|
位与运算技巧:
|
||||||
|
|
||||||
|
- n&(n-1) 去除 n 的位级表示中最低的那一位。例如对于二进制表示 10110100,减去 1 得到 10110011,这两个数相与得到 10110000。
|
||||||
|
- n&(-n) 得到 n 的位级表示中最低的那一位。-n 得到 n 的反码加 1,对于二进制表示 10110100,-n 得到 01001100,相与得到 00000100。
|
||||||
|
- n-n&(\~n+1) 去除 n 的位级表示中最高的那一位。
|
||||||
|
|
||||||
|
移位运算:
|
||||||
|
|
||||||
|
- \>\> n 为算术右移,相当于除以 2<sup>n</sup>;
|
||||||
|
- \>\>\> n 为无符号右移,左边会补上 0。
|
||||||
|
- << n 为算术左移,相当于乘以 2<sup>n</sup>。
|
||||||
|
|
||||||
|
## 2. mask 计算
|
||||||
|
|
||||||
|
要获取 111111111,将 0 取反即可,\~0。
|
||||||
|
|
||||||
|
要得到只有第 i 位为 1 的 mask,将 1 向左移动 i-1 位即可,1<<(i-1) 。例如 1<<4 得到只有第 5 位为 1 的 mask :00010000。
|
||||||
|
|
||||||
|
要得到 1 到 i 位为 1 的 mask,1<<(i+1)-1 即可,例如将 1<<(4+1)-1 = 00010000-1 = 00001111。
|
||||||
|
|
||||||
|
要得到 1 到 i 位为 0 的 mask,只需将 1 到 i 位为 1 的 mask 取反,即 \~(1<<(i+1)-1)。
|
||||||
|
|
||||||
|
## 3. Java 中的位操作
|
||||||
|
|
||||||
|
```html
|
||||||
|
static int Integer.bitCount(); // 统计 1 的数量
|
||||||
|
static int Integer.highestOneBit(); // 获得最高位
|
||||||
|
static String toBinaryString(int i); // 转换为二进制表示的字符串
|
||||||
|
```
|
||||||
|
|
||||||
|
# 例题
|
||||||
|
|
||||||
|
## 统计两个数的二进制表示有多少位不同
|
||||||
|
|
||||||
|
[461. Hamming Distance (Easy)](https://leetcode.com/problems/hamming-distance/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: x = 1, y = 4
|
||||||
|
|
||||||
|
Output: 2
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
1 (0 0 0 1)
|
||||||
|
4 (0 1 0 0)
|
||||||
|
↑ ↑
|
||||||
|
|
||||||
|
The above arrows point to positions where the corresponding bits are different.
|
||||||
|
```
|
||||||
|
|
||||||
|
对两个数进行异或操作,位级表示不同的那一位为 1,统计有多少个 1 即可。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int hammingDistance(int x, int y) {
|
||||||
|
int z = x ^ y;
|
||||||
|
int cnt = 0;
|
||||||
|
while(z != 0) {
|
||||||
|
if ((z & 1) == 1) cnt++;
|
||||||
|
z = z >> 1;
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
使用 z&(z-1) 去除 z 位级表示最低的那一位。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int hammingDistance(int x, int y) {
|
||||||
|
int z = x ^ y;
|
||||||
|
int cnt = 0;
|
||||||
|
while (z != 0) {
|
||||||
|
z &= (z - 1);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
可以使用 Integer.bitcount() 来统计 1 个的个数。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int hammingDistance(int x, int y) {
|
||||||
|
return Integer.bitCount(x ^ y);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数组中唯一一个不重复的元素
|
||||||
|
|
||||||
|
[136. Single Number (Easy)](https://leetcode.com/problems/single-number/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [4,1,2,1,2]
|
||||||
|
Output: 4
|
||||||
|
```
|
||||||
|
|
||||||
|
两个相同的数异或的结果为 0,对所有数进行异或操作,最后的结果就是单独出现的那个数。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int singleNumber(int[] nums) {
|
||||||
|
int ret = 0;
|
||||||
|
for (int n : nums) ret = ret ^ n;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 找出数组中缺失的那个数
|
||||||
|
|
||||||
|
[268. Missing Number (Easy)](https://leetcode.com/problems/missing-number/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [3,0,1]
|
||||||
|
Output: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:数组元素在 0-n 之间,但是有一个数是缺失的,要求找到这个缺失的数。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int missingNumber(int[] nums) {
|
||||||
|
int ret = 0;
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
ret = ret ^ i ^ nums[i];
|
||||||
|
}
|
||||||
|
return ret ^ nums.length;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数组中不重复的两个元素
|
||||||
|
|
||||||
|
[260. Single Number III (Medium)](https://leetcode.com/problems/single-number-iii/description/)
|
||||||
|
|
||||||
|
两个不相等的元素在位级表示上必定会有一位存在不同。
|
||||||
|
|
||||||
|
将数组的所有元素异或得到的结果为不存在重复的两个元素异或的结果。
|
||||||
|
|
||||||
|
diff &= -diff 得到出 diff 最右侧不为 0 的位,也就是不存在重复的两个元素在位级表示上最右侧不同的那一位,利用这一位就可以将两个元素区分开来。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] singleNumber(int[] nums) {
|
||||||
|
int diff = 0;
|
||||||
|
for (int num : nums) diff ^= num;
|
||||||
|
diff &= -diff; // 得到最右一位
|
||||||
|
int[] ret = new int[2];
|
||||||
|
for (int num : nums) {
|
||||||
|
if ((num & diff) == 0) ret[0] ^= num;
|
||||||
|
else ret[1] ^= num;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 翻转一个数的比特位
|
||||||
|
|
||||||
|
[190. Reverse Bits (Easy)](https://leetcode.com/problems/reverse-bits/description/)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int reverseBits(int n) {
|
||||||
|
int ret = 0;
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
ret <<= 1;
|
||||||
|
ret |= (n & 1);
|
||||||
|
n >>>= 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
如果该函数需要被调用很多次,可以将 int 拆成 4 个 byte,然后缓存 byte 对应的比特位翻转,最后再拼接起来。
|
||||||
|
|
||||||
|
```java
|
||||||
|
private static Map<Byte, Integer> cache = new HashMap<>();
|
||||||
|
|
||||||
|
public int reverseBits(int n) {
|
||||||
|
int ret = 0;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
ret <<= 8;
|
||||||
|
ret |= reverseByte((byte) (n & 0b11111111));
|
||||||
|
n >>= 8;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int reverseByte(byte b) {
|
||||||
|
if (cache.containsKey(b)) return cache.get(b);
|
||||||
|
int ret = 0;
|
||||||
|
byte t = b;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
ret <<= 1;
|
||||||
|
ret |= t & 1;
|
||||||
|
t >>= 1;
|
||||||
|
}
|
||||||
|
cache.put(b, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 不用额外变量交换两个整数
|
||||||
|
|
||||||
|
[程序员代码面试指南 :P317](#)
|
||||||
|
|
||||||
|
```java
|
||||||
|
a = a ^ b;
|
||||||
|
b = a ^ b;
|
||||||
|
a = a ^ b;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 判断一个数是不是 2 的 n 次方
|
||||||
|
|
||||||
|
[231. Power of Two (Easy)](https://leetcode.com/problems/power-of-two/description/)
|
||||||
|
|
||||||
|
二进制表示只有一个 1 存在。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isPowerOfTwo(int n) {
|
||||||
|
return n > 0 && Integer.bitCount(n) == 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
利用 1000 & 0111 == 0 这种性质,得到以下解法:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isPowerOfTwo(int n) {
|
||||||
|
return n > 0 && (n & (n - 1)) == 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 判断一个数是不是 4 的 n 次方
|
||||||
|
|
||||||
|
[342. Power of Four (Easy)](https://leetcode.com/problems/power-of-four/)
|
||||||
|
|
||||||
|
这种数在二进制表示中有且只有一个奇数位为 1,例如 16(10000)。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isPowerOfFour(int num) {
|
||||||
|
return num > 0 && (num & (num - 1)) == 0 && (num & 0b01010101010101010101010101010101) != 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
也可以使用正则表达式进行匹配。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isPowerOfFour(int num) {
|
||||||
|
return Integer.toString(num, 4).matches("10*");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 判断一个数的位级表示是否不会出现连续的 0 和 1
|
||||||
|
|
||||||
|
[693. Binary Number with Alternating Bits (Easy)](https://leetcode.com/problems/binary-number-with-alternating-bits/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: 10
|
||||||
|
Output: True
|
||||||
|
Explanation:
|
||||||
|
The binary representation of 10 is: 1010.
|
||||||
|
|
||||||
|
Input: 11
|
||||||
|
Output: False
|
||||||
|
Explanation:
|
||||||
|
The binary representation of 11 is: 1011.
|
||||||
|
```
|
||||||
|
|
||||||
|
对于 1010 这种位级表示的数,把它向右移动 1 位得到 101,这两个数每个位都不同,因此异或得到的结果为 1111。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean hasAlternatingBits(int n) {
|
||||||
|
int a = (n ^ (n >> 1));
|
||||||
|
return (a & (a + 1)) == 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 求一个数的补码
|
||||||
|
|
||||||
|
[476. Number Complement (Easy)](https://leetcode.com/problems/number-complement/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: 5
|
||||||
|
Output: 2
|
||||||
|
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:不考虑二进制表示中的首 0 部分。
|
||||||
|
|
||||||
|
对于 00000101,要求补码可以将它与 00000111 进行异或操作。那么问题就转换为求掩码 00000111。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findComplement(int num) {
|
||||||
|
if (num == 0) return 1;
|
||||||
|
int mask = 1 << 30;
|
||||||
|
while ((num & mask) == 0) mask >>= 1;
|
||||||
|
mask = (mask << 1) - 1;
|
||||||
|
return num ^ mask;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
可以利用 Java 的 Integer.highestOneBit() 方法来获得含有首 1 的数。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findComplement(int num) {
|
||||||
|
if (num == 0) return 1;
|
||||||
|
int mask = Integer.highestOneBit(num);
|
||||||
|
mask = (mask << 1) - 1;
|
||||||
|
return num ^ mask;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
对于 10000000 这样的数要扩展成 11111111,可以利用以下方法:
|
||||||
|
|
||||||
|
```html
|
||||||
|
mask |= mask >> 1 11000000
|
||||||
|
mask |= mask >> 2 11110000
|
||||||
|
mask |= mask >> 4 11111111
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findComplement(int num) {
|
||||||
|
int mask = num;
|
||||||
|
mask |= mask >> 1;
|
||||||
|
mask |= mask >> 2;
|
||||||
|
mask |= mask >> 4;
|
||||||
|
mask |= mask >> 8;
|
||||||
|
mask |= mask >> 16;
|
||||||
|
return (mask ^ num);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 实现整数的加法
|
||||||
|
|
||||||
|
[371. Sum of Two Integers (Easy)](https://leetcode.com/problems/sum-of-two-integers/description/)
|
||||||
|
|
||||||
|
a ^ b 表示没有考虑进位的情况下两数的和,(a & b) << 1 就是进位。
|
||||||
|
|
||||||
|
递归会终止的原因是 (a & b) << 1 最右边会多一个 0,那么继续递归,进位最右边的 0 会慢慢增多,最后进位会变为 0,递归终止。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int getSum(int a, int b) {
|
||||||
|
return b == 0 ? a : getSum((a ^ b), (a & b) << 1);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 字符串数组最大乘积
|
||||||
|
|
||||||
|
[318. Maximum Product of Word Lengths (Medium)](https://leetcode.com/problems/maximum-product-of-word-lengths/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Given ["abcw", "baz", "foo", "bar", "xtfn", "abcdef"]
|
||||||
|
Return 16
|
||||||
|
The two words can be "abcw", "xtfn".
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:字符串数组的字符串只含有小写字符。求解字符串数组中两个字符串长度的最大乘积,要求这两个字符串不能含有相同字符。
|
||||||
|
|
||||||
|
本题主要问题是判断两个字符串是否含相同字符,由于字符串只含有小写字符,总共 26 位,因此可以用一个 32 位的整数来存储每个字符是否出现过。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int maxProduct(String[] words) {
|
||||||
|
int n = words.length;
|
||||||
|
int[] val = new int[n];
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
for (char c : words[i].toCharArray()) {
|
||||||
|
val[i] |= 1 << (c - 'a');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int ret = 0;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
for (int j = i + 1; j < n; j++) {
|
||||||
|
if ((val[i] & val[j]) == 0) {
|
||||||
|
ret = Math.max(ret, words[i].length() * words[j].length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 统计从 0 \~ n 每个数的二进制表示中 1 的个数
|
||||||
|
|
||||||
|
[338. Counting Bits (Medium)](https://leetcode.com/problems/counting-bits/description/)
|
||||||
|
|
||||||
|
对于数字 6(110),它可以看成是 4(100) 再加一个 2(10),因此 dp[i] = dp[i&(i-1)] + 1;
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] countBits(int num) {
|
||||||
|
int[] ret = new int[num + 1];
|
||||||
|
for(int i = 1; i <= num; i++){
|
||||||
|
ret[i] = ret[i&(i-1)] + 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
55
docs/notes/Leetcode 题解 - 分治.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [1. 给表达式加括号](#1-给表达式加括号)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 1. 给表达式加括号
|
||||||
|
|
||||||
|
[241. Different Ways to Add Parentheses (Medium)](https://leetcode.com/problems/different-ways-to-add-parentheses/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: "2-1-1".
|
||||||
|
|
||||||
|
((2-1)-1) = 0
|
||||||
|
(2-(1-1)) = 2
|
||||||
|
|
||||||
|
Output : [0, 2]
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public List<Integer> diffWaysToCompute(String input) {
|
||||||
|
List<Integer> ways = new ArrayList<>();
|
||||||
|
for (int i = 0; i < input.length(); i++) {
|
||||||
|
char c = input.charAt(i);
|
||||||
|
if (c == '+' || c == '-' || c == '*') {
|
||||||
|
List<Integer> left = diffWaysToCompute(input.substring(0, i));
|
||||||
|
List<Integer> right = diffWaysToCompute(input.substring(i + 1));
|
||||||
|
for (int l : left) {
|
||||||
|
for (int r : right) {
|
||||||
|
switch (c) {
|
||||||
|
case '+':
|
||||||
|
ways.add(l + r);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
ways.add(l - r);
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
ways.add(l * r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ways.size() == 0) {
|
||||||
|
ways.add(Integer.valueOf(input));
|
||||||
|
}
|
||||||
|
return ways;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
1227
docs/notes/Leetcode 题解 - 动态规划.md
Normal file
244
docs/notes/Leetcode 题解 - 双指针.md
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [有序数组的 Two Sum](#有序数组的-two-sum)
|
||||||
|
* [两数平方和](#两数平方和)
|
||||||
|
* [反转字符串中的元音字符](#反转字符串中的元音字符)
|
||||||
|
* [回文字符串](#回文字符串)
|
||||||
|
* [归并两个有序数组](#归并两个有序数组)
|
||||||
|
* [判断链表是否存在环](#判断链表是否存在环)
|
||||||
|
* [最长子序列](#最长子序列)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。
|
||||||
|
|
||||||
|
# 有序数组的 Two Sum
|
||||||
|
|
||||||
|
[Leetcode :167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: numbers={2, 7, 11, 15}, target=9
|
||||||
|
Output: index1=1, index2=2
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:在有序数组中找出两个数,使它们的和为 target。
|
||||||
|
|
||||||
|
使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
|
||||||
|
|
||||||
|
- 如果两个指针指向元素的和 sum == target,那么得到要求的结果;
|
||||||
|
- 如果 sum > target,移动较大的元素,使 sum 变小一些;
|
||||||
|
- 如果 sum < target,移动较小的元素,使 sum 变大一些。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] twoSum(int[] numbers, int target) {
|
||||||
|
int i = 0, j = numbers.length - 1;
|
||||||
|
while (i < j) {
|
||||||
|
int sum = numbers[i] + numbers[j];
|
||||||
|
if (sum == target) {
|
||||||
|
return new int[]{i + 1, j + 1};
|
||||||
|
} else if (sum < target) {
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 两数平方和
|
||||||
|
|
||||||
|
[633. Sum of Square Numbers (Easy)](https://leetcode.com/problems/sum-of-square-numbers/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: 5
|
||||||
|
Output: True
|
||||||
|
Explanation: 1 * 1 + 2 * 2 = 5
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:判断一个数是否为两个数的平方和。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean judgeSquareSum(int c) {
|
||||||
|
int i = 0, j = (int) Math.sqrt(c);
|
||||||
|
while (i <= j) {
|
||||||
|
int powSum = i * i + j * j;
|
||||||
|
if (powSum == c) {
|
||||||
|
return true;
|
||||||
|
} else if (powSum > c) {
|
||||||
|
j--;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 反转字符串中的元音字符
|
||||||
|
|
||||||
|
[345. Reverse Vowels of a String (Easy)](https://leetcode.com/problems/reverse-vowels-of-a-string/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Given s = "leetcode", return "leotcede".
|
||||||
|
```
|
||||||
|
|
||||||
|
使用双指针指向待反转的两个元音字符,一个指针从头向尾遍历,一个指针从尾到头遍历。
|
||||||
|
|
||||||
|
```java
|
||||||
|
private final static HashSet<Character> vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
|
||||||
|
|
||||||
|
public String reverseVowels(String s) {
|
||||||
|
int i = 0, j = s.length() - 1;
|
||||||
|
char[] result = new char[s.length()];
|
||||||
|
while (i <= j) {
|
||||||
|
char ci = s.charAt(i);
|
||||||
|
char cj = s.charAt(j);
|
||||||
|
if (!vowels.contains(ci)) {
|
||||||
|
result[i++] = ci;
|
||||||
|
} else if (!vowels.contains(cj)) {
|
||||||
|
result[j--] = cj;
|
||||||
|
} else {
|
||||||
|
result[i++] = cj;
|
||||||
|
result[j--] = ci;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new String(result);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 回文字符串
|
||||||
|
|
||||||
|
[680. Valid Palindrome II (Easy)](https://leetcode.com/problems/valid-palindrome-ii/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: "abca"
|
||||||
|
Output: True
|
||||||
|
Explanation: You could delete the character 'c'.
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:可以删除一个字符,判断是否能构成回文字符串。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean validPalindrome(String s) {
|
||||||
|
int i = -1, j = s.length();
|
||||||
|
while (++i < --j) {
|
||||||
|
if (s.charAt(i) != s.charAt(j)) {
|
||||||
|
return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPalindrome(String s, int i, int j) {
|
||||||
|
while (i < j) {
|
||||||
|
if (s.charAt(i++) != s.charAt(j--)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 归并两个有序数组
|
||||||
|
|
||||||
|
[88. Merge Sorted Array (Easy)](https://leetcode.com/problems/merge-sorted-array/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input:
|
||||||
|
nums1 = [1,2,3,0,0,0], m = 3
|
||||||
|
nums2 = [2,5,6], n = 3
|
||||||
|
|
||||||
|
Output: [1,2,2,3,5,6]
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:把归并结果存到第一个数组上。
|
||||||
|
|
||||||
|
需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public void merge(int[] nums1, int m, int[] nums2, int n) {
|
||||||
|
int index1 = m - 1, index2 = n - 1;
|
||||||
|
int indexMerge = m + n - 1;
|
||||||
|
while (index1 >= 0 || index2 >= 0) {
|
||||||
|
if (index1 < 0) {
|
||||||
|
nums1[indexMerge--] = nums2[index2--];
|
||||||
|
} else if (index2 < 0) {
|
||||||
|
nums1[indexMerge--] = nums1[index1--];
|
||||||
|
} else if (nums1[index1] > nums2[index2]) {
|
||||||
|
nums1[indexMerge--] = nums1[index1--];
|
||||||
|
} else {
|
||||||
|
nums1[indexMerge--] = nums2[index2--];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 判断链表是否存在环
|
||||||
|
|
||||||
|
[141. Linked List Cycle (Easy)](https://leetcode.com/problems/linked-list-cycle/description/)
|
||||||
|
|
||||||
|
使用双指针,一个指针每次移动一个节点,一个指针每次移动两个节点,如果存在环,那么这两个指针一定会相遇。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean hasCycle(ListNode head) {
|
||||||
|
if (head == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ListNode l1 = head, l2 = head.next;
|
||||||
|
while (l1 != null && l2 != null && l2.next != null) {
|
||||||
|
if (l1 == l2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
l1 = l1.next;
|
||||||
|
l2 = l2.next.next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 最长子序列
|
||||||
|
|
||||||
|
[524. Longest Word in Dictionary through Deleting (Medium)](https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/description/)
|
||||||
|
|
||||||
|
```
|
||||||
|
Input:
|
||||||
|
s = "abpcplea", d = ["ale","apple","monkey","plea"]
|
||||||
|
|
||||||
|
Output:
|
||||||
|
"apple"
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回字典序的最小字符串。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public String findLongestWord(String s, List<String> d) {
|
||||||
|
String longestWord = "";
|
||||||
|
for (String target : d) {
|
||||||
|
int l1 = longestWord.length(), l2 = target.length();
|
||||||
|
if (l1 > l2 || (l1 == l2 && longestWord.compareTo(target) < 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isValid(s, target)) {
|
||||||
|
longestWord = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return longestWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValid(String s, String target) {
|
||||||
|
int i = 0, j = 0;
|
||||||
|
while (i < s.length() && j < target.length()) {
|
||||||
|
if (s.charAt(i) == target.charAt(j)) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return j == target.length();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
129
docs/notes/Leetcode 题解 - 哈希表.md
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [1. 数组中两个数的和为给定值](#1-数组中两个数的和为给定值)
|
||||||
|
* [2. 判断数组是否含有重复元素](#2-判断数组是否含有重复元素)
|
||||||
|
* [3. 最长和谐序列](#3-最长和谐序列)
|
||||||
|
* [4. 最长连续序列](#4-最长连续序列)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
哈希表使用 O(N) 空间复杂度存储数据,并且以 O(1) 时间复杂度求解问题。
|
||||||
|
|
||||||
|
- Java 中的 **HashSet** 用于存储一个集合,可以查找元素是否在集合中。如果元素有穷,并且范围不大,那么可以用一个布尔数组来存储一个元素是否存在。例如对于只有小写字符的元素,就可以用一个长度为 26 的布尔数组来存储一个字符集合,使得空间复杂度降低为 O(1)。
|
||||||
|
|
||||||
|
- Java 中的 **HashMap** 主要用于映射关系,从而把两个元素联系起来。HashMap 也可以用来对元素进行计数统计,此时键为元素,值为计数。和 HashSet 类似,如果元素有穷并且范围不大,可以用整型数组来进行统计。在对一个内容进行压缩或者其它转换时,利用 HashMap 可以把原始内容和转换后的内容联系起来。例如在一个简化 url 的系统中 [Leetcdoe : 535. Encode and Decode TinyURL (Medium)](https://leetcode.com/problems/encode-and-decode-tinyurl/description/),利用 HashMap 就可以存储精简后的 url 到原始 url 的映射,使得不仅可以显示简化的 url,也可以根据简化的 url 得到原始 url 从而定位到正确的资源。
|
||||||
|
|
||||||
|
|
||||||
|
# 1. 数组中两个数的和为给定值
|
||||||
|
|
||||||
|
[1. Two Sum (Easy)](https://leetcode.com/problems/two-sum/description/)
|
||||||
|
|
||||||
|
可以先对数组进行排序,然后使用双指针方法或者二分查找方法。这样做的时间复杂度为 O(NlogN),空间复杂度为 O(1)。
|
||||||
|
|
||||||
|
用 HashMap 存储数组元素和索引的映射,在访问到 nums[i] 时,判断 HashMap 中是否存在 target - nums[i],如果存在说明 target - nums[i] 所在的索引和 i 就是要找的两个数。该方法的时间复杂度为 O(N),空间复杂度为 O(N),使用空间来换取时间。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] twoSum(int[] nums, int target) {
|
||||||
|
HashMap<Integer, Integer> indexForNum = new HashMap<>();
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
if (indexForNum.containsKey(target - nums[i])) {
|
||||||
|
return new int[]{indexForNum.get(target - nums[i]), i};
|
||||||
|
} else {
|
||||||
|
indexForNum.put(nums[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 2. 判断数组是否含有重复元素
|
||||||
|
|
||||||
|
[217. Contains Duplicate (Easy)](https://leetcode.com/problems/contains-duplicate/description/)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean containsDuplicate(int[] nums) {
|
||||||
|
Set<Integer> set = new HashSet<>();
|
||||||
|
for (int num : nums) {
|
||||||
|
set.add(num);
|
||||||
|
}
|
||||||
|
return set.size() < nums.length;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 3. 最长和谐序列
|
||||||
|
|
||||||
|
[594. Longest Harmonious Subsequence (Easy)](https://leetcode.com/problems/longest-harmonious-subsequence/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [1,3,2,2,5,2,3,7]
|
||||||
|
Output: 5
|
||||||
|
Explanation: The longest harmonious subsequence is [3,2,2,2,3].
|
||||||
|
```
|
||||||
|
|
||||||
|
和谐序列中最大数和最小数之差正好为 1,应该注意的是序列的元素不一定是数组的连续元素。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findLHS(int[] nums) {
|
||||||
|
Map<Integer, Integer> countForNum = new HashMap<>();
|
||||||
|
for (int num : nums) {
|
||||||
|
countForNum.put(num, countForNum.getOrDefault(num, 0) + 1);
|
||||||
|
}
|
||||||
|
int longest = 0;
|
||||||
|
for (int num : countForNum.keySet()) {
|
||||||
|
if (countForNum.containsKey(num + 1)) {
|
||||||
|
longest = Math.max(longest, countForNum.get(num + 1) + countForNum.get(num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return longest;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 4. 最长连续序列
|
||||||
|
|
||||||
|
[128. Longest Consecutive Sequence (Hard)](https://leetcode.com/problems/longest-consecutive-sequence/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Given [100, 4, 200, 1, 3, 2],
|
||||||
|
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.
|
||||||
|
```
|
||||||
|
|
||||||
|
要求以 O(N) 的时间复杂度求解。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int longestConsecutive(int[] nums) {
|
||||||
|
Map<Integer, Integer> countForNum = new HashMap<>();
|
||||||
|
for (int num : nums) {
|
||||||
|
countForNum.put(num, 1);
|
||||||
|
}
|
||||||
|
for (int num : nums) {
|
||||||
|
forward(countForNum, num);
|
||||||
|
}
|
||||||
|
return maxCount(countForNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int forward(Map<Integer, Integer> countForNum, int num) {
|
||||||
|
if (!countForNum.containsKey(num)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int cnt = countForNum.get(num);
|
||||||
|
if (cnt > 1) {
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
cnt = forward(countForNum, num + 1) + 1;
|
||||||
|
countForNum.put(num, cnt);
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int maxCount(Map<Integer, Integer> countForNum) {
|
||||||
|
int max = 0;
|
||||||
|
for (int num : countForNum.keySet()) {
|
||||||
|
max = Math.max(max, countForNum.get(num));
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
263
docs/notes/Leetcode 题解 - 图.md
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [二分图](#二分图)
|
||||||
|
* [判断是否为二分图](#判断是否为二分图)
|
||||||
|
* [拓扑排序](#拓扑排序)
|
||||||
|
* [课程安排的合法性](#课程安排的合法性)
|
||||||
|
* [课程安排的顺序](#课程安排的顺序)
|
||||||
|
* [并查集](#并查集)
|
||||||
|
* [冗余连接](#冗余连接)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 二分图
|
||||||
|
|
||||||
|
如果可以用两种颜色对图中的节点进行着色,并且保证相邻的节点颜色不同,那么这个图就是二分图。
|
||||||
|
|
||||||
|
## 判断是否为二分图
|
||||||
|
|
||||||
|
[785. Is Graph Bipartite? (Medium)](https://leetcode.com/problems/is-graph-bipartite/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [[1,3], [0,2], [1,3], [0,2]]
|
||||||
|
Output: true
|
||||||
|
Explanation:
|
||||||
|
The graph looks like this:
|
||||||
|
0----1
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
3----2
|
||||||
|
We can divide the vertices into two groups: {0, 2} and {1, 3}.
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
Example 2:
|
||||||
|
Input: [[1,2,3], [0,2], [0,1,3], [0,2]]
|
||||||
|
Output: false
|
||||||
|
Explanation:
|
||||||
|
The graph looks like this:
|
||||||
|
0----1
|
||||||
|
| \ |
|
||||||
|
| \ |
|
||||||
|
3----2
|
||||||
|
We cannot find a way to divide the set of nodes into two independent subsets.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isBipartite(int[][] graph) {
|
||||||
|
int[] colors = new int[graph.length];
|
||||||
|
Arrays.fill(colors, -1);
|
||||||
|
for (int i = 0; i < graph.length; i++) { // 处理图不是连通的情况
|
||||||
|
if (colors[i] == -1 && !isBipartite(i, 0, colors, graph)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBipartite(int curNode, int curColor, int[] colors, int[][] graph) {
|
||||||
|
if (colors[curNode] != -1) {
|
||||||
|
return colors[curNode] == curColor;
|
||||||
|
}
|
||||||
|
colors[curNode] = curColor;
|
||||||
|
for (int nextNode : graph[curNode]) {
|
||||||
|
if (!isBipartite(nextNode, 1 - curColor, colors, graph)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 拓扑排序
|
||||||
|
|
||||||
|
常用于在具有先序关系的任务规划中。
|
||||||
|
|
||||||
|
## 课程安排的合法性
|
||||||
|
|
||||||
|
[207. Course Schedule (Medium)](https://leetcode.com/problems/course-schedule/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
2, [[1,0]]
|
||||||
|
return true
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
2, [[1,0],[0,1]]
|
||||||
|
return false
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:一个课程可能会先修课程,判断给定的先修课程规定是否合法。
|
||||||
|
|
||||||
|
本题不需要使用拓扑排序,只需要检测有向图是否存在环即可。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean canFinish(int numCourses, int[][] prerequisites) {
|
||||||
|
List<Integer>[] graphic = new List[numCourses];
|
||||||
|
for (int i = 0; i < numCourses; i++) {
|
||||||
|
graphic[i] = new ArrayList<>();
|
||||||
|
}
|
||||||
|
for (int[] pre : prerequisites) {
|
||||||
|
graphic[pre[0]].add(pre[1]);
|
||||||
|
}
|
||||||
|
boolean[] globalMarked = new boolean[numCourses];
|
||||||
|
boolean[] localMarked = new boolean[numCourses];
|
||||||
|
for (int i = 0; i < numCourses; i++) {
|
||||||
|
if (hasCycle(globalMarked, localMarked, graphic, i)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasCycle(boolean[] globalMarked, boolean[] localMarked,
|
||||||
|
List<Integer>[] graphic, int curNode) {
|
||||||
|
|
||||||
|
if (localMarked[curNode]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (globalMarked[curNode]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
globalMarked[curNode] = true;
|
||||||
|
localMarked[curNode] = true;
|
||||||
|
for (int nextNode : graphic[curNode]) {
|
||||||
|
if (hasCycle(globalMarked, localMarked, graphic, nextNode)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localMarked[curNode] = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 课程安排的顺序
|
||||||
|
|
||||||
|
[210. Course Schedule II (Medium)](https://leetcode.com/problems/course-schedule-ii/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
4, [[1,0],[2,0],[3,1],[3,2]]
|
||||||
|
There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3].
|
||||||
|
```
|
||||||
|
|
||||||
|
使用 DFS 来实现拓扑排序,使用一个栈存储后序遍历结果,这个栈的逆序结果就是拓扑排序结果。
|
||||||
|
|
||||||
|
证明:对于任何先序关系:v->w,后序遍历结果可以保证 w 先进入栈中,因此栈的逆序结果中 v 会在 w 之前。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] findOrder(int numCourses, int[][] prerequisites) {
|
||||||
|
List<Integer>[] graphic = new List[numCourses];
|
||||||
|
for (int i = 0; i < numCourses; i++) {
|
||||||
|
graphic[i] = new ArrayList<>();
|
||||||
|
}
|
||||||
|
for (int[] pre : prerequisites) {
|
||||||
|
graphic[pre[0]].add(pre[1]);
|
||||||
|
}
|
||||||
|
Stack<Integer> postOrder = new Stack<>();
|
||||||
|
boolean[] globalMarked = new boolean[numCourses];
|
||||||
|
boolean[] localMarked = new boolean[numCourses];
|
||||||
|
for (int i = 0; i < numCourses; i++) {
|
||||||
|
if (hasCycle(globalMarked, localMarked, graphic, i, postOrder)) {
|
||||||
|
return new int[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int[] orders = new int[numCourses];
|
||||||
|
for (int i = numCourses - 1; i >= 0; i--) {
|
||||||
|
orders[i] = postOrder.pop();
|
||||||
|
}
|
||||||
|
return orders;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasCycle(boolean[] globalMarked, boolean[] localMarked, List<Integer>[] graphic,
|
||||||
|
int curNode, Stack<Integer> postOrder) {
|
||||||
|
|
||||||
|
if (localMarked[curNode]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (globalMarked[curNode]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
globalMarked[curNode] = true;
|
||||||
|
localMarked[curNode] = true;
|
||||||
|
for (int nextNode : graphic[curNode]) {
|
||||||
|
if (hasCycle(globalMarked, localMarked, graphic, nextNode, postOrder)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localMarked[curNode] = false;
|
||||||
|
postOrder.push(curNode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 并查集
|
||||||
|
|
||||||
|
并查集可以动态地连通两个点,并且可以非常快速地判断两个点是否连通。
|
||||||
|
|
||||||
|
## 冗余连接
|
||||||
|
|
||||||
|
[684. Redundant Connection (Medium)](https://leetcode.com/problems/redundant-connection/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [[1,2], [1,3], [2,3]]
|
||||||
|
Output: [2,3]
|
||||||
|
Explanation: The given undirected graph will be like this:
|
||||||
|
1
|
||||||
|
/ \
|
||||||
|
2 - 3
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:有一系列的边连成的图,找出一条边,移除它之后该图能够成为一棵树。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] findRedundantConnection(int[][] edges) {
|
||||||
|
int N = edges.length;
|
||||||
|
UF uf = new UF(N);
|
||||||
|
for (int[] e : edges) {
|
||||||
|
int u = e[0], v = e[1];
|
||||||
|
if (uf.connect(u, v)) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
uf.union(u, v);
|
||||||
|
}
|
||||||
|
return new int[]{-1, -1};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UF {
|
||||||
|
|
||||||
|
private int[] id;
|
||||||
|
|
||||||
|
UF(int N) {
|
||||||
|
id = new int[N + 1];
|
||||||
|
for (int i = 0; i < id.length; i++) {
|
||||||
|
id[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void union(int u, int v) {
|
||||||
|
int uID = find(u);
|
||||||
|
int vID = find(v);
|
||||||
|
if (uID == vID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < id.length; i++) {
|
||||||
|
if (id[i] == uID) {
|
||||||
|
id[i] = vID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int find(int p) {
|
||||||
|
return id[p];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean connect(int u, int v) {
|
||||||
|
return find(u) == find(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
231
docs/notes/Leetcode 题解 - 字符串.md
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [字符串循环移位包含](#字符串循环移位包含)
|
||||||
|
* [字符串循环移位](#字符串循环移位)
|
||||||
|
* [字符串中单词的翻转](#字符串中单词的翻转)
|
||||||
|
* [两个字符串包含的字符是否完全相同](#两个字符串包含的字符是否完全相同)
|
||||||
|
* [计算一组字符集合可以组成的回文字符串的最大长度](#计算一组字符集合可以组成的回文字符串的最大长度)
|
||||||
|
* [字符串同构](#字符串同构)
|
||||||
|
* [回文子字符串个数](#回文子字符串个数)
|
||||||
|
* [判断一个整数是否是回文数](#判断一个整数是否是回文数)
|
||||||
|
* [统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数](#统计二进制字符串中连续-1-和连续-0-数量相同的子字符串个数)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 字符串循环移位包含
|
||||||
|
|
||||||
|
[编程之美 3.1](#)
|
||||||
|
|
||||||
|
```html
|
||||||
|
s1 = AABCD, s2 = CDAA
|
||||||
|
Return : true
|
||||||
|
```
|
||||||
|
|
||||||
|
给定两个字符串 s1 和 s2,要求判定 s2 是否能够被 s1 做循环移位得到的字符串包含。
|
||||||
|
|
||||||
|
s1 进行循环移位的结果是 s1s1 的子字符串,因此只要判断 s2 是否是 s1s1 的子字符串即可。
|
||||||
|
|
||||||
|
# 字符串循环移位
|
||||||
|
|
||||||
|
[编程之美 2.17](#)
|
||||||
|
|
||||||
|
```html
|
||||||
|
s = "abcd123" k = 3
|
||||||
|
Return "123abcd"
|
||||||
|
```
|
||||||
|
|
||||||
|
将字符串向右循环移动 k 位。
|
||||||
|
|
||||||
|
将 abcd123 中的 abcd 和 123 单独翻转,得到 dcba321,然后对整个字符串进行翻转,得到 123abcd。
|
||||||
|
|
||||||
|
# 字符串中单词的翻转
|
||||||
|
|
||||||
|
[程序员代码面试指南](#)
|
||||||
|
|
||||||
|
```html
|
||||||
|
s = "I am a student"
|
||||||
|
Return "student a am I"
|
||||||
|
```
|
||||||
|
|
||||||
|
将每个单词翻转,然后将整个字符串翻转。
|
||||||
|
|
||||||
|
# 两个字符串包含的字符是否完全相同
|
||||||
|
|
||||||
|
[242. Valid Anagram (Easy)](https://leetcode.com/problems/valid-anagram/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
s = "anagram", t = "nagaram", return true.
|
||||||
|
s = "rat", t = "car", return false.
|
||||||
|
```
|
||||||
|
|
||||||
|
可以用 HashMap 来映射字符与出现次数,然后比较两个字符串出现的字符数量是否相同。
|
||||||
|
|
||||||
|
由于本题的字符串只包含 26 个小写字符,因此可以使用长度为 26 的整型数组对字符串出现的字符进行统计,不再使用 HashMap。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isAnagram(String s, String t) {
|
||||||
|
int[] cnts = new int[26];
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
cnts[c - 'a']++;
|
||||||
|
}
|
||||||
|
for (char c : t.toCharArray()) {
|
||||||
|
cnts[c - 'a']--;
|
||||||
|
}
|
||||||
|
for (int cnt : cnts) {
|
||||||
|
if (cnt != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 计算一组字符集合可以组成的回文字符串的最大长度
|
||||||
|
|
||||||
|
[409. Longest Palindrome (Easy)](https://leetcode.com/problems/longest-palindrome/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input : "abccccdd"
|
||||||
|
Output : 7
|
||||||
|
Explanation : One longest palindrome that can be built is "dccaccd", whose length is 7.
|
||||||
|
```
|
||||||
|
|
||||||
|
使用长度为 256 的整型数组来统计每个字符出现的个数,每个字符有偶数个可以用来构成回文字符串。
|
||||||
|
|
||||||
|
因为回文字符串最中间的那个字符可以单独出现,所以如果有单独的字符就把它放到最中间。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int longestPalindrome(String s) {
|
||||||
|
int[] cnts = new int[256];
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
cnts[c]++;
|
||||||
|
}
|
||||||
|
int palindrome = 0;
|
||||||
|
for (int cnt : cnts) {
|
||||||
|
palindrome += (cnt / 2) * 2;
|
||||||
|
}
|
||||||
|
if (palindrome < s.length()) {
|
||||||
|
palindrome++; // 这个条件下 s 中一定有单个未使用的字符存在,可以把这个字符放到回文的最中间
|
||||||
|
}
|
||||||
|
return palindrome;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 字符串同构
|
||||||
|
|
||||||
|
[205. Isomorphic Strings (Easy)](https://leetcode.com/problems/isomorphic-strings/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Given "egg", "add", return true.
|
||||||
|
Given "foo", "bar", return false.
|
||||||
|
Given "paper", "title", return true.
|
||||||
|
```
|
||||||
|
|
||||||
|
记录一个字符上次出现的位置,如果两个字符串中的字符上次出现的位置一样,那么就属于同构。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isIsomorphic(String s, String t) {
|
||||||
|
int[] preIndexOfS = new int[256];
|
||||||
|
int[] preIndexOfT = new int[256];
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
char sc = s.charAt(i), tc = t.charAt(i);
|
||||||
|
if (preIndexOfS[sc] != preIndexOfT[tc]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
preIndexOfS[sc] = i + 1;
|
||||||
|
preIndexOfT[tc] = i + 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 回文子字符串个数
|
||||||
|
|
||||||
|
[647. Palindromic Substrings (Medium)](https://leetcode.com/problems/palindromic-substrings/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: "aaa"
|
||||||
|
Output: 6
|
||||||
|
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
|
||||||
|
```
|
||||||
|
|
||||||
|
从字符串的某一位开始,尝试着去扩展子字符串。
|
||||||
|
|
||||||
|
```java
|
||||||
|
private int cnt = 0;
|
||||||
|
|
||||||
|
public int countSubstrings(String s) {
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
extendSubstrings(s, i, i); // 奇数长度
|
||||||
|
extendSubstrings(s, i, i + 1); // 偶数长度
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void extendSubstrings(String s, int start, int end) {
|
||||||
|
while (start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)) {
|
||||||
|
start--;
|
||||||
|
end++;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 判断一个整数是否是回文数
|
||||||
|
|
||||||
|
[9. Palindrome Number (Easy)](https://leetcode.com/problems/palindrome-number/description/)
|
||||||
|
|
||||||
|
要求不能使用额外空间,也就不能将整数转换为字符串进行判断。
|
||||||
|
|
||||||
|
将整数分成左右两部分,右边那部分需要转置,然后判断这两部分是否相等。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isPalindrome(int x) {
|
||||||
|
if (x == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (x < 0 || x % 10 == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int right = 0;
|
||||||
|
while (x > right) {
|
||||||
|
right = right * 10 + x % 10;
|
||||||
|
x /= 10;
|
||||||
|
}
|
||||||
|
return x == right || x == right / 10;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数
|
||||||
|
|
||||||
|
[696. Count Binary Substrings (Easy)](https://leetcode.com/problems/count-binary-substrings/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: "00110011"
|
||||||
|
Output: 6
|
||||||
|
Explanation: There are 6 substrings that have equal number of consecutive 1's and 0's: "0011", "01", "1100", "10", "0011", and "01".
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int countBinarySubstrings(String s) {
|
||||||
|
int preLen = 0, curLen = 1, count = 0;
|
||||||
|
for (int i = 1; i < s.length(); i++) {
|
||||||
|
if (s.charAt(i) == s.charAt(i - 1)) {
|
||||||
|
curLen++;
|
||||||
|
} else {
|
||||||
|
preLen = curLen;
|
||||||
|
curLen = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preLen >= curLen) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
232
docs/notes/Leetcode 题解 - 排序.md
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [快速选择](#快速选择)
|
||||||
|
* [堆排序](#堆排序)
|
||||||
|
* [Kth Element](#kth-element)
|
||||||
|
* [桶排序](#桶排序)
|
||||||
|
* [出现频率最多的 k 个数](#出现频率最多的-k-个数)
|
||||||
|
* [按照字符出现次数对字符串排序](#按照字符出现次数对字符串排序)
|
||||||
|
* [荷兰国旗问题](#荷兰国旗问题)
|
||||||
|
* [按颜色进行排序](#按颜色进行排序)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 快速选择
|
||||||
|
|
||||||
|
用于求解 **Kth Element** 问题,使用快速排序的 partition() 进行实现。
|
||||||
|
|
||||||
|
需要先打乱数组,否则最坏情况下时间复杂度为 O(N<sup>2</sup>)。
|
||||||
|
|
||||||
|
# 堆排序
|
||||||
|
|
||||||
|
用于求解 **TopK Elements** 问题,通过维护一个大小为 K 的堆,堆中的元素就是 TopK Elements。
|
||||||
|
|
||||||
|
堆排序也可以用于求解 Kth Element 问题,堆顶元素就是 Kth Element。
|
||||||
|
|
||||||
|
快速选择也可以求解 TopK Elements 问题,因为找到 Kth Element 之后,再遍历一次数组,所有小于等于 Kth Element 的元素都是 TopK Elements。
|
||||||
|
|
||||||
|
可以看到,快速选择和堆排序都可以求解 Kth Element 和 TopK Elements 问题。
|
||||||
|
|
||||||
|
## Kth Element
|
||||||
|
|
||||||
|
[215. Kth Largest Element in an Array (Medium)](https://leetcode.com/problems/kth-largest-element-in-an-array/description/)
|
||||||
|
|
||||||
|
题目描述:找到第 k 大的元素。
|
||||||
|
|
||||||
|
**排序** :时间复杂度 O(NlogN),空间复杂度 O(1)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findKthLargest(int[] nums, int k) {
|
||||||
|
Arrays.sort(nums);
|
||||||
|
return nums[nums.length - k];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**堆排序** :时间复杂度 O(NlogK),空间复杂度 O(K)。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findKthLargest(int[] nums, int k) {
|
||||||
|
PriorityQueue<Integer> pq = new PriorityQueue<>(); // 小顶堆
|
||||||
|
for (int val : nums) {
|
||||||
|
pq.add(val);
|
||||||
|
if (pq.size() > k) // 维护堆的大小为 K
|
||||||
|
pq.poll();
|
||||||
|
}
|
||||||
|
return pq.peek();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**快速选择** :时间复杂度 O(N),空间复杂度 O(1)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findKthLargest(int[] nums, int k) {
|
||||||
|
k = nums.length - k;
|
||||||
|
int l = 0, h = nums.length - 1;
|
||||||
|
while (l < h) {
|
||||||
|
int j = partition(nums, l, h);
|
||||||
|
if (j == k) {
|
||||||
|
break;
|
||||||
|
} else if (j < k) {
|
||||||
|
l = j + 1;
|
||||||
|
} else {
|
||||||
|
h = j - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nums[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int partition(int[] a, int l, int h) {
|
||||||
|
int i = l, j = h + 1;
|
||||||
|
while (true) {
|
||||||
|
while (a[++i] < a[l] && i < h) ;
|
||||||
|
while (a[--j] > a[l] && j > l) ;
|
||||||
|
if (i >= j) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
swap(a, i, j);
|
||||||
|
}
|
||||||
|
swap(a, l, j);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swap(int[] a, int i, int j) {
|
||||||
|
int t = a[i];
|
||||||
|
a[i] = a[j];
|
||||||
|
a[j] = t;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 桶排序
|
||||||
|
|
||||||
|
## 出现频率最多的 k 个数
|
||||||
|
|
||||||
|
[347. Top K Frequent Elements (Medium)](https://leetcode.com/problems/top-k-frequent-elements/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Given [1,1,1,2,2,3] and k = 2, return [1,2].
|
||||||
|
```
|
||||||
|
|
||||||
|
设置若干个桶,每个桶存储出现频率相同的数,并且桶的下标代表桶中数出现的频率,即第 i 个桶中存储的数出现的频率为 i。
|
||||||
|
|
||||||
|
把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public List<Integer> topKFrequent(int[] nums, int k) {
|
||||||
|
Map<Integer, Integer> frequencyForNum = new HashMap<>();
|
||||||
|
for (int num : nums) {
|
||||||
|
frequencyForNum.put(num, frequencyForNum.getOrDefault(num, 0) + 1);
|
||||||
|
}
|
||||||
|
List<Integer>[] buckets = new ArrayList[nums.length + 1];
|
||||||
|
for (int key : frequencyForNum.keySet()) {
|
||||||
|
int frequency = frequencyForNum.get(key);
|
||||||
|
if (buckets[frequency] == null) {
|
||||||
|
buckets[frequency] = new ArrayList<>();
|
||||||
|
}
|
||||||
|
buckets[frequency].add(key);
|
||||||
|
}
|
||||||
|
List<Integer> topK = new ArrayList<>();
|
||||||
|
for (int i = buckets.length - 1; i >= 0 && topK.size() < k; i--) {
|
||||||
|
if (buckets[i] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (buckets[i].size() <= (k - topK.size())) {
|
||||||
|
topK.addAll(buckets[i]);
|
||||||
|
} else {
|
||||||
|
topK.addAll(buckets[i].subList(0, k - topK.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return topK;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 按照字符出现次数对字符串排序
|
||||||
|
|
||||||
|
[451. Sort Characters By Frequency (Medium)](https://leetcode.com/problems/sort-characters-by-frequency/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input:
|
||||||
|
"tree"
|
||||||
|
|
||||||
|
Output:
|
||||||
|
"eert"
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
'e' appears twice while 'r' and 't' both appear once.
|
||||||
|
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public String frequencySort(String s) {
|
||||||
|
Map<Character, Integer> frequencyForNum = new HashMap<>();
|
||||||
|
for (char c : s.toCharArray())
|
||||||
|
frequencyForNum.put(c, frequencyForNum.getOrDefault(c, 0) + 1);
|
||||||
|
|
||||||
|
List<Character>[] frequencyBucket = new ArrayList[s.length() + 1];
|
||||||
|
for (char c : frequencyForNum.keySet()) {
|
||||||
|
int f = frequencyForNum.get(c);
|
||||||
|
if (frequencyBucket[f] == null) {
|
||||||
|
frequencyBucket[f] = new ArrayList<>();
|
||||||
|
}
|
||||||
|
frequencyBucket[f].add(c);
|
||||||
|
}
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
for (int i = frequencyBucket.length - 1; i >= 0; i--) {
|
||||||
|
if (frequencyBucket[i] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (char c : frequencyBucket[i]) {
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
str.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 荷兰国旗问题
|
||||||
|
|
||||||
|
荷兰国旗包含三种颜色:红、白、蓝。
|
||||||
|
|
||||||
|
有三种颜色的球,算法的目标是将这三种球按颜色顺序正确地排列。
|
||||||
|
|
||||||
|
它其实是三向切分快速排序的一种变种,在三向切分快速排序中,每次切分都将数组分成三个区间:小于切分元素、等于切分元素、大于切分元素,而该算法是将数组分成三个区间:等于红色、等于白色、等于蓝色。
|
||||||
|
|
||||||
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7a3215ec-6fb7-4935-8b0d-cb408208f7cb.png"/> </div><br>
|
||||||
|
|
||||||
|
## 按颜色进行排序
|
||||||
|
|
||||||
|
[75. Sort Colors (Medium)](https://leetcode.com/problems/sort-colors/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [2,0,2,1,1,0]
|
||||||
|
Output: [0,0,1,1,2,2]
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:只有 0/1/2 三种颜色。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public void sortColors(int[] nums) {
|
||||||
|
int zero = -1, one = 0, two = nums.length;
|
||||||
|
while (one < two) {
|
||||||
|
if (nums[one] == 0) {
|
||||||
|
swap(nums, ++zero, one++);
|
||||||
|
} else if (nums[one] == 2) {
|
||||||
|
swap(nums, --two, one);
|
||||||
|
} else {
|
||||||
|
++one;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swap(int[] nums, int i, int j) {
|
||||||
|
int t = nums[i];
|
||||||
|
nums[i] = nums[j];
|
||||||
|
nums[j] = t;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
1274
docs/notes/Leetcode 题解 - 搜索.md
Normal file
515
docs/notes/Leetcode 题解 - 数学.md
Normal file
@ -0,0 +1,515 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [素数分解](#素数分解)
|
||||||
|
* [整除](#整除)
|
||||||
|
* [最大公约数最小公倍数](#最大公约数最小公倍数)
|
||||||
|
* [生成素数序列](#生成素数序列)
|
||||||
|
* [最大公约数](#最大公约数)
|
||||||
|
* [使用位操作和减法求解最大公约数](#使用位操作和减法求解最大公约数)
|
||||||
|
* [进制转换](#进制转换)
|
||||||
|
* [7 进制](#7-进制)
|
||||||
|
* [16 进制](#16-进制)
|
||||||
|
* [26 进制](#26-进制)
|
||||||
|
* [阶乘](#阶乘)
|
||||||
|
* [统计阶乘尾部有多少个 0](#统计阶乘尾部有多少个-0)
|
||||||
|
* [字符串加法减法](#字符串加法减法)
|
||||||
|
* [二进制加法](#二进制加法)
|
||||||
|
* [字符串加法](#字符串加法)
|
||||||
|
* [相遇问题](#相遇问题)
|
||||||
|
* [改变数组元素使所有的数组元素都相等](#改变数组元素使所有的数组元素都相等)
|
||||||
|
* [解法 1](#解法-1)
|
||||||
|
* [解法 2](#解法-2)
|
||||||
|
* [多数投票问题](#多数投票问题)
|
||||||
|
* [数组中出现次数多于 n / 2 的元素](#数组中出现次数多于-n--2-的元素)
|
||||||
|
* [其它](#其它)
|
||||||
|
* [平方数](#平方数)
|
||||||
|
* [3 的 n 次方](#3-的-n-次方)
|
||||||
|
* [乘积数组](#乘积数组)
|
||||||
|
* [找出数组中的乘积最大的三个数](#找出数组中的乘积最大的三个数)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 素数分解
|
||||||
|
|
||||||
|
每一个数都可以分解成素数的乘积,例如 84 = 2<sup>2</sup> \* 3<sup>1</sup> \* 5<sup>0</sup> \* 7<sup>1</sup> \* 11<sup>0</sup> \* 13<sup>0</sup> \* 17<sup>0</sup> \* …
|
||||||
|
|
||||||
|
# 整除
|
||||||
|
|
||||||
|
令 x = 2<sup>m0</sup> \* 3<sup>m1</sup> \* 5<sup>m2</sup> \* 7<sup>m3</sup> \* 11<sup>m4</sup> \* …
|
||||||
|
|
||||||
|
令 y = 2<sup>n0</sup> \* 3<sup>n1</sup> \* 5<sup>n2</sup> \* 7<sup>n3</sup> \* 11<sup>n4</sup> \* …
|
||||||
|
|
||||||
|
如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= ni。
|
||||||
|
|
||||||
|
## 最大公约数最小公倍数
|
||||||
|
|
||||||
|
x 和 y 的最大公约数为:gcd(x,y) = 2<sup>min(m0,n0)</sup> \* 3<sup>min(m1,n1)</sup> \* 5<sup>min(m2,n2)</sup> \* ...
|
||||||
|
|
||||||
|
x 和 y 的最小公倍数为:lcm(x,y) = 2<sup>max(m0,n0)</sup> \* 3<sup>max(m1,n1)</sup> \* 5<sup>max(m2,n2)</sup> \* ...
|
||||||
|
|
||||||
|
## 生成素数序列
|
||||||
|
|
||||||
|
[204. Count Primes (Easy)](https://leetcode.com/problems/count-primes/description/)
|
||||||
|
|
||||||
|
埃拉托斯特尼筛法在每次找到一个素数时,将能被素数整除的数排除掉。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int countPrimes(int n) {
|
||||||
|
boolean[] notPrimes = new boolean[n + 1];
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 2; i < n; i++) {
|
||||||
|
if (notPrimes[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
// 从 i * i 开始,因为如果 k < i,那么 k * i 在之前就已经被去除过了
|
||||||
|
for (long j = (long) (i) * i; j < n; j += i) {
|
||||||
|
notPrimes[(int) j] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 最大公约数
|
||||||
|
|
||||||
|
```java
|
||||||
|
int gcd(int a, int b) {
|
||||||
|
return b == 0 ? a : gcd(b, a % b);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
最小公倍数为两数的乘积除以最大公约数。
|
||||||
|
|
||||||
|
```java
|
||||||
|
int lcm(int a, int b) {
|
||||||
|
return a * b / gcd(a, b);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用位操作和减法求解最大公约数
|
||||||
|
|
||||||
|
[编程之美:2.7](#)
|
||||||
|
|
||||||
|
对于 a 和 b 的最大公约数 f(a, b),有:
|
||||||
|
|
||||||
|
- 如果 a 和 b 均为偶数,f(a, b) = 2\*f(a/2, b/2);
|
||||||
|
- 如果 a 是偶数 b 是奇数,f(a, b) = f(a/2, b);
|
||||||
|
- 如果 b 是偶数 a 是奇数,f(a, b) = f(a, b/2);
|
||||||
|
- 如果 a 和 b 均为奇数,f(a, b) = f(b, a-b);
|
||||||
|
|
||||||
|
乘 2 和除 2 都可以转换为移位操作。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int gcd(int a, int b) {
|
||||||
|
if (a < b) {
|
||||||
|
return gcd(b, a);
|
||||||
|
}
|
||||||
|
if (b == 0) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
boolean isAEven = isEven(a), isBEven = isEven(b);
|
||||||
|
if (isAEven && isBEven) {
|
||||||
|
return 2 * gcd(a >> 1, b >> 1);
|
||||||
|
} else if (isAEven && !isBEven) {
|
||||||
|
return gcd(a >> 1, b);
|
||||||
|
} else if (!isAEven && isBEven) {
|
||||||
|
return gcd(a, b >> 1);
|
||||||
|
} else {
|
||||||
|
return gcd(b, a - b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 进制转换
|
||||||
|
|
||||||
|
## 7 进制
|
||||||
|
|
||||||
|
[504. Base 7 (Easy)](https://leetcode.com/problems/base-7/description/)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public String convertToBase7(int num) {
|
||||||
|
if (num == 0) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
boolean isNegative = num < 0;
|
||||||
|
if (isNegative) {
|
||||||
|
num = -num;
|
||||||
|
}
|
||||||
|
while (num > 0) {
|
||||||
|
sb.append(num % 7);
|
||||||
|
num /= 7;
|
||||||
|
}
|
||||||
|
String ret = sb.reverse().toString();
|
||||||
|
return isNegative ? "-" + ret : ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Java 中 static String toString(int num, int radix) 可以将一个整数转换为 radix 进制表示的字符串。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public String convertToBase7(int num) {
|
||||||
|
return Integer.toString(num, 7);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 16 进制
|
||||||
|
|
||||||
|
[405. Convert a Number to Hexadecimal (Easy)](https://leetcode.com/problems/convert-a-number-to-hexadecimal/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input:
|
||||||
|
26
|
||||||
|
|
||||||
|
Output:
|
||||||
|
"1a"
|
||||||
|
|
||||||
|
Input:
|
||||||
|
-1
|
||||||
|
|
||||||
|
Output:
|
||||||
|
"ffffffff"
|
||||||
|
```
|
||||||
|
|
||||||
|
负数要用它的补码形式。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public String toHex(int num) {
|
||||||
|
char[] map = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||||
|
if (num == 0) return "0";
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while (num != 0) {
|
||||||
|
sb.append(map[num & 0b1111]);
|
||||||
|
num >>>= 4; // 因为考虑的是补码形式,因此符号位就不能有特殊的意义,需要使用无符号右移,左边填 0
|
||||||
|
}
|
||||||
|
return sb.reverse().toString();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 26 进制
|
||||||
|
|
||||||
|
[168. Excel Sheet Column Title (Easy)](https://leetcode.com/problems/excel-sheet-column-title/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
1 -> A
|
||||||
|
2 -> B
|
||||||
|
3 -> C
|
||||||
|
...
|
||||||
|
26 -> Z
|
||||||
|
27 -> AA
|
||||||
|
28 -> AB
|
||||||
|
```
|
||||||
|
|
||||||
|
因为是从 1 开始计算的,而不是从 0 开始,因此需要对 n 执行 -1 操作。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public String convertToTitle(int n) {
|
||||||
|
if (n == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
n--;
|
||||||
|
return convertToTitle(n / 26) + (char) (n % 26 + 'A');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 阶乘
|
||||||
|
|
||||||
|
## 统计阶乘尾部有多少个 0
|
||||||
|
|
||||||
|
[172. Factorial Trailing Zeroes (Easy)](https://leetcode.com/problems/factorial-trailing-zeroes/description/)
|
||||||
|
|
||||||
|
尾部的 0 由 2 * 5 得来,2 的数量明显多于 5 的数量,因此只要统计有多少个 5 即可。
|
||||||
|
|
||||||
|
对于一个数 N,它所包含 5 的个数为:N/5 + N/5<sup>2</sup> + N/5<sup>3</sup> + ...,其中 N/5 表示不大于 N 的数中 5 的倍数贡献一个 5,N/5<sup>2</sup> 表示不大于 N 的数中 5<sup>2</sup> 的倍数再贡献一个 5 ...。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int trailingZeroes(int n) {
|
||||||
|
return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
如果统计的是 N! 的二进制表示中最低位 1 的位置,只要统计有多少个 2 即可,该题目出自 [编程之美:2.2](#) 。和求解有多少个 5 一样,2 的个数为 N/2 + N/2<sup>2</sup> + N/2<sup>3</sup> + ...
|
||||||
|
|
||||||
|
# 字符串加法减法
|
||||||
|
|
||||||
|
## 二进制加法
|
||||||
|
|
||||||
|
[67. Add Binary (Easy)](https://leetcode.com/problems/add-binary/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
a = "11"
|
||||||
|
b = "1"
|
||||||
|
Return "100".
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public String addBinary(String a, String b) {
|
||||||
|
int i = a.length() - 1, j = b.length() - 1, carry = 0;
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
while (carry == 1 || i >= 0 || j >= 0) {
|
||||||
|
if (i >= 0 && a.charAt(i--) == '1') {
|
||||||
|
carry++;
|
||||||
|
}
|
||||||
|
if (j >= 0 && b.charAt(j--) == '1') {
|
||||||
|
carry++;
|
||||||
|
}
|
||||||
|
str.append(carry % 2);
|
||||||
|
carry /= 2;
|
||||||
|
}
|
||||||
|
return str.reverse().toString();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 字符串加法
|
||||||
|
|
||||||
|
[415. Add Strings (Easy)](https://leetcode.com/problems/add-strings/description/)
|
||||||
|
|
||||||
|
字符串的值为非负整数。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public String addStrings(String num1, String num2) {
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
int carry = 0, i = num1.length() - 1, j = num2.length() - 1;
|
||||||
|
while (carry == 1 || i >= 0 || j >= 0) {
|
||||||
|
int x = i < 0 ? 0 : num1.charAt(i--) - '0';
|
||||||
|
int y = j < 0 ? 0 : num2.charAt(j--) - '0';
|
||||||
|
str.append((x + y + carry) % 10);
|
||||||
|
carry = (x + y + carry) / 10;
|
||||||
|
}
|
||||||
|
return str.reverse().toString();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 相遇问题
|
||||||
|
|
||||||
|
## 改变数组元素使所有的数组元素都相等
|
||||||
|
|
||||||
|
[462. Minimum Moves to Equal Array Elements II (Medium)](https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input:
|
||||||
|
[1,2,3]
|
||||||
|
|
||||||
|
Output:
|
||||||
|
2
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
Only two moves are needed (remember each move increments or decrements one element):
|
||||||
|
|
||||||
|
[1,2,3] => [2,2,3] => [2,2,2]
|
||||||
|
```
|
||||||
|
|
||||||
|
每次可以对一个数组元素加一或者减一,求最小的改变次数。
|
||||||
|
|
||||||
|
这是个典型的相遇问题,移动距离最小的方式是所有元素都移动到中位数。理由如下:
|
||||||
|
|
||||||
|
设 m 为中位数。a 和 b 是 m 两边的两个元素,且 b > a。要使 a 和 b 相等,它们总共移动的次数为 b - a,这个值等于 (b - m) + (m - a),也就是把这两个数移动到中位数的移动次数。
|
||||||
|
|
||||||
|
设数组长度为 N,则可以找到 N/2 对 a 和 b 的组合,使它们都移动到 m 的位置。
|
||||||
|
|
||||||
|
## 解法 1
|
||||||
|
|
||||||
|
先排序,时间复杂度:O(NlogN)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int minMoves2(int[] nums) {
|
||||||
|
Arrays.sort(nums);
|
||||||
|
int move = 0;
|
||||||
|
int l = 0, h = nums.length - 1;
|
||||||
|
while (l <= h) {
|
||||||
|
move += nums[h] - nums[l];
|
||||||
|
l++;
|
||||||
|
h--;
|
||||||
|
}
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 解法 2
|
||||||
|
|
||||||
|
使用快速选择找到中位数,时间复杂度 O(N)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int minMoves2(int[] nums) {
|
||||||
|
int move = 0;
|
||||||
|
int median = findKthSmallest(nums, nums.length / 2);
|
||||||
|
for (int num : nums) {
|
||||||
|
move += Math.abs(num - median);
|
||||||
|
}
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findKthSmallest(int[] nums, int k) {
|
||||||
|
int l = 0, h = nums.length - 1;
|
||||||
|
while (l < h) {
|
||||||
|
int j = partition(nums, l, h);
|
||||||
|
if (j == k) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j < k) {
|
||||||
|
l = j + 1;
|
||||||
|
} else {
|
||||||
|
h = j - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nums[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int partition(int[] nums, int l, int h) {
|
||||||
|
int i = l, j = h + 1;
|
||||||
|
while (true) {
|
||||||
|
while (nums[++i] < nums[l] && i < h) ;
|
||||||
|
while (nums[--j] > nums[l] && j > l) ;
|
||||||
|
if (i >= j) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
swap(nums, i, j);
|
||||||
|
}
|
||||||
|
swap(nums, l, j);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swap(int[] nums, int i, int j) {
|
||||||
|
int tmp = nums[i];
|
||||||
|
nums[i] = nums[j];
|
||||||
|
nums[j] = tmp;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 多数投票问题
|
||||||
|
|
||||||
|
## 数组中出现次数多于 n / 2 的元素
|
||||||
|
|
||||||
|
[169. Majority Element (Easy)](https://leetcode.com/problems/majority-element/description/)
|
||||||
|
|
||||||
|
先对数组排序,最中间那个数出现次数一定多于 n / 2。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int majorityElement(int[] nums) {
|
||||||
|
Arrays.sort(nums);
|
||||||
|
return nums[nums.length / 2];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
可以利用 Boyer-Moore Majority Vote Algorithm 来解决这个问题,使得时间复杂度为 O(N)。可以这么理解该算法:使用 cnt 来统计一个元素出现的次数,当遍历到的元素和统计元素不相等时,令 cnt--。如果前面查找了 i 个元素,且 cnt == 0,说明前 i 个元素没有 majority,或者有 majority,但是出现的次数少于 i / 2,因为如果多于 i / 2 的话 cnt 就一定不会为 0。此时剩下的 n - i 个元素中,majority 的数目依然多于 (n - i) / 2,因此继续查找就能找出 majority。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int majorityElement(int[] nums) {
|
||||||
|
int cnt = 0, majority = nums[0];
|
||||||
|
for (int num : nums) {
|
||||||
|
majority = (cnt == 0) ? num : majority;
|
||||||
|
cnt = (majority == num) ? cnt + 1 : cnt - 1;
|
||||||
|
}
|
||||||
|
return majority;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 其它
|
||||||
|
|
||||||
|
## 平方数
|
||||||
|
|
||||||
|
[367. Valid Perfect Square (Easy)](https://leetcode.com/problems/valid-perfect-square/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: 16
|
||||||
|
Returns: True
|
||||||
|
```
|
||||||
|
|
||||||
|
平方序列:1,4,9,16,..
|
||||||
|
|
||||||
|
间隔:3,5,7,...
|
||||||
|
|
||||||
|
间隔为等差数列,使用这个特性可以得到从 1 开始的平方序列。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isPerfectSquare(int num) {
|
||||||
|
int subNum = 1;
|
||||||
|
while (num > 0) {
|
||||||
|
num -= subNum;
|
||||||
|
subNum += 2;
|
||||||
|
}
|
||||||
|
return num == 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3 的 n 次方
|
||||||
|
|
||||||
|
[326. Power of Three (Easy)](https://leetcode.com/problems/power-of-three/description/)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isPowerOfThree(int n) {
|
||||||
|
return n > 0 && (1162261467 % n == 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 乘积数组
|
||||||
|
|
||||||
|
[238. Product of Array Except Self (Medium)](https://leetcode.com/problems/product-of-array-except-self/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
For example, given [1,2,3,4], return [24,12,8,6].
|
||||||
|
```
|
||||||
|
|
||||||
|
给定一个数组,创建一个新数组,新数组的每个元素为原始数组中除了该位置上的元素之外所有元素的乘积。
|
||||||
|
|
||||||
|
要求时间复杂度为 O(N),并且不能使用除法。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] productExceptSelf(int[] nums) {
|
||||||
|
int n = nums.length;
|
||||||
|
int[] products = new int[n];
|
||||||
|
Arrays.fill(products, 1);
|
||||||
|
int left = 1;
|
||||||
|
for (int i = 1; i < n; i++) {
|
||||||
|
left *= nums[i - 1];
|
||||||
|
products[i] *= left;
|
||||||
|
}
|
||||||
|
int right = 1;
|
||||||
|
for (int i = n - 2; i >= 0; i--) {
|
||||||
|
right *= nums[i + 1];
|
||||||
|
products[i] *= right;
|
||||||
|
}
|
||||||
|
return products;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 找出数组中的乘积最大的三个数
|
||||||
|
|
||||||
|
[628. Maximum Product of Three Numbers (Easy)](https://leetcode.com/problems/maximum-product-of-three-numbers/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [1,2,3,4]
|
||||||
|
Output: 24
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int maximumProduct(int[] nums) {
|
||||||
|
int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE, min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
|
||||||
|
for (int n : nums) {
|
||||||
|
if (n > max1) {
|
||||||
|
max3 = max2;
|
||||||
|
max2 = max1;
|
||||||
|
max1 = n;
|
||||||
|
} else if (n > max2) {
|
||||||
|
max3 = max2;
|
||||||
|
max2 = n;
|
||||||
|
} else if (n > max3) {
|
||||||
|
max3 = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n < min1) {
|
||||||
|
min2 = min1;
|
||||||
|
min1 = n;
|
||||||
|
} else if (n < min2) {
|
||||||
|
min2 = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.max(max1*max2*max3, max1*min1*min2);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
439
docs/notes/Leetcode 题解 - 数组与矩阵.md
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [1. 把数组中的 0 移到末尾](#1-把数组中的-0-移到末尾)
|
||||||
|
* [2. 改变矩阵维度](#2-改变矩阵维度)
|
||||||
|
* [3. 找出数组中最长的连续 1](#3-找出数组中最长的连续-1)
|
||||||
|
* [4. 有序矩阵查找](#4-有序矩阵查找)
|
||||||
|
* [5. 有序矩阵的 Kth Element](#5-有序矩阵的-kth-element)
|
||||||
|
* [6. 一个数组元素在 [1, n] 之间,其中一个数被替换为另一个数,找出重复的数和丢失的数](#6-一个数组元素在-[1,-n]-之间,其中一个数被替换为另一个数,找出重复的数和丢失的数)
|
||||||
|
* [7. 找出数组中重复的数,数组值在 [1, n] 之间](#7-找出数组中重复的数,数组值在-[1,-n]-之间)
|
||||||
|
* [8. 数组相邻差值的个数](#8-数组相邻差值的个数)
|
||||||
|
* [9. 数组的度](#9-数组的度)
|
||||||
|
* [10. 对角元素相等的矩阵](#10-对角元素相等的矩阵)
|
||||||
|
* [11. 嵌套数组](#11-嵌套数组)
|
||||||
|
* [12. 分隔数组](#12-分隔数组)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 1. 把数组中的 0 移到末尾
|
||||||
|
|
||||||
|
[283. Move Zeroes (Easy)](https://leetcode.com/problems/move-zeroes/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public void moveZeroes(int[] nums) {
|
||||||
|
int idx = 0;
|
||||||
|
for (int num : nums) {
|
||||||
|
if (num != 0) {
|
||||||
|
nums[idx++] = num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (idx < nums.length) {
|
||||||
|
nums[idx++] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 2. 改变矩阵维度
|
||||||
|
|
||||||
|
[566. Reshape the Matrix (Easy)](https://leetcode.com/problems/reshape-the-matrix/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input:
|
||||||
|
nums =
|
||||||
|
[[1,2],
|
||||||
|
[3,4]]
|
||||||
|
r = 1, c = 4
|
||||||
|
|
||||||
|
Output:
|
||||||
|
[[1,2,3,4]]
|
||||||
|
|
||||||
|
Explanation:
|
||||||
|
The row-traversing of nums is [1,2,3,4]. The new reshaped matrix is a 1 * 4 matrix, fill it row by row by using the previous list.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[][] matrixReshape(int[][] nums, int r, int c) {
|
||||||
|
int m = nums.length, n = nums[0].length;
|
||||||
|
if (m * n != r * c) {
|
||||||
|
return nums;
|
||||||
|
}
|
||||||
|
int[][] reshapedNums = new int[r][c];
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < r; i++) {
|
||||||
|
for (int j = 0; j < c; j++) {
|
||||||
|
reshapedNums[i][j] = nums[index / n][index % n];
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reshapedNums;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 3. 找出数组中最长的连续 1
|
||||||
|
|
||||||
|
[485. Max Consecutive Ones (Easy)](https://leetcode.com/problems/max-consecutive-ones/description/)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findMaxConsecutiveOnes(int[] nums) {
|
||||||
|
int max = 0, cur = 0;
|
||||||
|
for (int x : nums) {
|
||||||
|
cur = x == 0 ? 0 : cur + 1;
|
||||||
|
max = Math.max(max, cur);
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 4. 有序矩阵查找
|
||||||
|
|
||||||
|
[240. Search a 2D Matrix II (Medium)](https://leetcode.com/problems/search-a-2d-matrix-ii/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
[
|
||||||
|
[ 1, 5, 9],
|
||||||
|
[10, 11, 13],
|
||||||
|
[12, 13, 15]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean searchMatrix(int[][] matrix, int target) {
|
||||||
|
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false;
|
||||||
|
int m = matrix.length, n = matrix[0].length;
|
||||||
|
int row = 0, col = n - 1;
|
||||||
|
while (row < m && col >= 0) {
|
||||||
|
if (target == matrix[row][col]) return true;
|
||||||
|
else if (target < matrix[row][col]) col--;
|
||||||
|
else row++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 5. 有序矩阵的 Kth Element
|
||||||
|
|
||||||
|
[378. Kth Smallest Element in a Sorted Matrix ((Medium))](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
matrix = [
|
||||||
|
[ 1, 5, 9],
|
||||||
|
[10, 11, 13],
|
||||||
|
[12, 13, 15]
|
||||||
|
],
|
||||||
|
k = 8,
|
||||||
|
|
||||||
|
return 13.
|
||||||
|
```
|
||||||
|
|
||||||
|
解题参考:[Share my thoughts and Clean Java Code](https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/discuss/85173)
|
||||||
|
|
||||||
|
二分查找解法:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int kthSmallest(int[][] matrix, int k) {
|
||||||
|
int m = matrix.length, n = matrix[0].length;
|
||||||
|
int lo = matrix[0][0], hi = matrix[m - 1][n - 1];
|
||||||
|
while (lo <= hi) {
|
||||||
|
int mid = lo + (hi - lo) / 2;
|
||||||
|
int cnt = 0;
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
for (int j = 0; j < n && matrix[i][j] <= mid; j++) {
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cnt < k) lo = mid + 1;
|
||||||
|
else hi = mid - 1;
|
||||||
|
}
|
||||||
|
return lo;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
堆解法:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int kthSmallest(int[][] matrix, int k) {
|
||||||
|
int m = matrix.length, n = matrix[0].length;
|
||||||
|
PriorityQueue<Tuple> pq = new PriorityQueue<Tuple>();
|
||||||
|
for(int j = 0; j < n; j++) pq.offer(new Tuple(0, j, matrix[0][j]));
|
||||||
|
for(int i = 0; i < k - 1; i++) { // 小根堆,去掉 k - 1 个堆顶元素,此时堆顶元素就是第 k 的数
|
||||||
|
Tuple t = pq.poll();
|
||||||
|
if(t.x == m - 1) continue;
|
||||||
|
pq.offer(new Tuple(t.x + 1, t.y, matrix[t.x + 1][t.y]));
|
||||||
|
}
|
||||||
|
return pq.poll().val;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Tuple implements Comparable<Tuple> {
|
||||||
|
int x, y, val;
|
||||||
|
public Tuple(int x, int y, int val) {
|
||||||
|
this.x = x; this.y = y; this.val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Tuple that) {
|
||||||
|
return this.val - that.val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 6. 一个数组元素在 [1, n] 之间,其中一个数被替换为另一个数,找出重复的数和丢失的数
|
||||||
|
|
||||||
|
[645. Set Mismatch (Easy)](https://leetcode.com/problems/set-mismatch/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: nums = [1,2,2,4]
|
||||||
|
Output: [2,3]
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: nums = [1,2,2,4]
|
||||||
|
Output: [2,3]
|
||||||
|
```
|
||||||
|
|
||||||
|
最直接的方法是先对数组进行排序,这种方法时间复杂度为 O(NlogN)。本题可以以 O(N) 的时间复杂度、O(1) 空间复杂度来求解。
|
||||||
|
|
||||||
|
主要思想是通过交换数组元素,使得数组上的元素在正确的位置上。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] findErrorNums(int[] nums) {
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
while (nums[i] != i + 1 && nums[nums[i] - 1] != nums[i]) {
|
||||||
|
swap(nums, i, nums[i] - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
if (nums[i] != i + 1) {
|
||||||
|
return new int[]{nums[i], i + 1};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swap(int[] nums, int i, int j) {
|
||||||
|
int tmp = nums[i];
|
||||||
|
nums[i] = nums[j];
|
||||||
|
nums[j] = tmp;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
类似题目:
|
||||||
|
|
||||||
|
- [448. Find All Numbers Disappeared in an Array (Easy)](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/description/),寻找所有丢失的元素
|
||||||
|
- [442. Find All Duplicates in an Array (Medium)](https://leetcode.com/problems/find-all-duplicates-in-an-array/description/),寻找所有重复的元素。
|
||||||
|
|
||||||
|
# 7. 找出数组中重复的数,数组值在 [1, n] 之间
|
||||||
|
|
||||||
|
[287. Find the Duplicate Number (Medium)](https://leetcode.com/problems/find-the-duplicate-number/description/)
|
||||||
|
|
||||||
|
要求不能修改数组,也不能使用额外的空间。
|
||||||
|
|
||||||
|
二分查找解法:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findDuplicate(int[] nums) {
|
||||||
|
int l = 1, h = nums.length - 1;
|
||||||
|
while (l <= h) {
|
||||||
|
int mid = l + (h - l) / 2;
|
||||||
|
int cnt = 0;
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
if (nums[i] <= mid) cnt++;
|
||||||
|
}
|
||||||
|
if (cnt > mid) h = mid - 1;
|
||||||
|
else l = mid + 1;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
双指针解法,类似于有环链表中找出环的入口:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findDuplicate(int[] nums) {
|
||||||
|
int slow = nums[0], fast = nums[nums[0]];
|
||||||
|
while (slow != fast) {
|
||||||
|
slow = nums[slow];
|
||||||
|
fast = nums[nums[fast]];
|
||||||
|
}
|
||||||
|
fast = 0;
|
||||||
|
while (slow != fast) {
|
||||||
|
slow = nums[slow];
|
||||||
|
fast = nums[fast];
|
||||||
|
}
|
||||||
|
return slow;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 8. 数组相邻差值的个数
|
||||||
|
|
||||||
|
[667. Beautiful Arrangement II (Medium)](https://leetcode.com/problems/beautiful-arrangement-ii/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: n = 3, k = 2
|
||||||
|
Output: [1, 3, 2]
|
||||||
|
Explanation: The [1, 3, 2] has three different positive integers ranging from 1 to 3, and the [2, 1] has exactly 2 distinct integers: 1 and 2.
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:数组元素为 1\~n 的整数,要求构建数组,使得相邻元素的差值不相同的个数为 k。
|
||||||
|
|
||||||
|
让前 k+1 个元素构建出 k 个不相同的差值,序列为:1 k+1 2 k 3 k-1 ... k/2 k/2+1.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] constructArray(int n, int k) {
|
||||||
|
int[] ret = new int[n];
|
||||||
|
ret[0] = 1;
|
||||||
|
for (int i = 1, interval = k; i <= k; i++, interval--) {
|
||||||
|
ret[i] = i % 2 == 1 ? ret[i - 1] + interval : ret[i - 1] - interval;
|
||||||
|
}
|
||||||
|
for (int i = k + 1; i < n; i++) {
|
||||||
|
ret[i] = i + 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 9. 数组的度
|
||||||
|
|
||||||
|
[697. Degree of an Array (Easy)](https://leetcode.com/problems/degree-of-an-array/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [1,2,2,3,1,4,2]
|
||||||
|
Output: 6
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:数组的度定义为元素出现的最高频率,例如上面的数组度为 3。要求找到一个最小的子数组,这个子数组的度和原数组一样。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findShortestSubArray(int[] nums) {
|
||||||
|
Map<Integer, Integer> numsCnt = new HashMap<>();
|
||||||
|
Map<Integer, Integer> numsLastIndex = new HashMap<>();
|
||||||
|
Map<Integer, Integer> numsFirstIndex = new HashMap<>();
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
int num = nums[i];
|
||||||
|
numsCnt.put(num, numsCnt.getOrDefault(num, 0) + 1);
|
||||||
|
numsLastIndex.put(num, i);
|
||||||
|
if (!numsFirstIndex.containsKey(num)) {
|
||||||
|
numsFirstIndex.put(num, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int maxCnt = 0;
|
||||||
|
for (int num : nums) {
|
||||||
|
maxCnt = Math.max(maxCnt, numsCnt.get(num));
|
||||||
|
}
|
||||||
|
int ret = nums.length;
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
int num = nums[i];
|
||||||
|
int cnt = numsCnt.get(num);
|
||||||
|
if (cnt != maxCnt) continue;
|
||||||
|
ret = Math.min(ret, numsLastIndex.get(num) - numsFirstIndex.get(num) + 1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 10. 对角元素相等的矩阵
|
||||||
|
|
||||||
|
[766. Toeplitz Matrix (Easy)](https://leetcode.com/problems/toeplitz-matrix/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
1234
|
||||||
|
5123
|
||||||
|
9512
|
||||||
|
|
||||||
|
In the above grid, the diagonals are "[9]", "[5, 5]", "[1, 1, 1]", "[2, 2, 2]", "[3, 3]", "[4]", and in each diagonal all elements are the same, so the answer is True.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isToeplitzMatrix(int[][] matrix) {
|
||||||
|
for (int i = 0; i < matrix[0].length; i++) {
|
||||||
|
if (!check(matrix, matrix[0][i], 0, i)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < matrix.length; i++) {
|
||||||
|
if (!check(matrix, matrix[i][0], i, 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean check(int[][] matrix, int expectValue, int row, int col) {
|
||||||
|
if (row >= matrix.length || col >= matrix[0].length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (matrix[row][col] != expectValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return check(matrix, expectValue, row + 1, col + 1);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 11. 嵌套数组
|
||||||
|
|
||||||
|
[565. Array Nesting (Medium)](https://leetcode.com/problems/array-nesting/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: A = [5,4,0,3,1,6,2]
|
||||||
|
Output: 4
|
||||||
|
Explanation:
|
||||||
|
A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2.
|
||||||
|
|
||||||
|
One of the longest S[K]:
|
||||||
|
S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0}
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:S[i] 表示一个集合,集合的第一个元素是 A[i],第二个元素是 A[A[i]],如此嵌套下去。求最大的 S[i]。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int arrayNesting(int[] nums) {
|
||||||
|
int max = 0;
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
int cnt = 0;
|
||||||
|
for (int j = i; nums[j] != -1; ) {
|
||||||
|
cnt++;
|
||||||
|
int t = nums[j];
|
||||||
|
nums[j] = -1; // 标记该位置已经被访问
|
||||||
|
j = t;
|
||||||
|
|
||||||
|
}
|
||||||
|
max = Math.max(max, cnt);
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 12. 分隔数组
|
||||||
|
|
||||||
|
[769. Max Chunks To Make Sorted (Medium)](https://leetcode.com/problems/max-chunks-to-make-sorted/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: arr = [1,0,2,3,4]
|
||||||
|
Output: 4
|
||||||
|
Explanation:
|
||||||
|
We can split into two chunks, such as [1, 0], [2, 3, 4].
|
||||||
|
However, splitting into [1, 0], [2], [3], [4] is the highest number of chunks possible.
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:分隔数组,使得对每部分排序后数组就为有序。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int maxChunksToSorted(int[] arr) {
|
||||||
|
if (arr == null) return 0;
|
||||||
|
int ret = 0;
|
||||||
|
int right = arr[0];
|
||||||
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
right = Math.max(right, arr[i]);
|
||||||
|
if (right == i) ret++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
226
docs/notes/Leetcode 题解 - 栈和队列.md
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [用栈实现队列](#用栈实现队列)
|
||||||
|
* [用队列实现栈](#用队列实现栈)
|
||||||
|
* [最小值栈](#最小值栈)
|
||||||
|
* [用栈实现括号匹配](#用栈实现括号匹配)
|
||||||
|
* [数组中元素与下一个比它大的元素之间的距离](#数组中元素与下一个比它大的元素之间的距离)
|
||||||
|
* [循环数组中比当前元素大的下一个元素](#循环数组中比当前元素大的下一个元素)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 用栈实现队列
|
||||||
|
|
||||||
|
[232. Implement Queue using Stacks (Easy)](https://leetcode.com/problems/implement-queue-using-stacks/description/)
|
||||||
|
|
||||||
|
栈的顺序为后进先出,而队列的顺序为先进先出。使用两个栈实现队列,一个元素需要经过两个栈才能出队列,在经过第一个栈时元素顺序被反转,经过第二个栈时再次被反转,此时就是先进先出顺序。
|
||||||
|
|
||||||
|
```java
|
||||||
|
class MyQueue {
|
||||||
|
|
||||||
|
private Stack<Integer> in = new Stack<>();
|
||||||
|
private Stack<Integer> out = new Stack<>();
|
||||||
|
|
||||||
|
public void push(int x) {
|
||||||
|
in.push(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int pop() {
|
||||||
|
in2out();
|
||||||
|
return out.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int peek() {
|
||||||
|
in2out();
|
||||||
|
return out.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void in2out() {
|
||||||
|
if (out.isEmpty()) {
|
||||||
|
while (!in.isEmpty()) {
|
||||||
|
out.push(in.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean empty() {
|
||||||
|
return in.isEmpty() && out.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 用队列实现栈
|
||||||
|
|
||||||
|
[225. Implement Stack using Queues (Easy)](https://leetcode.com/problems/implement-stack-using-queues/description/)
|
||||||
|
|
||||||
|
在将一个元素 x 插入队列时,为了维护原来的后进先出顺序,需要让 x 插入队列首部。而队列的默认插入顺序是队列尾部,因此在将 x 插入队列尾部之后,需要让除了 x 之外的所有元素出队列,再入队列。
|
||||||
|
|
||||||
|
```java
|
||||||
|
class MyStack {
|
||||||
|
|
||||||
|
private Queue<Integer> queue;
|
||||||
|
|
||||||
|
public MyStack() {
|
||||||
|
queue = new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void push(int x) {
|
||||||
|
queue.add(x);
|
||||||
|
int cnt = queue.size();
|
||||||
|
while (cnt-- > 1) {
|
||||||
|
queue.add(queue.poll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int pop() {
|
||||||
|
return queue.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int top() {
|
||||||
|
return queue.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean empty() {
|
||||||
|
return queue.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 最小值栈
|
||||||
|
|
||||||
|
[155. Min Stack (Easy)](https://leetcode.com/problems/min-stack/description/)
|
||||||
|
|
||||||
|
```java
|
||||||
|
class MinStack {
|
||||||
|
|
||||||
|
private Stack<Integer> dataStack;
|
||||||
|
private Stack<Integer> minStack;
|
||||||
|
private int min;
|
||||||
|
|
||||||
|
public MinStack() {
|
||||||
|
dataStack = new Stack<>();
|
||||||
|
minStack = new Stack<>();
|
||||||
|
min = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void push(int x) {
|
||||||
|
dataStack.add(x);
|
||||||
|
min = Math.min(min, x);
|
||||||
|
minStack.add(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pop() {
|
||||||
|
dataStack.pop();
|
||||||
|
minStack.pop();
|
||||||
|
min = minStack.isEmpty() ? Integer.MAX_VALUE : minStack.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int top() {
|
||||||
|
return dataStack.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMin() {
|
||||||
|
return minStack.peek();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
对于实现最小值队列问题,可以先将队列使用栈来实现,然后就将问题转换为最小值栈,这个问题出现在 编程之美:3.7。
|
||||||
|
|
||||||
|
# 用栈实现括号匹配
|
||||||
|
|
||||||
|
[20. Valid Parentheses (Easy)](https://leetcode.com/problems/valid-parentheses/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
"()[]{}"
|
||||||
|
|
||||||
|
Output : true
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isValid(String s) {
|
||||||
|
Stack<Character> stack = new Stack<>();
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
if (c == '(' || c == '{' || c == '[') {
|
||||||
|
stack.push(c);
|
||||||
|
} else {
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char cStack = stack.pop();
|
||||||
|
boolean b1 = c == ')' && cStack != '(';
|
||||||
|
boolean b2 = c == ']' && cStack != '[';
|
||||||
|
boolean b3 = c == '}' && cStack != '{';
|
||||||
|
if (b1 || b2 || b3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stack.isEmpty();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 数组中元素与下一个比它大的元素之间的距离
|
||||||
|
|
||||||
|
[739. Daily Temperatures (Medium)](https://leetcode.com/problems/daily-temperatures/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [73, 74, 75, 71, 69, 72, 76, 73]
|
||||||
|
Output: [1, 1, 4, 2, 1, 1, 0, 0]
|
||||||
|
```
|
||||||
|
|
||||||
|
在遍历数组时用栈把数组中的数存起来,如果当前遍历的数比栈顶元素来的大,说明栈顶元素的下一个比它大的数就是当前元素。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] dailyTemperatures(int[] temperatures) {
|
||||||
|
int n = temperatures.length;
|
||||||
|
int[] dist = new int[n];
|
||||||
|
Stack<Integer> indexs = new Stack<>();
|
||||||
|
for (int curIndex = 0; curIndex < n; curIndex++) {
|
||||||
|
while (!indexs.isEmpty() && temperatures[curIndex] > temperatures[indexs.peek()]) {
|
||||||
|
int preIndex = indexs.pop();
|
||||||
|
dist[preIndex] = curIndex - preIndex;
|
||||||
|
}
|
||||||
|
indexs.add(curIndex);
|
||||||
|
}
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 循环数组中比当前元素大的下一个元素
|
||||||
|
|
||||||
|
[503. Next Greater Element II (Medium)](https://leetcode.com/problems/next-greater-element-ii/description/)
|
||||||
|
|
||||||
|
```text
|
||||||
|
Input: [1,2,1]
|
||||||
|
Output: [2,-1,2]
|
||||||
|
Explanation: The first 1's next greater number is 2;
|
||||||
|
The number 2 can't find next greater number;
|
||||||
|
The second 1's next greater number needs to search circularly, which is also 2.
|
||||||
|
```
|
||||||
|
|
||||||
|
与 739. Daily Temperatures (Medium) 不同的是,数组是循环数组,并且最后要求的不是距离而是下一个元素。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[] nextGreaterElements(int[] nums) {
|
||||||
|
int n = nums.length;
|
||||||
|
int[] next = new int[n];
|
||||||
|
Arrays.fill(next, -1);
|
||||||
|
Stack<Integer> pre = new Stack<>();
|
||||||
|
for (int i = 0; i < n * 2; i++) {
|
||||||
|
int num = nums[i % n];
|
||||||
|
while (!pre.isEmpty() && nums[pre.peek()] < num) {
|
||||||
|
next[pre.pop()] = num;
|
||||||
|
}
|
||||||
|
if (i < n){
|
||||||
|
pre.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
1126
docs/notes/Leetcode 题解 - 树.md
Normal file
44
docs/notes/Leetcode 题解 - 目录.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [算法思想](#算法思想)
|
||||||
|
* [数据结构相关](#数据结构相关)
|
||||||
|
* [参考资料](#参考资料)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 算法思想
|
||||||
|
|
||||||
|
- [双指针](Leetcode%20题解%20-%20双指针.md)
|
||||||
|
- [排序](Leetcode%20题解%20-%20排序.md)
|
||||||
|
- [贪心思想](Leetcode%20题解%20-%20贪心思想.md)
|
||||||
|
- [二分查找](Leetcode%20题解%20-%20二分查找.md)
|
||||||
|
- [分治](Leetcode%20题解%20-%20分治.md)
|
||||||
|
- [搜索](Leetcode%20题解%20-%20搜索.md)
|
||||||
|
- [动态规划](Leetcode%20题解%20-%20动态规划.md)
|
||||||
|
- [数学](Leetcode%20题解%20-%20数学.md)
|
||||||
|
|
||||||
|
# 数据结构相关
|
||||||
|
|
||||||
|
- [链表](Leetcode%20题解%20-%20链表.md)
|
||||||
|
- [树](Leetcode%20题解%20-%20树.md)
|
||||||
|
- [栈和队列](Leetcode%20题解%20-%20栈和队列.md)
|
||||||
|
- [哈希表](Leetcode%20题解%20-%20哈希表.md)
|
||||||
|
- [字符串](Leetcode%20题解%20-%20字符串.md)
|
||||||
|
- [数组与矩阵](Leetcode%20题解%20-%20数组与矩阵.md)
|
||||||
|
- [图](Leetcode%20题解%20-%20图.md)
|
||||||
|
- [位运算](Leetcode%20题解%20-%20位运算.md)
|
||||||
|
|
||||||
|
# 参考资料
|
||||||
|
|
||||||
|
|
||||||
|
- Leetcode
|
||||||
|
- Weiss M A, 冯舜玺. 数据结构与算法分析——C 语言描述[J]. 2004.
|
||||||
|
- Sedgewick R. Algorithms[M]. Pearson Education India, 1988.
|
||||||
|
- 何海涛, 软件工程师. 剑指 Offer: 名企面试官精讲典型编程题[M]. 电子工业出版社, 2014.
|
||||||
|
- 《编程之美》小组. 编程之美[M]. 电子工业出版社, 2008.
|
||||||
|
- 左程云. 程序员代码面试指南[M]. 电子工业出版社, 2015.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
44
docs/notes/Leetcode 题解 - 目录1.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [算法思想](#算法思想)
|
||||||
|
* [数据结构相关](#数据结构相关)
|
||||||
|
* [参考资料](#参考资料)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
# 算法思想
|
||||||
|
|
||||||
|
- [双指针](notes/Leetcode%20题解%20-%20双指针.md)
|
||||||
|
- [排序](notes/Leetcode%20题解%20-%20排序.md)
|
||||||
|
- [贪心思想](notes/Leetcode%20题解%20-%20贪心思想.md)
|
||||||
|
- [二分查找](notes/Leetcode%20题解%20-%20二分查找.md)
|
||||||
|
- [分治](notes/Leetcode%20题解%20-%20分治.md)
|
||||||
|
- [搜索](notes/Leetcode%20题解%20-%20搜索.md)
|
||||||
|
- [动态规划](notes/Leetcode%20题解%20-%20动态规划.md)
|
||||||
|
- [数学](notes/Leetcode%20题解%20-%20数学.md)
|
||||||
|
|
||||||
|
# 数据结构相关
|
||||||
|
|
||||||
|
- [链表](notes/Leetcode%20题解%20-%20链表.md)
|
||||||
|
- [树](notes/Leetcode%20题解%20-%20树.md)
|
||||||
|
- [栈和队列](notes/Leetcode%20题解%20-%20栈和队列.md)
|
||||||
|
- [哈希表](notes/Leetcode%20题解%20-%20哈希表.md)
|
||||||
|
- [字符串](notes/Leetcode%20题解%20-%20字符串.md)
|
||||||
|
- [数组与矩阵](notes/Leetcode%20题解%20-%20数组与矩阵.md)
|
||||||
|
- [图](notes/Leetcode%20题解%20-%20图.md)
|
||||||
|
- [位运算](notes/Leetcode%20题解%20-%20位运算.md)
|
||||||
|
|
||||||
|
# 参考资料
|
||||||
|
|
||||||
|
|
||||||
|
- Leetcode
|
||||||
|
- Weiss M A, 冯舜玺. 数据结构与算法分析——C 语言描述[J]. 2004.
|
||||||
|
- Sedgewick R. Algorithms[M]. Pearson Education India, 1988.
|
||||||
|
- 何海涛, 软件工程师. 剑指 Offer: 名企面试官精讲典型编程题[M]. 电子工业出版社, 2014.
|
||||||
|
- 《编程之美》小组. 编程之美[M]. 电子工业出版社, 2008.
|
||||||
|
- 左程云. 程序员代码面试指南[M]. 电子工业出版社, 2015.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
372
docs/notes/Leetcode 题解 - 贪心思想.md
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [分配饼干](#分配饼干)
|
||||||
|
* [不重叠的区间个数](#不重叠的区间个数)
|
||||||
|
* [投飞镖刺破气球](#投飞镖刺破气球)
|
||||||
|
* [根据身高和序号重组队列](#根据身高和序号重组队列)
|
||||||
|
* [分隔字符串使同种字符出现在一起](#分隔字符串使同种字符出现在一起)
|
||||||
|
* [种植花朵](#种植花朵)
|
||||||
|
* [判断是否为子序列](#判断是否为子序列)
|
||||||
|
* [修改一个数成为非递减数组](#修改一个数成为非递减数组)
|
||||||
|
* [股票的最大收益](#股票的最大收益)
|
||||||
|
* [子数组最大的和](#子数组最大的和)
|
||||||
|
* [买入和售出股票最大的收益](#买入和售出股票最大的收益)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。
|
||||||
|
|
||||||
|
# 分配饼干
|
||||||
|
|
||||||
|
[455. Assign Cookies (Easy)](https://leetcode.com/problems/assign-cookies/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [1,2], [1,2,3]
|
||||||
|
Output: 2
|
||||||
|
|
||||||
|
Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2.
|
||||||
|
You have 3 cookies and their sizes are big enough to gratify all of the children,
|
||||||
|
You need to output 2.
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:每个孩子都有一个满足度,每个饼干都有一个大小,只有饼干的大小大于等于一个孩子的满足度,该孩子才会获得满足。求解最多可以获得满足的孩子数量。
|
||||||
|
|
||||||
|
给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。因为最小的孩子最容易得到满足,所以先满足最小的孩子。
|
||||||
|
|
||||||
|
证明:假设在某次选择中,贪心策略选择给当前满足度最小的孩子分配第 m 个饼干,第 m 个饼干为可以满足该孩子的最小饼干。假设存在一种最优策略,给该孩子分配第 n 个饼干,并且 m < n。我们可以发现,经过这一轮分配,贪心策略分配后剩下的饼干一定有一个比最优策略来得大。因此在后续的分配中,贪心策略一定能满足更多的孩子。也就是说不存在比贪心策略更优的策略,即贪心策略就是最优策略。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findContentChildren(int[] g, int[] s) {
|
||||||
|
Arrays.sort(g);
|
||||||
|
Arrays.sort(s);
|
||||||
|
int gi = 0, si = 0;
|
||||||
|
while (gi < g.length && si < s.length) {
|
||||||
|
if (g[gi] <= s[si]) {
|
||||||
|
gi++;
|
||||||
|
}
|
||||||
|
si++;
|
||||||
|
}
|
||||||
|
return gi;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 不重叠的区间个数
|
||||||
|
|
||||||
|
[435. Non-overlapping Intervals (Medium)](https://leetcode.com/problems/non-overlapping-intervals/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [ [1,2], [1,2], [1,2] ]
|
||||||
|
|
||||||
|
Output: 2
|
||||||
|
|
||||||
|
Explanation: You need to remove two [1,2] to make the rest of intervals non-overlapping.
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [ [1,2], [2,3] ]
|
||||||
|
|
||||||
|
Output: 0
|
||||||
|
|
||||||
|
Explanation: You don't need to remove any of the intervals since they're already non-overlapping.
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:计算让一组区间不重叠所需要移除的区间个数。
|
||||||
|
|
||||||
|
先计算最多能组成的不重叠区间个数,然后用区间总个数减去不重叠区间的个数。
|
||||||
|
|
||||||
|
在每次选择中,区间的结尾最为重要,选择的区间结尾越小,留给后面的区间的空间越大,那么后面能够选择的区间个数也就越大。
|
||||||
|
|
||||||
|
按区间的结尾进行排序,每次选择结尾最小,并且和前一个区间不重叠的区间。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int eraseOverlapIntervals(Interval[] intervals) {
|
||||||
|
if (intervals.length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Arrays.sort(intervals, Comparator.comparingInt(o -> o.end));
|
||||||
|
int cnt = 1;
|
||||||
|
int end = intervals[0].end;
|
||||||
|
for (int i = 1; i < intervals.length; i++) {
|
||||||
|
if (intervals[i].start < end) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
end = intervals[i].end;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
return intervals.length - cnt;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
使用 lambda 表示式创建 Comparator 会导致算法运行时间过长,如果注重运行时间,可以修改为普通创建 Comparator 语句:
|
||||||
|
|
||||||
|
```java
|
||||||
|
Arrays.sort(intervals, new Comparator<Interval>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Interval o1, Interval o2) {
|
||||||
|
return o1.end - o2.end;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
# 投飞镖刺破气球
|
||||||
|
|
||||||
|
[452. Minimum Number of Arrows to Burst Balloons (Medium)](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/description/)
|
||||||
|
|
||||||
|
```
|
||||||
|
Input:
|
||||||
|
[[10,16], [2,8], [1,6], [7,12]]
|
||||||
|
|
||||||
|
Output:
|
||||||
|
2
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:气球在一个水平数轴上摆放,可以重叠,飞镖垂直投向坐标轴,使得路径上的气球都会刺破。求解最小的投飞镖次数使所有气球都被刺破。
|
||||||
|
|
||||||
|
也是计算不重叠的区间个数,不过和 Non-overlapping Intervals 的区别在于,[1, 2] 和 [2, 3] 在本题中算是重叠区间。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int findMinArrowShots(int[][] points) {
|
||||||
|
if (points.length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Arrays.sort(points, Comparator.comparingInt(o -> o[1]));
|
||||||
|
int cnt = 1, end = points[0][1];
|
||||||
|
for (int i = 1; i < points.length; i++) {
|
||||||
|
if (points[i][0] <= end) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cnt++;
|
||||||
|
end = points[i][1];
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 根据身高和序号重组队列
|
||||||
|
|
||||||
|
[406. Queue Reconstruction by Height(Medium)](https://leetcode.com/problems/queue-reconstruction-by-height/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input:
|
||||||
|
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
|
||||||
|
|
||||||
|
Output:
|
||||||
|
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:一个学生用两个分量 (h, k) 描述,h 表示身高,k 表示排在前面的有 k 个学生的身高比他高或者和他一样高。
|
||||||
|
|
||||||
|
为了使插入操作不影响后续的操作,身高较高的学生应该先做插入操作,否则身高较小的学生原先正确插入的第 k 个位置可能会变成第 k+1 个位置。
|
||||||
|
|
||||||
|
身高降序、k 值升序,然后按排好序的顺序插入队列的第 k 个位置中。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int[][] reconstructQueue(int[][] people) {
|
||||||
|
if (people == null || people.length == 0 || people[0].length == 0) {
|
||||||
|
return new int[0][0];
|
||||||
|
}
|
||||||
|
Arrays.sort(people, (a, b) -> (a[0] == b[0] ? a[1] - b[1] : b[0] - a[0]));
|
||||||
|
List<int[]> queue = new ArrayList<>();
|
||||||
|
for (int[] p : people) {
|
||||||
|
queue.add(p[1], p);
|
||||||
|
}
|
||||||
|
return queue.toArray(new int[queue.size()][]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 分隔字符串使同种字符出现在一起
|
||||||
|
|
||||||
|
[763. Partition Labels (Medium)](https://leetcode.com/problems/partition-labels/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: S = "ababcbacadefegdehijhklij"
|
||||||
|
Output: [9,7,8]
|
||||||
|
Explanation:
|
||||||
|
The partition is "ababcbaca", "defegde", "hijhklij".
|
||||||
|
This is a partition so that each letter appears in at most one part.
|
||||||
|
A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits S into less parts.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public List<Integer> partitionLabels(String S) {
|
||||||
|
int[] lastIndexsOfChar = new int[26];
|
||||||
|
for (int i = 0; i < S.length(); i++) {
|
||||||
|
lastIndexsOfChar[char2Index(S.charAt(i))] = i;
|
||||||
|
}
|
||||||
|
List<Integer> partitions = new ArrayList<>();
|
||||||
|
int firstIndex = 0;
|
||||||
|
while (firstIndex < S.length()) {
|
||||||
|
int lastIndex = firstIndex;
|
||||||
|
for (int i = firstIndex; i < S.length() && i <= lastIndex; i++) {
|
||||||
|
int index = lastIndexsOfChar[char2Index(S.charAt(i))];
|
||||||
|
if (index > lastIndex) {
|
||||||
|
lastIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
partitions.add(lastIndex - firstIndex + 1);
|
||||||
|
firstIndex = lastIndex + 1;
|
||||||
|
}
|
||||||
|
return partitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int char2Index(char c) {
|
||||||
|
return c - 'a';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# 种植花朵
|
||||||
|
|
||||||
|
[605. Can Place Flowers (Easy)](https://leetcode.com/problems/can-place-flowers/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: flowerbed = [1,0,0,0,1], n = 1
|
||||||
|
Output: True
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:花朵之间至少需要一个单位的间隔,求解是否能种下 n 朵花。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean canPlaceFlowers(int[] flowerbed, int n) {
|
||||||
|
int len = flowerbed.length;
|
||||||
|
int cnt = 0;
|
||||||
|
for (int i = 0; i < len && cnt < n; i++) {
|
||||||
|
if (flowerbed[i] == 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int pre = i == 0 ? 0 : flowerbed[i - 1];
|
||||||
|
int next = i == len - 1 ? 0 : flowerbed[i + 1];
|
||||||
|
if (pre == 0 && next == 0) {
|
||||||
|
cnt++;
|
||||||
|
flowerbed[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cnt >= n;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 判断是否为子序列
|
||||||
|
|
||||||
|
[392. Is Subsequence (Medium)](https://leetcode.com/problems/is-subsequence/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
s = "abc", t = "ahbgdc"
|
||||||
|
Return true.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isSubsequence(String s, String t) {
|
||||||
|
int index = -1;
|
||||||
|
for (char c : s.toCharArray()) {
|
||||||
|
index = t.indexOf(c, index + 1);
|
||||||
|
if (index == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 修改一个数成为非递减数组
|
||||||
|
|
||||||
|
[665. Non-decreasing Array (Easy)](https://leetcode.com/problems/non-decreasing-array/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: [4,2,3]
|
||||||
|
Output: True
|
||||||
|
Explanation: You could modify the first 4 to 1 to get a non-decreasing array.
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:判断一个数组能不能只修改一个数就成为非递减数组。
|
||||||
|
|
||||||
|
在出现 nums[i] < nums[i - 1] 时,需要考虑的是应该修改数组的哪个数,使得本次修改能使 i 之前的数组成为非递减数组,并且 **不影响后续的操作** 。优先考虑令 nums[i - 1] = nums[i],因为如果修改 nums[i] = nums[i - 1] 的话,那么 nums[i] 这个数会变大,就有可能比 nums[i + 1] 大,从而影响了后续操作。还有一个比较特别的情况就是 nums[i] < nums[i - 2],只修改 nums[i - 1] = nums[i] 不能使数组成为非递减数组,只能修改 nums[i] = nums[i - 1]。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean checkPossibility(int[] nums) {
|
||||||
|
int cnt = 0;
|
||||||
|
for (int i = 1; i < nums.length && cnt < 2; i++) {
|
||||||
|
if (nums[i] >= nums[i - 1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cnt++;
|
||||||
|
if (i - 2 >= 0 && nums[i - 2] > nums[i]) {
|
||||||
|
nums[i] = nums[i - 1];
|
||||||
|
} else {
|
||||||
|
nums[i - 1] = nums[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cnt <= 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 股票的最大收益
|
||||||
|
|
||||||
|
[122. Best Time to Buy and Sell Stock II (Easy)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/)
|
||||||
|
|
||||||
|
题目描述:一次股票交易包含买入和卖出,多个交易之间不能交叉进行。
|
||||||
|
|
||||||
|
对于 [a, b, c, d],如果有 a <= b <= c <= d ,那么最大收益为 d - a。而 d - a = (d - c) + (c - b) + (b - a) ,因此当访问到一个 prices[i] 且 prices[i] - prices[i-1] > 0,那么就把 prices[i] - prices[i-1] 添加到收益中,从而在局部最优的情况下也保证全局最优。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int maxProfit(int[] prices) {
|
||||||
|
int profit = 0;
|
||||||
|
for (int i = 1; i < prices.length; i++) {
|
||||||
|
if (prices[i] > prices[i - 1]) {
|
||||||
|
profit += (prices[i] - prices[i - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return profit;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 子数组最大的和
|
||||||
|
|
||||||
|
[53. Maximum Subarray (Easy)](https://leetcode.com/problems/maximum-subarray/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
|
||||||
|
the contiguous subarray [4,-1,2,1] has the largest sum = 6.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int maxSubArray(int[] nums) {
|
||||||
|
if (nums == null || nums.length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int preSum = nums[0];
|
||||||
|
int maxSum = preSum;
|
||||||
|
for (int i = 1; i < nums.length; i++) {
|
||||||
|
preSum = preSum > 0 ? preSum + nums[i] : nums[i];
|
||||||
|
maxSum = Math.max(maxSum, preSum);
|
||||||
|
}
|
||||||
|
return maxSum;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 买入和售出股票最大的收益
|
||||||
|
|
||||||
|
[121. Best Time to Buy and Sell Stock (Easy)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/)
|
||||||
|
|
||||||
|
题目描述:只进行一次交易。
|
||||||
|
|
||||||
|
只要记录前面的最小价格,将这个最小价格作为买入价格,然后将当前的价格作为售出价格,查看当前收益是不是最大收益。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public int maxProfit(int[] prices) {
|
||||||
|
int n = prices.length;
|
||||||
|
if (n == 0) return 0;
|
||||||
|
int soFarMin = prices[0];
|
||||||
|
int max = 0;
|
||||||
|
for (int i = 1; i < n; i++) {
|
||||||
|
if (soFarMin > prices[i]) soFarMin = prices[i];
|
||||||
|
else max = Math.max(max, prices[i] - soFarMin);
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
333
docs/notes/Leetcode 题解 - 链表.md
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
<!-- GFM-TOC -->
|
||||||
|
* [找出两个链表的交点](#找出两个链表的交点)
|
||||||
|
* [链表反转](#链表反转)
|
||||||
|
* [归并两个有序的链表](#归并两个有序的链表)
|
||||||
|
* [从有序链表中删除重复节点](#从有序链表中删除重复节点)
|
||||||
|
* [删除链表的倒数第 n 个节点](#删除链表的倒数第-n-个节点)
|
||||||
|
* [交换链表中的相邻结点](#交换链表中的相邻结点)
|
||||||
|
* [链表求和](#链表求和)
|
||||||
|
* [回文链表](#回文链表)
|
||||||
|
* [分隔链表](#分隔链表)
|
||||||
|
* [链表元素按奇偶聚集](#链表元素按奇偶聚集)
|
||||||
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
|
链表是空节点,或者有一个值和一个指向下一个链表的指针,因此很多链表问题可以用递归来处理。
|
||||||
|
|
||||||
|
# 找出两个链表的交点
|
||||||
|
|
||||||
|
[160. Intersection of Two Linked Lists (Easy)](https://leetcode.com/problems/intersection-of-two-linked-lists/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
A: a1 → a2
|
||||||
|
↘
|
||||||
|
c1 → c2 → c3
|
||||||
|
↗
|
||||||
|
B: b1 → b2 → b3
|
||||||
|
```
|
||||||
|
|
||||||
|
要求:时间复杂度为 O(N),空间复杂度为 O(1)
|
||||||
|
|
||||||
|
设 A 的长度为 a + c,B 的长度为 b + c,其中 c 为尾部公共部分长度,可知 a + c + b = b + c + a。
|
||||||
|
|
||||||
|
当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B;同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
|
||||||
|
ListNode l1 = headA, l2 = headB;
|
||||||
|
while (l1 != l2) {
|
||||||
|
l1 = (l1 == null) ? headB : l1.next;
|
||||||
|
l2 = (l2 == null) ? headA : l2.next;
|
||||||
|
}
|
||||||
|
return l1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
如果只是判断是否存在交点,那么就是另一个问题,即 [编程之美 3.6]() 的问题。有两种解法:
|
||||||
|
|
||||||
|
- 把第一个链表的结尾连接到第二个链表的开头,看第二个链表是否存在环;
|
||||||
|
- 或者直接比较两个链表的最后一个节点是否相同。
|
||||||
|
|
||||||
|
# 链表反转
|
||||||
|
|
||||||
|
[206. Reverse Linked List (Easy)](https://leetcode.com/problems/reverse-linked-list/description/)
|
||||||
|
|
||||||
|
递归
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode reverseList(ListNode head) {
|
||||||
|
if (head == null || head.next == null) {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
ListNode next = head.next;
|
||||||
|
ListNode newHead = reverseList(next);
|
||||||
|
next.next = head;
|
||||||
|
head.next = null;
|
||||||
|
return newHead;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
头插法
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode reverseList(ListNode head) {
|
||||||
|
ListNode newHead = new ListNode(-1);
|
||||||
|
while (head != null) {
|
||||||
|
ListNode next = head.next;
|
||||||
|
head.next = newHead.next;
|
||||||
|
newHead.next = head;
|
||||||
|
head = next;
|
||||||
|
}
|
||||||
|
return newHead.next;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 归并两个有序的链表
|
||||||
|
|
||||||
|
[21. Merge Two Sorted Lists (Easy)](https://leetcode.com/problems/merge-two-sorted-lists/description/)
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
|
||||||
|
if (l1 == null) return l2;
|
||||||
|
if (l2 == null) return l1;
|
||||||
|
if (l1.val < l2.val) {
|
||||||
|
l1.next = mergeTwoLists(l1.next, l2);
|
||||||
|
return l1;
|
||||||
|
} else {
|
||||||
|
l2.next = mergeTwoLists(l1, l2.next);
|
||||||
|
return l2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 从有序链表中删除重复节点
|
||||||
|
|
||||||
|
[83. Remove Duplicates from Sorted List (Easy)](https://leetcode.com/problems/remove-duplicates-from-sorted-list/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Given 1->1->2, return 1->2.
|
||||||
|
Given 1->1->2->3->3, return 1->2->3.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode deleteDuplicates(ListNode head) {
|
||||||
|
if (head == null || head.next == null) return head;
|
||||||
|
head.next = deleteDuplicates(head.next);
|
||||||
|
return head.val == head.next.val ? head.next : head;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 删除链表的倒数第 n 个节点
|
||||||
|
|
||||||
|
[19. Remove Nth Node From End of List (Medium)](https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Given linked list: 1->2->3->4->5, and n = 2.
|
||||||
|
After removing the second node from the end, the linked list becomes 1->2->3->5.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode removeNthFromEnd(ListNode head, int n) {
|
||||||
|
ListNode fast = head;
|
||||||
|
while (n-- > 0) {
|
||||||
|
fast = fast.next;
|
||||||
|
}
|
||||||
|
if (fast == null) return head.next;
|
||||||
|
ListNode slow = head;
|
||||||
|
while (fast.next != null) {
|
||||||
|
fast = fast.next;
|
||||||
|
slow = slow.next;
|
||||||
|
}
|
||||||
|
slow.next = slow.next.next;
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 交换链表中的相邻结点
|
||||||
|
|
||||||
|
[24. Swap Nodes in Pairs (Medium)](https://leetcode.com/problems/swap-nodes-in-pairs/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Given 1->2->3->4, you should return the list as 2->1->4->3.
|
||||||
|
```
|
||||||
|
|
||||||
|
题目要求:不能修改结点的 val 值,O(1) 空间复杂度。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode swapPairs(ListNode head) {
|
||||||
|
ListNode node = new ListNode(-1);
|
||||||
|
node.next = head;
|
||||||
|
ListNode pre = node;
|
||||||
|
while (pre.next != null && pre.next.next != null) {
|
||||||
|
ListNode l1 = pre.next, l2 = pre.next.next;
|
||||||
|
ListNode next = l2.next;
|
||||||
|
l1.next = next;
|
||||||
|
l2.next = l1;
|
||||||
|
pre.next = l2;
|
||||||
|
|
||||||
|
pre = l1;
|
||||||
|
}
|
||||||
|
return node.next;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 链表求和
|
||||||
|
|
||||||
|
[445. Add Two Numbers II (Medium)](https://leetcode.com/problems/add-two-numbers-ii/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
|
||||||
|
Output: 7 -> 8 -> 0 -> 7
|
||||||
|
```
|
||||||
|
|
||||||
|
题目要求:不能修改原始链表。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
|
||||||
|
Stack<Integer> l1Stack = buildStack(l1);
|
||||||
|
Stack<Integer> l2Stack = buildStack(l2);
|
||||||
|
ListNode head = new ListNode(-1);
|
||||||
|
int carry = 0;
|
||||||
|
while (!l1Stack.isEmpty() || !l2Stack.isEmpty() || carry != 0) {
|
||||||
|
int x = l1Stack.isEmpty() ? 0 : l1Stack.pop();
|
||||||
|
int y = l2Stack.isEmpty() ? 0 : l2Stack.pop();
|
||||||
|
int sum = x + y + carry;
|
||||||
|
ListNode node = new ListNode(sum % 10);
|
||||||
|
node.next = head.next;
|
||||||
|
head.next = node;
|
||||||
|
carry = sum / 10;
|
||||||
|
}
|
||||||
|
return head.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stack<Integer> buildStack(ListNode l) {
|
||||||
|
Stack<Integer> stack = new Stack<>();
|
||||||
|
while (l != null) {
|
||||||
|
stack.push(l.val);
|
||||||
|
l = l.next;
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 回文链表
|
||||||
|
|
||||||
|
[234. Palindrome Linked List (Easy)](https://leetcode.com/problems/palindrome-linked-list/description/)
|
||||||
|
|
||||||
|
题目要求:以 O(1) 的空间复杂度来求解。
|
||||||
|
|
||||||
|
切成两半,把后半段反转,然后比较两半是否相等。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public boolean isPalindrome(ListNode head) {
|
||||||
|
if (head == null || head.next == null) return true;
|
||||||
|
ListNode slow = head, fast = head.next;
|
||||||
|
while (fast != null && fast.next != null) {
|
||||||
|
slow = slow.next;
|
||||||
|
fast = fast.next.next;
|
||||||
|
}
|
||||||
|
if (fast != null) slow = slow.next; // 偶数节点,让 slow 指向下一个节点
|
||||||
|
cut(head, slow); // 切成两个链表
|
||||||
|
return isEqual(head, reverse(slow));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cut(ListNode head, ListNode cutNode) {
|
||||||
|
while (head.next != cutNode) {
|
||||||
|
head = head.next;
|
||||||
|
}
|
||||||
|
head.next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ListNode reverse(ListNode head) {
|
||||||
|
ListNode newHead = null;
|
||||||
|
while (head != null) {
|
||||||
|
ListNode nextNode = head.next;
|
||||||
|
head.next = newHead;
|
||||||
|
newHead = head;
|
||||||
|
head = nextNode;
|
||||||
|
}
|
||||||
|
return newHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEqual(ListNode l1, ListNode l2) {
|
||||||
|
while (l1 != null && l2 != null) {
|
||||||
|
if (l1.val != l2.val) return false;
|
||||||
|
l1 = l1.next;
|
||||||
|
l2 = l2.next;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 分隔链表
|
||||||
|
|
||||||
|
[725. Split Linked List in Parts(Medium)](https://leetcode.com/problems/split-linked-list-in-parts/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Input:
|
||||||
|
root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
|
||||||
|
Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
|
||||||
|
Explanation:
|
||||||
|
The input has been split into consecutive parts with size difference at most 1, and earlier parts are a larger size than the later parts.
|
||||||
|
```
|
||||||
|
|
||||||
|
题目描述:把链表分隔成 k 部分,每部分的长度都应该尽可能相同,排在前面的长度应该大于等于后面的。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode[] splitListToParts(ListNode root, int k) {
|
||||||
|
int N = 0;
|
||||||
|
ListNode cur = root;
|
||||||
|
while (cur != null) {
|
||||||
|
N++;
|
||||||
|
cur = cur.next;
|
||||||
|
}
|
||||||
|
int mod = N % k;
|
||||||
|
int size = N / k;
|
||||||
|
ListNode[] ret = new ListNode[k];
|
||||||
|
cur = root;
|
||||||
|
for (int i = 0; cur != null && i < k; i++) {
|
||||||
|
ret[i] = cur;
|
||||||
|
int curSize = size + (mod-- > 0 ? 1 : 0);
|
||||||
|
for (int j = 0; j < curSize - 1; j++) {
|
||||||
|
cur = cur.next;
|
||||||
|
}
|
||||||
|
ListNode next = cur.next;
|
||||||
|
cur.next = null;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 链表元素按奇偶聚集
|
||||||
|
|
||||||
|
[328. Odd Even Linked List (Medium)](https://leetcode.com/problems/odd-even-linked-list/description/)
|
||||||
|
|
||||||
|
```html
|
||||||
|
Example:
|
||||||
|
Given 1->2->3->4->5->NULL,
|
||||||
|
return 1->3->5->2->4->NULL.
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
public ListNode oddEvenList(ListNode head) {
|
||||||
|
if (head == null) {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
ListNode odd = head, even = head.next, evenHead = even;
|
||||||
|
while (even != null && even.next != null) {
|
||||||
|
odd.next = odd.next.next;
|
||||||
|
odd = odd.next;
|
||||||
|
even.next = even.next.next;
|
||||||
|
even = even.next;
|
||||||
|
}
|
||||||
|
odd.next = evenHead;
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [595. Big Countries](#595-big-countries)
|
* [595. Big Countries](#595-big-countries)
|
||||||
* [627. Swap Salary](#627-swap-salary)
|
* [627. Swap Salary](#627-swap-salary)
|
||||||
@ -497,7 +496,7 @@ https://leetcode.com/problems/customers-who-never-order/description/
|
|||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
Curstomers 表:
|
Customers 表:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
+----+-------+
|
+----+-------+
|
||||||
@ -949,3 +948,9 @@ WHERE
|
|||||||
ORDER BY
|
ORDER BY
|
||||||
id;
|
id;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一、常用操作以及概念](#一常用操作以及概念)
|
* [一、常用操作以及概念](#一常用操作以及概念)
|
||||||
* [快捷键](#快捷键)
|
* [快捷键](#快捷键)
|
||||||
@ -158,7 +157,7 @@ Linux 发行版是 Linux 内核及各种应用软件的集成版本。
|
|||||||
- 编辑模式(Insert mode):按下 "i" 等按键之后进入,可以对文本进行编辑;
|
- 编辑模式(Insert mode):按下 "i" 等按键之后进入,可以对文本进行编辑;
|
||||||
- 指令列模式(Bottom-line mode):按下 ":" 按键之后进入,用于保存退出等操作。
|
- 指令列模式(Bottom-line mode):按下 ":" 按键之后进入,用于保存退出等操作。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br>
|
||||||
|
|
||||||
在指令列模式下,有以下命令用于离开或者保存文件。
|
在指令列模式下,有以下命令用于离开或者保存文件。
|
||||||
|
|
||||||
@ -192,25 +191,25 @@ GNU 计划,译为革奴计划,它的目标是创建一套完全自由的操
|
|||||||
|
|
||||||
IDE(ATA)全称 Advanced Technology Attachment,接口速度最大为 133MB/s,因为并口线的抗干扰性太差,且排线占用空间较大,不利电脑内部散热,已逐渐被 SATA 所取代。
|
IDE(ATA)全称 Advanced Technology Attachment,接口速度最大为 133MB/s,因为并口线的抗干扰性太差,且排线占用空间较大,不利电脑内部散热,已逐渐被 SATA 所取代。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br>
|
||||||
|
|
||||||
### 2. SATA
|
### 2. SATA
|
||||||
|
|
||||||
SATA 全称 Serial ATA,也就是使用串口的 ATA 接口,抗干扰性强,且对数据线的长度要求比 ATA 低很多,支持热插拔等功能。SATA-II 的接口速度为 300MiB/s,而新的 SATA-III 标准可达到 600MiB/s 的传输速度。SATA 的数据线也比 ATA 的细得多,有利于机箱内的空气流通,整理线材也比较方便。
|
SATA 全称 Serial ATA,也就是使用串口的 ATA 接口,抗干扰性强,且对数据线的长度要求比 ATA 低很多,支持热插拔等功能。SATA-II 的接口速度为 300MiB/s,而新的 SATA-III 标准可达到 600MiB/s 的传输速度。SATA 的数据线也比 ATA 的细得多,有利于机箱内的空气流通,整理线材也比较方便。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
### 3. SCSI
|
### 3. SCSI
|
||||||
|
|
||||||
SCSI 全称是 Small Computer System Interface(小型机系统接口),经历多代的发展,从早期的 SCSI-II 到目前的 Ultra320 SCSI 以及 Fiber-Channel(光纤通道),接口型式也多种多样。SCSI 硬盘广为工作站级个人电脑以及服务器所使用,因此会使用较为先进的技术,如碟片转速 15000rpm 的高转速,且传输时 CPU 占用率较低,但是单价也比相同容量的 ATA 及 SATA 硬盘更加昂贵。
|
SCSI 全称是 Small Computer System Interface(小型机系统接口),经历多代的发展,从早期的 SCSI-II 到目前的 Ultra320 SCSI 以及 Fiber-Channel(光纤通道),接口型式也多种多样。SCSI 硬盘广为工作站级个人电脑以及服务器所使用,因此会使用较为先进的技术,如碟片转速 15000rpm 的高转速,且传输时 CPU 占用率较低,但是单价也比相同容量的 ATA 及 SATA 硬盘更加昂贵。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
### 4. SAS
|
### 4. SAS
|
||||||
|
|
||||||
SAS(Serial Attached SCSI)是新一代的 SCSI 技术,和 SATA 硬盘相同,都是采取序列式技术以获得更高的传输速度,可达到 6Gb/s。此外也透过缩小连接线改善系统内部空间等。
|
SAS(Serial Attached SCSI)是新一代的 SCSI 技术,和 SATA 硬盘相同,都是采取序列式技术以获得更高的传输速度,可达到 6Gb/s。此外也透过缩小连接线改善系统内部空间等。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br>
|
||||||
|
|
||||||
## 磁盘的文件名
|
## 磁盘的文件名
|
||||||
|
|
||||||
@ -245,7 +244,7 @@ GPT 没有扩展分区概念,都是主分区,每个 LAB 可以分 4 个分
|
|||||||
|
|
||||||
MBR 不支持 2.2 TB 以上的硬盘,GPT 则最多支持到 2<sup>33</sup> TB = 8 ZB。
|
MBR 不支持 2.2 TB 以上的硬盘,GPT 则最多支持到 2<sup>33</sup> TB = 8 ZB。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br>
|
||||||
|
|
||||||
## 开机检测程序
|
## 开机检测程序
|
||||||
|
|
||||||
@ -253,7 +252,7 @@ MBR 不支持 2.2 TB 以上的硬盘,GPT 则最多支持到 2<sup>33</sup> TB
|
|||||||
|
|
||||||
BIOS(Basic Input/Output System,基本输入输出系统),它是一个固件(嵌入在硬件中的软件),BIOS 程序存放在断电后内容不会丢失的只读内存中。
|
BIOS(Basic Input/Output System,基本输入输出系统),它是一个固件(嵌入在硬件中的软件),BIOS 程序存放在断电后内容不会丢失的只读内存中。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br>
|
||||||
|
|
||||||
BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可以开机的磁盘,并读取磁盘第一个扇区的主要开机记录(MBR),由主要开机记录(MBR)执行其中的开机管理程序,这个开机管理程序会加载操作系统的核心文件。
|
BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可以开机的磁盘,并读取磁盘第一个扇区的主要开机记录(MBR),由主要开机记录(MBR)执行其中的开机管理程序,这个开机管理程序会加载操作系统的核心文件。
|
||||||
|
|
||||||
@ -261,7 +260,7 @@ BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可
|
|||||||
|
|
||||||
下图中,第一扇区的主要开机记录(MBR)中的开机管理程序提供了两个选单:M1、M2,M1 指向了 Windows 操作系统,而 M2 指向其它分区的启动扇区,里面包含了另外一个开机管理程序,提供了一个指向 Linux 的选单。
|
下图中,第一扇区的主要开机记录(MBR)中的开机管理程序提供了两个选单:M1、M2,M1 指向了 Windows 操作系统,而 M2 指向其它分区的启动扇区,里面包含了另外一个开机管理程序,提供了一个指向 Linux 的选单。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br>
|
||||||
|
|
||||||
安装多重引导,最好先安装 Windows 再安装 Linux。因为安装 Windows 时会覆盖掉主要开机记录(MBR),而 Linux 可以选择将开机管理程序安装在主要开机记录(MBR)或者其它分区的启动扇区,并且可以设置开机管理程序的选单。
|
安装多重引导,最好先安装 Windows 再安装 Linux。因为安装 Windows 时会覆盖掉主要开机记录(MBR),而 Linux 可以选择将开机管理程序安装在主要开机记录(MBR)或者其它分区的启动扇区,并且可以设置开机管理程序的选单。
|
||||||
|
|
||||||
@ -287,17 +286,17 @@ BIOS 不可以读取 GPT 分区表,而 UEFI 可以。
|
|||||||
- superblock:记录文件系统的整体信息,包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
|
- superblock:记录文件系统的整体信息,包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
|
||||||
- block bitmap:记录 block 是否被使用的位域。
|
- block bitmap:记录 block 是否被使用的位域。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/BSD_disk.png" width="800"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/BSD_disk.png" width="800"/> </div><br>
|
||||||
|
|
||||||
## 文件读取
|
## 文件读取
|
||||||
|
|
||||||
对于 Ext2 文件系统,当要读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block,然后把所有 block 的内容读出来。
|
对于 Ext2 文件系统,当要读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block,然后把所有 block 的内容读出来。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br>
|
||||||
|
|
||||||
而对于 FAT 文件系统,它没有 inode,每个 block 中存储着下一个 block 的编号。
|
而对于 FAT 文件系统,它没有 inode,每个 block 中存储着下一个 block 的编号。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br>
|
||||||
|
|
||||||
## 磁盘碎片
|
## 磁盘碎片
|
||||||
|
|
||||||
@ -334,7 +333,7 @@ inode 具有以下特点:
|
|||||||
|
|
||||||
inode 中记录了文件内容所在的 block 编号,但是每个 block 非常小,一个大文件随便都需要几十万的 block。而一个 inode 大小有限,无法直接引用这么多 block 编号。因此引入了间接、双间接、三间接引用。间接引用是指,让 inode 记录的引用 block 块记录引用信息。
|
inode 中记录了文件内容所在的 block 编号,但是每个 block 非常小,一个大文件随便都需要几十万的 block。而一个 inode 大小有限,无法直接引用这么多 block 编号。因此引入了间接、双间接、三间接引用。间接引用是指,让 inode 记录的引用 block 块记录引用信息。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/inode_with_signatures.jpg" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/inode_with_signatures.jpg" width="600"/> </div><br>
|
||||||
|
|
||||||
## 目录
|
## 目录
|
||||||
|
|
||||||
@ -360,7 +359,7 @@ ext3/ext4 文件系统引入了日志功能,可以利用日志来修复文件
|
|||||||
- /usr (unix software resource):所有系统默认软件都会安装到这个目录;
|
- /usr (unix software resource):所有系统默认软件都会安装到这个目录;
|
||||||
- /var (variable):存放系统或程序运行过程中的数据文件。
|
- /var (variable):存放系统或程序运行过程中的数据文件。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/linux-filesystem.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/linux-filesystem.png" width=""/> </div><br>
|
||||||
|
|
||||||
# 五、文件
|
# 五、文件
|
||||||
|
|
||||||
@ -535,7 +534,7 @@ cp [-adfilprsu] source destination
|
|||||||
-f :如果目标文件存在时,先删除目标文件
|
-f :如果目标文件存在时,先删除目标文件
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center"> <img src="pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg" width="400px"> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg" width="400px"> </div><br>
|
||||||
|
|
||||||
### 1. 实体链接
|
### 1. 实体链接
|
||||||
|
|
||||||
@ -656,7 +655,7 @@ example: find . -name "shadow*"
|
|||||||
|
|
||||||
+4、4 和 -4 的指示的时间范围如下:
|
+4、4 和 -4 的指示的时间范围如下:
|
||||||
|
|
||||||
<div align="center"> <img src="pics/658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br>
|
||||||
|
|
||||||
**② 与文件拥有者和所属群组有关的选项**
|
**② 与文件拥有者和所属群组有关的选项**
|
||||||
|
|
||||||
@ -1169,7 +1168,7 @@ dmtsai lines: 5 columns: 9
|
|||||||
| Z | zombie (terminated but not reaped by its parent) |
|
| Z | zombie (terminated but not reaped by its parent) |
|
||||||
| T | stopped (either by a job control signal or because it is being traced) |
|
| T | stopped (either by a job control signal or because it is being traced) |
|
||||||
<br>
|
<br>
|
||||||
<div align="center"> <img src="pics/76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br>
|
||||||
|
|
||||||
## SIGCHLD
|
## SIGCHLD
|
||||||
|
|
||||||
@ -1182,7 +1181,7 @@ dmtsai lines: 5 columns: 9
|
|||||||
|
|
||||||
在子进程退出时,它的进程描述符不会立即释放,这是为了让父进程得到子进程信息,父进程通过 wait() 和 waitpid() 来获得一个已经退出的子进程的信息。
|
在子进程退出时,它的进程描述符不会立即释放,这是为了让父进程得到子进程信息,父进程通过 wait() 和 waitpid() 来获得一个已经退出的子进程的信息。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/flow.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/flow.png" width=""/> </div><br>
|
||||||
|
|
||||||
## wait()
|
## wait()
|
||||||
|
|
||||||
@ -1246,3 +1245,9 @@ options 参数主要有 WNOHANG 和 WUNTRACED 两个选项,WNOHANG 可以使 w
|
|||||||
- [File system design case studies](https://www.cs.rutgers.edu/\~pxk/416/notes/13-fs-studies.html)
|
- [File system design case studies](https://www.cs.rutgers.edu/\~pxk/416/notes/13-fs-studies.html)
|
||||||
- [Programming Project #4](https://classes.soe.ucsc.edu/cmps111/Fall08/proj4.shtml)
|
- [Programming Project #4](https://classes.soe.ucsc.edu/cmps111/Fall08/proj4.shtml)
|
||||||
- [FILE SYSTEM DESIGN](http://web.cs.ucla.edu/classes/fall14/cs111/scribe/11a/index.html)
|
- [FILE SYSTEM DESIGN](http://web.cs.ucla.edu/classes/fall14/cs111/scribe/11a/index.html)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一、索引](#一索引)
|
* [一、索引](#一索引)
|
||||||
* [B+ Tree 原理](#b-tree-原理)
|
* [B+ Tree 原理](#b-tree-原理)
|
||||||
@ -43,7 +42,7 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
|
|||||||
|
|
||||||
在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 key<sub>i</sub> 和 key<sub>i+1</sub>,且不为 null,则该指针指向节点的所有 key 大于等于 key<sub>i</sub> 且小于等于 key<sub>i+1</sub>。
|
在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 key<sub>i</sub> 和 key<sub>i+1</sub>,且不为 null,则该指针指向节点的所有 key 大于等于 key<sub>i</sub> 且小于等于 key<sub>i+1</sub>。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/10a6d3ee-04b2-46b4-b171-d596e5ab0f84.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/10a6d3ee-04b2-46b4-b171-d596e5ab0f84.jpg"/> </div><br>
|
||||||
|
|
||||||
### 2. 操作
|
### 2. 操作
|
||||||
|
|
||||||
@ -85,11 +84,11 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
|
|||||||
|
|
||||||
InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
|
InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/4f151e62-6160-47f1-9eff-47b1f4dea4e9.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4f151e62-6160-47f1-9eff-47b1f4dea4e9.jpg"/> </div><br>
|
||||||
|
|
||||||
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。
|
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/40f29839-fd56-4ed0-9353-39dfe6f0bba5.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/40f29839-fd56-4ed0-9353-39dfe6f0bba5.jpg"/> </div><br>
|
||||||
|
|
||||||
### 2. 哈希索引
|
### 2. 哈希索引
|
||||||
|
|
||||||
@ -351,7 +350,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
|||||||
|
|
||||||
当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。
|
当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
|
||||||
|
|
||||||
## 垂直切分
|
## 垂直切分
|
||||||
|
|
||||||
@ -359,7 +358,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
|||||||
|
|
||||||
在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。
|
在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
|
||||||
|
|
||||||
## Sharding 策略
|
## Sharding 策略
|
||||||
|
|
||||||
@ -390,10 +389,10 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
|||||||
主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。
|
主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。
|
||||||
|
|
||||||
- **binlog 线程** :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
|
- **binlog 线程** :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
|
||||||
- **I/O 线程** :负责从主服务器上读取二进制日志,并写入从服务器的重放日志(Replay log)中。
|
- **I/O 线程** :负责从主服务器上读取二进制日志,并写入从服务器的中继日志(Relay log)。
|
||||||
- **SQL 线程** :负责读取重放日志并重放其中的 SQL 语句。
|
- **SQL 线程** :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中执行。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/master-slave.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/master-slave.png"/> </div><br>
|
||||||
|
|
||||||
## 读写分离
|
## 读写分离
|
||||||
|
|
||||||
@ -407,7 +406,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
|||||||
|
|
||||||
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
|
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/master-slave-proxy.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/master-slave-proxy.png"/> </div><br>
|
||||||
|
|
||||||
# 参考资料
|
# 参考资料
|
||||||
|
|
||||||
@ -422,3 +421,9 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
|||||||
- [How Sharding Works](https://medium.com/@jeeyoungk/how-sharding-works-b4dec46b3f6)
|
- [How Sharding Works](https://medium.com/@jeeyoungk/how-sharding-works-b4dec46b3f6)
|
||||||
- [大众点评订单系统分库分表实践](https://tech.meituan.com/dianping_order_db_sharding.html)
|
- [大众点评订单系统分库分表实践](https://tech.meituan.com/dianping_order_db_sharding.html)
|
||||||
- [B + 树](https://zh.wikipedia.org/wiki/B%2B%E6%A0%91)
|
- [B + 树](https://zh.wikipedia.org/wiki/B%2B%E6%A0%91)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
<!-- GFM-TOC -->
|
||||||
<!-- GFM-TOC -->
|
|
||||||
* [一、概述](#一概述)
|
* [一、概述](#一概述)
|
||||||
* [二、数据类型](#二数据类型)
|
* [二、数据类型](#二数据类型)
|
||||||
* [STRING](#string)
|
* [STRING](#string)
|
||||||
@ -68,7 +67,7 @@ Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,
|
|||||||
|
|
||||||
## STRING
|
## STRING
|
||||||
|
|
||||||
<div align="center"> <img src="pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
|
||||||
|
|
||||||
```html
|
```html
|
||||||
> set hello world
|
> set hello world
|
||||||
@ -83,7 +82,7 @@ OK
|
|||||||
|
|
||||||
## LIST
|
## LIST
|
||||||
|
|
||||||
<div align="center"> <img src="pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
|
||||||
|
|
||||||
```html
|
```html
|
||||||
> rpush list-key item
|
> rpush list-key item
|
||||||
@ -111,7 +110,7 @@ OK
|
|||||||
|
|
||||||
## SET
|
## SET
|
||||||
|
|
||||||
<div align="center"> <img src="pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
|
||||||
|
|
||||||
```html
|
```html
|
||||||
> sadd set-key item
|
> sadd set-key item
|
||||||
@ -145,7 +144,7 @@ OK
|
|||||||
|
|
||||||
## HASH
|
## HASH
|
||||||
|
|
||||||
<div align="center"> <img src="pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
|
||||||
|
|
||||||
```html
|
```html
|
||||||
> hset hash-key sub-key1 value1
|
> hset hash-key sub-key1 value1
|
||||||
@ -176,7 +175,7 @@ OK
|
|||||||
|
|
||||||
## ZSET
|
## ZSET
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
|
||||||
|
|
||||||
```html
|
```html
|
||||||
> zadd zset-key 728 member1
|
> zadd zset-key 728 member1
|
||||||
@ -318,11 +317,11 @@ int dictRehash(dict *d, int n) {
|
|||||||
|
|
||||||
跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。
|
跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png" width="600px"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png" width="600px"/> </div><br>
|
||||||
|
|
||||||
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。
|
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png" width="600px"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png" width="600px"/> </div><br>
|
||||||
|
|
||||||
与红黑树等平衡树相比,跳跃表具有以下优点:
|
与红黑树等平衡树相比,跳跃表具有以下优点:
|
||||||
|
|
||||||
@ -364,7 +363,7 @@ List 是一个双向链表,可以通过 lpop 和 lpush 写入和读取消息
|
|||||||
|
|
||||||
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
|
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
|
||||||
|
|
||||||
可以使用 Reids 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
|
可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
|
||||||
|
|
||||||
## 其它
|
## 其它
|
||||||
|
|
||||||
@ -406,7 +405,7 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除
|
|||||||
|
|
||||||
可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。
|
可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。
|
||||||
|
|
||||||
Reids 具体有 6 种淘汰策略:
|
Redis 具体有 6 种淘汰策略:
|
||||||
|
|
||||||
| 策略 | 描述 |
|
| 策略 | 描述 |
|
||||||
| :--: | :--: |
|
| :--: | :--: |
|
||||||
@ -473,7 +472,7 @@ Redis 服务器是一个事件驱动程序。
|
|||||||
|
|
||||||
Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。
|
Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png" width=""/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png" width=""/> </div><br>
|
||||||
|
|
||||||
## 时间事件
|
## 时间事件
|
||||||
|
|
||||||
@ -526,7 +525,7 @@ def main():
|
|||||||
|
|
||||||
从事件处理的角度来看,服务器运行流程如下:
|
从事件处理的角度来看,服务器运行流程如下:
|
||||||
|
|
||||||
<div align="center"> <img src="pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="350"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="350"/> </div><br>
|
||||||
|
|
||||||
# 十一、复制
|
# 十一、复制
|
||||||
|
|
||||||
@ -546,7 +545,7 @@ def main():
|
|||||||
|
|
||||||
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。
|
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
|
||||||
|
|
||||||
# 十二、Sentinel
|
# 十二、Sentinel
|
||||||
|
|
||||||
@ -556,7 +555,7 @@ Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入
|
|||||||
|
|
||||||
分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级别的性能提升。
|
分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级别的性能提升。
|
||||||
|
|
||||||
假设有 4 个 Reids 实例 R0,R1,R2,R3,还有很多表示用户的键 user:1,user:2,... ,有不同的方式来选择一个指定的键存储在哪个实例中。
|
假设有 4 个 Redis 实例 R0,R1,R2,R3,还有很多表示用户的键 user:1,user:2,... ,有不同的方式来选择一个指定的键存储在哪个实例中。
|
||||||
|
|
||||||
- 最简单的方式是范围分片,例如用户 id 从 0\~1000 的存储到实例 R0 中,用户 id 从 1001\~2000 的存储到实例 R1 中,等等。但是这样需要维护一张映射范围表,维护操作代价很高。
|
- 最简单的方式是范围分片,例如用户 id 从 0\~1000 的存储到实例 R0 中,用户 id 从 1001\~2000 的存储到实例 R1 中,等等。但是这样需要维护一张映射范围表,维护操作代价很高。
|
||||||
- 还有一种方式是哈希分片,使用 CRC32 哈希函数将键转换为一个数字,再对实例数量求模就能知道应该存储的实例。
|
- 还有一种方式是哈希分片,使用 CRC32 哈希函数将键转换为一个数字,再对实例数量求模就能知道应该存储的实例。
|
||||||
@ -581,7 +580,7 @@ Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入
|
|||||||
|
|
||||||
Redis 没有关系型数据库中的表这一概念来将同种类型的数据存放在一起,而是使用命名空间的方式来实现这一功能。键名的前面部分存储命名空间,后面部分的内容存储 ID,通常使用 : 来进行分隔。例如下面的 HASH 的键名为 article:92617,其中 article 为命名空间,ID 为 92617。
|
Redis 没有关系型数据库中的表这一概念来将同种类型的数据存放在一起,而是使用命名空间的方式来实现这一功能。键名的前面部分存储命名空间,后面部分的内容存储 ID,通常使用 : 来进行分隔。例如下面的 HASH 的键名为 article:92617,其中 article 为命名空间,ID 为 92617。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
|
||||||
|
|
||||||
## 点赞功能
|
## 点赞功能
|
||||||
|
|
||||||
@ -589,13 +588,13 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
|
|||||||
|
|
||||||
为了节约内存,规定一篇文章发布满一周之后,就不能再对它进行投票,而文章的已投票集合也会被删除,可以为文章的已投票集合设置一个一周的过期时间就能实现这个规定。
|
为了节约内存,规定一篇文章发布满一周之后,就不能再对它进行投票,而文章的已投票集合也会被删除,可以为文章的已投票集合设置一个一周的过期时间就能实现这个规定。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
|
||||||
|
|
||||||
## 对文章进行排序
|
## 对文章进行排序
|
||||||
|
|
||||||
为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的)
|
为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的)
|
||||||
|
|
||||||
<div align="center"> <img src="pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
|
||||||
|
|
||||||
# 参考资料
|
# 参考资料
|
||||||
|
|
||||||
@ -607,3 +606,9 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
|
|||||||
- [Redis 3.0 中文版- 分片](http://wiki.jikexueyuan.com/project/redis-guide)
|
- [Redis 3.0 中文版- 分片](http://wiki.jikexueyuan.com/project/redis-guide)
|
||||||
- [Redis 应用场景](http://www.scienjus.com/redis-use-case/)
|
- [Redis 应用场景](http://www.scienjus.com/redis-use-case/)
|
||||||
- [Using Redis as an LRU cache](https://redis.io/topics/lru-cache)
|
- [Using Redis as an LRU cache](https://redis.io/topics/lru-cache)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一、基础](#一基础)
|
* [一、基础](#一基础)
|
||||||
* [二、创建表](#二创建表)
|
* [二、创建表](#二创建表)
|
||||||
@ -766,3 +765,9 @@ SET PASSWROD FOR myuser = Password('new_password');
|
|||||||
# 参考资料
|
# 参考资料
|
||||||
|
|
||||||
- BenForta. SQL 必知必会 [M]. 人民邮电出版社, 2013.
|
- BenForta. SQL 必知必会 [M]. 人民邮电出版社, 2013.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
* [点击阅读面试进阶指南 ](https://github.com/CyC2018/Backend-Interview-Guide)
|
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [一、I/O 模型](#一io-模型)
|
* [一、I/O 模型](#一io-模型)
|
||||||
* [阻塞式 I/O](#阻塞式-io)
|
* [阻塞式 I/O](#阻塞式-io)
|
||||||
@ -47,7 +46,7 @@ Unix 有五种 I/O 模型:
|
|||||||
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
|
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
|
||||||
```
|
```
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1492928416812_4.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492928416812_4.png"/> </div><br>
|
||||||
|
|
||||||
## 非阻塞式 I/O
|
## 非阻塞式 I/O
|
||||||
|
|
||||||
@ -55,7 +54,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
|||||||
|
|
||||||
由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率比较低。
|
由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率比较低。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1492929000361_5.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492929000361_5.png"/> </div><br>
|
||||||
|
|
||||||
## I/O 复用
|
## I/O 复用
|
||||||
|
|
||||||
@ -65,7 +64,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
|||||||
|
|
||||||
如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接,那么就需要创建相同数量的线程。相比于多进程和多线程技术,I/O 复用不需要进程线程创建和切换的开销,系统开销更小。
|
如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接,那么就需要创建相同数量的线程。相比于多进程和多线程技术,I/O 复用不需要进程线程创建和切换的开销,系统开销更小。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1492929444818_6.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492929444818_6.png"/> </div><br>
|
||||||
|
|
||||||
## 信号驱动 I/O
|
## 信号驱动 I/O
|
||||||
|
|
||||||
@ -73,7 +72,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
|||||||
|
|
||||||
相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。
|
相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1492929553651_7.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492929553651_7.png"/> </div><br>
|
||||||
|
|
||||||
## 异步 I/O
|
## 异步 I/O
|
||||||
|
|
||||||
@ -81,7 +80,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
|||||||
|
|
||||||
异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
|
异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1492930243286_8.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492930243286_8.png"/> </div><br>
|
||||||
|
|
||||||
## 五大 I/O 模型比较
|
## 五大 I/O 模型比较
|
||||||
|
|
||||||
@ -92,7 +91,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
|||||||
|
|
||||||
非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。
|
非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。
|
||||||
|
|
||||||
<div align="center"> <img src="pics/1492928105791_3.png"/> </div><br>
|
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/1492928105791_3.png"/> </div><br>
|
||||||
|
|
||||||
# 二、I/O 复用
|
# 二、I/O 复用
|
||||||
|
|
||||||
@ -322,3 +321,9 @@ poll 没有最大描述符数量的限制,如果平台支持并且对实时性
|
|||||||
- [poll vs select vs event-based](https://daniel.haxx.se/docs/poll-vs-select.html)
|
- [poll vs select vs event-based](https://daniel.haxx.se/docs/poll-vs-select.html)
|
||||||
- [select / poll / epoll: practical difference for system architects](http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-architects/)
|
- [select / poll / epoll: practical difference for system architects](http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-architects/)
|
||||||
- [Browse the source code of userspace/glibc/sysdeps/unix/sysv/linux/ online](https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/)
|
- [Browse the source code of userspace/glibc/sysdeps/unix/sysv/linux/ online](https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</br><div align="center">⭐️欢迎关注我的公众号 CyC2018,在公众号后台回复关键字 📚 **资料** 可领取复习大纲,这份大纲是我花了一整年时间整理的面试知识点列表,不仅系统整理了面试知识点,而且标注了各个知识点的重要程度,从而帮你理清多而杂的面试知识点。可以说我基本是按照这份大纲来进行复习的,这份大纲对我拿到了 BAT 头条等 Offer 起到很大的帮助。你们完全可以和我一样根据大纲上列的知识点来进行复习,就不用看很多不重要的内容,也可以知道哪些内容很重要从而多安排一些复习时间。</div></br>
|
||||||
|
<div align="center"><img width="180px" src="https://cyc-1256109796.cos.ap-guangzhou.myqcloud.com/%E5%85%AC%E4%BC%97%E5%8F%B7.jpg"></img></div>
|
||||||
|
BIN
docs/notes/pics/032771e7-f60f-47bf-aa79-f45c32799211.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
docs/notes/pics/067b310c-6877-40fe-9dcf-10654e737485.jpg
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
docs/notes/pics/0e8fdc96-83c1-4798-9abe-45fc91d70b9d.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
docs/notes/pics/14fe1e71-8518-458f-a220-116003061a83.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
docs/notes/pics/2de794ca-aa7b-48f3-a556-a0e2708cb976.jpg
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
docs/notes/pics/417cb02e-853d-4288-a36e-9161ded2c9fd_200.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
docs/notes/pics/45be9587-6069-4ab7-b9ac-840db1a53744.jpg
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
docs/notes/pics/48b1d459-8832-4e92-938a-728aae730739.jpg
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
docs/notes/pics/49e53613-46f8-4308-9ee5-c09d6231552088893397.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/notes/pics/56074abd-39d6-42a7-bed8-a360e81a82d8.jpg
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
docs/notes/pics/584b05d4-a101-4bde-a758-f5388cb843c8.jpg
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
docs/notes/pics/61d39d7a-c566-40dd-91ba-c6abaefa1a24.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
docs/notes/pics/6646db4a-7f43-45e4-96ff-0891a57a9ade.jpg
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
docs/notes/pics/68d76d01-f11f-4f6e-85ae-b9db4368d544_200.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
docs/notes/pics/6c0cf1e8-b03f-4eff-9b1a-ab262e0c7866.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
docs/notes/pics/6f1938e5-fc49-4e7b-a383-2b46f0942d70_200.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
docs/notes/pics/74dc31eb-6baa-47ea-ab1c-d27a0ca35093.png
Normal file
After Width: | Height: | Size: 14 KiB |