diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index ee76204..0000000 --- a/.editorconfig +++ /dev/null @@ -1,27 +0,0 @@ -# EditorConfig 用于在 IDE 中检查代码的基本 Code Style -# @see: https://editorconfig.org/ - -# 配置说明: -# 所有文件换行使用 Unix 风格(LF),*.bat 文件使用 Windows 风格(CRLF) -# java / sh 文件缩进 4 个空格,其他所有文件缩进 2 个空格 - -root = true - -[*] -end_of_line = lf -indent_size = 2 -indent_style = space -max_line_length = 120 -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.{bat, cmd}] -end_of_line = crlf - -[*.{java, gradle, groovy, kt, sh, xml}] -indent_size = 4 - -[*.md] -max_line_length = 0 -trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index eaae227..0000000 --- a/.gitattributes +++ /dev/null @@ -1,78 +0,0 @@ -* text=auto eol=lf - -# plan text -*.txt text -*.java text -*.scala text -*.groovy text -*.gradle text -*.xml text -*.xsd text -*.tld text -*.yaml text -*.yml text -*.wsdd text -*.wsdl text -*.jsp text -*.jspf text -*.js text -*.jsx text -*.json text -*.css text -*.less text -*.sql text -*.properties text -*.md text - -# unix style -*.sh text eol=lf - -# win style -*.bat text eol=crlf - -# don't handle -*.der -text -*.jks -text -*.pfx -text -*.map -text -*.patch -text -*.dat -text -*.data -text -*.db -text - -# binary -*.jar binary -*.war binary -*.zip binary -*.tar binary -*.tar.gz binary -*.gz binary -*.apk binary -*.bin binary -*.exe binary - -# images -*.png binary -*.jpg binary -*.ico binary -*.gif binary - -# medias -*.mp3 binary -*.swf binary - -# fonts -*.eot binary -*.svg binary -*.ttf binary -*.woff binary - -# others -*.pdf binary -*.doc binary -*.docx binary -*.ppt binary -*.pptx binary -*.xls binary -*.xlsx binary -*.xmind binary diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 36b705c..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: CI - -# 在master分支发生push事件时触发。 -on: - push: - branches: - - master - -env: # 设置环境变量 - TZ: Asia/Shanghai # 时区(设置时区可使页面中的`最近更新时间`使用时区时间) - -jobs: - build: # 自定义名称 - runs-on: ubuntu-latest # 运行在虚拟机环境ubuntu-latest - - strategy: - matrix: - node-version: [14.x] - - steps: - # 使用的动作。格式:userName/repoName。作用:检出仓库,获取源码。 官方actions库:https://github.com/actions - - name: Checkout - uses: actions/checkout@master - - # 指定 nodejs 版本 - - name: Use Nodejs ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - # 部署 - - name: Deploy - env: # 设置环境变量 - GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} - GITEE_TOKEN: ${{ secrets.GITEE_TOKEN }} - run: npm install && npm run deploy diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 7d98dac..0000000 --- a/.gitignore +++ /dev/null @@ -1,66 +0,0 @@ -# --------------------------------------------------------------------- -# more gitignore templates see https://github.com/github/gitignore -# --------------------------------------------------------------------- - -# ------------------------------- java ------------------------------- -# compiled folders -classes -target -logs -.mtj.tmp/ - -# compiled files -*.class - -# bluej files -*.ctxt - -# package files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs -hs_err_pid* - -# maven plugin temp files -.flattened-pom.xml - - -# ------------------------------- javascript ------------------------------- -# dependencies -node_modules - -# temp folders -build -dist -_book -_jsdoc -.temp -.deploy*/ - -# temp files -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -bundle*.js -.DS_Store -Thumbs.db -db.json -book.pdf -package-lock.json - - -# ------------------------------- intellij ------------------------------- -.idea -*.iml - - -# ------------------------------- eclipse ------------------------------- -.classpath -.project diff --git a/404.html b/404.html new file mode 100644 index 0000000..48cf6c1 --- /dev/null +++ b/404.html @@ -0,0 +1,20 @@ + + + + + + ALGORITHM-TUTORIAL + + + + + + + + + + +
404
这是一个Four-Oh-Four.
返回首页
+ + + diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 3b7b82d..0000000 --- a/LICENSE +++ /dev/null @@ -1,427 +0,0 @@ -Attribution-ShareAlike 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More_considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - - including for purposes of Section 3(b); and - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the “Licensor.” The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. diff --git a/README.md b/README.md deleted file mode 100644 index af71637..0000000 --- a/README.md +++ /dev/null @@ -1,624 +0,0 @@ -

- - logo - -

- -

- - - star - - - - fork - - - - build - - - - code style - - -

- -

ALGORITHM

- -> 💾 algorithm 是一个数据结构与算法学习笔记。 -> -> 掌握数据结构与算法,你看待问题的深度,解决问题的角度就会完全不一样。 -> -> - 🔁 项目同步维护:[Github](https://github.com/dunwu/algorithm-tutorial/) | [Gitee](https://gitee.com/turnon/algorithm-tutorial/) -> - 📖 电子书阅读:[Github Pages](https://dunwu.github.io/algorithm-tutorial/) | [Gitee Pages](http://turnon.gitee.io/algorithm-tutorial/) - -## 📖 内容 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200702071922.png) - -- 综合 - - [数据结构和算法指南](docs/01.数据结构和算法/00.综合/01.数据结构和算法指南.md) - - [复杂度分析](docs/01.数据结构和算法/00.综合/02.复杂度分析.md) - 关键词:**`时间复杂度`**、**`空间复杂度`**、**`大 O 表示法`**、**`复杂度量级`** -- 线性表 - - [数组和链表](docs/01.数据结构和算法/01.线性表/01.数组和链表.md) - 关键词:**`线性表`**、**`一维数组`**、**`多维数组`**、**`随机访问`**、**`单链表`**、**`双链表`**、**`循环链表`** - - [栈和队列](docs/01.数据结构和算法/01.线性表/02.栈和队列.md) - 关键词:**`先进后出`**、**`后进先出`**、**`循环队列`** - - [线性表的查找](docs/01.数据结构和算法/01.线性表/11.线性表的查找.md) - - [线性表的排序](docs/01.数据结构和算法/01.线性表/12.线性表的排序.md) -- 树 - - [树和二叉树](docs/01.数据结构和算法/02.树/01.树和二叉树.md) - - [堆](docs/01.数据结构和算法/02.树/02.堆.md) - - [B+树](docs/01.数据结构和算法/02.树/03.B+树.md) - - [LSM 树](docs/01.数据结构和算法/02.树/04.LSM树.md) - - [字典树](docs/01.数据结构和算法/02.树/05.字典树.md) - - [红黑树](docs/01.数据结构和算法/02.树/06.红黑树.md) -- [哈希表](docs/01.数据结构和算法/03.哈希表.md) - 关键词:**`哈希函数`**、**`装载因子`**、**`哈希冲突`**、**`开放寻址法`**、**`拉链法`** -- [跳表](docs/01.数据结构和算法/04.跳表.md) - 关键词:**`多级索引`** -- [图](docs/01.数据结构和算法/05.图.md) - -## 💻 刷题 - -### 链表 - -#### 基础操作 - -| 题目 | 难度 | 掌握度 | -| --------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [1290. 二进制链表转整数](https://leetcode.cn/problems/convert-binary-number-in-a-linked-list-to-integer/) | 💚 | ✔️ | - -#### 双指针技巧 - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------------------------ | ---- | ------ | -| [141. 环形链表](https://leetcode.cn/problems/linked-list-cycle/) | 💚 | ✔️ | -| [142. 环形链表 II](https://leetcode.cn/problems/linked-list-cycle-ii/) | 💛 | ✔️ | -| [160. 相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/) | 💚 | ✔️ | -| [19. 删除链表的倒数第 N 个结点](https://leetcode.cn/problems/remove-nth-node-from-end-of-list/) | 💛 | ✔️ | -| [21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/) | 💚 | ✔️ | -| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | ❤️ | ✔️ | -| [86. 分隔链表](https://leetcode.cn/problems/partition-list/) | 💛 | ✔️ | -| [876. 链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/) | 💚 | ✔️ | -| [面试题 02. 返回倒数第 k 个节点](https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/) | 💚 | ✔️ | -| [面试题 02.01. 移除重复节点](https://leetcode.cn/problems/remove-duplicate-node-lcci/) | 💚 | ✔️ | -| [203. 移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/) | 💚 | ✔️ | -| [328. 奇偶链表](https://leetcode.cn/problems/odd-even-linked-list/) | 💛 | ✔️ | -| [LCR 136. 删除链表的节点](https://leetcode.cn/problems/shan-chu-lian-biao-de-jie-dian-lcof/) | 💚 | ✔️ | -| [83. 删除排序链表中的重复元素](https://leetcode.cn/problems/remove-duplicates-from-sorted-list/) | 💚 | ✔️ | -| [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/) | 💛 | ✔️ | -| [2. 两数相加](https://leetcode.cn/problems/add-two-numbers/) | 💛 | ✔️ | -| [445. 两数相加 II](https://leetcode.cn/problems/add-two-numbers-ii/) | 💛 | ✔️ | - -#### 单链表反转 - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------ | ---- | ------ | -| [61. 旋转链表](https://leetcode.cn/problems/rotate-list/) | 💛 | ✔️ | -| [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/) | 💚 | ✔️ | -| [92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/) | 💛 | ✔️ | -| [25. K 个一组翻转链表](https://leetcode.cn/problems/reverse-nodes-in-k-group/) | ❤️ | ✔️ | - -#### 分治 - -| 题目 | 难度 | 掌握度 | -| -------------------------------------------------------- | ---- | ------ | -| [148. 排序链表](https://leetcode.cn/problems/sort-list/) | 💛 | ❌ | - -#### 回文链表 - -| 题目 | 难度 | 掌握度 | -| --------------------------------------------------------------------- | ---- | ------ | -| [234. 回文链表](https://leetcode.cn/problems/palindrome-linked-list/) | 💚 | ✔️ | - -### 数组 - -#### 基础 - -| 题目 | 难度 | 掌握度 | -| -------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [485. 最大连续 1 的个数](https://leetcode.cn/problems/max-consecutive-ones/) | 💚 | ✔️ | -| [747. 至少是其他数字两倍的最大数](https://leetcode.cn/problems/largest-number-at-least-twice-of-others/) | 💚 | ✔️ | - -#### 双指针技巧 - -| 题目 | 难度 | 掌握度 | -| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [27. 移除元素](https://leetcode.cn/problems/remove-element/) | 💚 | ✔️ | -| [283. 移动零](https://leetcode.cn/problems/move-zeroes/) | 💚 | ✔️ | -| [LCR 179. 查找总价格为目标值的两个商品](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/) | 💚 | ✔️ | -| [1. 两数之和](https://leetcode.cn/problems/two-sum/) | 💚 | ✔️ | -| [67. 二进制求和](https://leetcode.cn/problems/add-binary/) | 💚 | ✔️ | -| [167. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/)
[LCR 006. 两数之和 II - 输入有序数组](https://leetcode.cn/problems/kLl5u1/) | 💛 | ✔️ | -| [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/) | 💚 | ✔️ | -| [80. 删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/) | 💛 | ✔️ | -| [344. 反转字符串](https://leetcode.cn/problems/reverse-string/) | 💚 | ✔️ | -| [125. 验证回文串](https://leetcode.cn/problems/valid-palindrome/) | 💚 | ✔️ | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ✔️ | -| [75. 颜色分类](https://leetcode.cn/problems/sort-colors/) | 💛 | ✔️ | -| [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/) | 💚 | ✔️ | -| [977. 有序数组的平方](https://leetcode.cn/problems/squares-of-a-sorted-array/) | 💚 | ✔️ | -| [1329. 将矩阵按对角线排序](https://leetcode.cn/problems/sort-the-matrix-diagonally/) | 💛 | ✔️ | -| [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | 💚 | ✔️ | -| [867. 转置矩阵](https://leetcode.cn/problems/transpose-matrix/) | 💚 | ✔️ | -| [14. 最长公共前缀](https://leetcode.cn/problems/longest-common-prefix/) | 💚 | ✔️ | -| [15. 三数之和](https://leetcode.cn/problems/3sum/) | 💛 | ❗ | -| [56. 合并区间](https://leetcode.cn/problems/merge-intervals/) | 💛 | ✔️ | - -#### 二维数组遍历 - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---- | ------ | -| [151. 反转字符串中的单词](https://leetcode.cn/problems/reverse-words-in-a-string/) | 💛 | ✔️ | -| [48. 旋转图像](https://leetcode.cn/problems/rotate-image/) | 💛 | ✔️ | -| [54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/)
[LCR 146. 螺旋遍历二维数组](https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/) | 💛 | ✔️ | -| [59. 螺旋矩阵 II](https://leetcode.cn/problems/spiral-matrix-ii/) | 💛 | ✔️ | -| [498. 对角线遍历](https://leetcode.cn/problems/diagonal-traverse/) | 💛 | ❌ | -| [面试题 01.08. 零矩阵](https://leetcode.cn/problems/zero-matrix-lcci/) | 💛 | ✔️ | - -#### 滑动窗口算法 - -| 题目 | 难度 | 掌握度 | -| -------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [3. 无重复字符的最长子串](https://leetcode.cn/problems/longest-substring-without-repeating-characters/) | 💛 | ✔️ | -| [438. 找到字符串中所有字母异位词](https://leetcode.cn/problems/find-all-anagrams-in-a-string/) | 💛 | ✔️ | -| [567. 字符串的排列](https://leetcode.cn/problems/permutation-in-string/) | 💛 | ✔️ | -| [76. 最小覆盖子串](https://leetcode.cn/problems/minimum-window-substring/) | ❤️ | ✔️ | -| [1658. 将 x 减到 0 的最小操作数](https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/) | 💛 | ✔️ | -| [713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/) | 💛 | ✔️ | -| [1004. 最大连续 1 的个数 III](https://leetcode.cn/problems/max-consecutive-ones-iii/) | 💛 | ✔️ | -| [424. 替换后的最长重复字符](https://leetcode.cn/problems/longest-repeating-character-replacement/) | 💛 | ✔️ | -| [217. 存在重复元素](https://leetcode.cn/problems/contains-duplicate/) | 💚 | ✔️ | -| [219. 存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/) | 💛 | ✔️ | -| [220. 存在重复元素 III](https://leetcode.cn/problems/contains-duplicate-iii/) | ❤️ | ❌ | -| [209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/) | 💛 | ✔️ | -| [395. 至少有 K 个重复字符的最长子串](https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/) | 💛 | ❌ | - -#### 二分查找算法 - -| 题目 | 难度 | 掌握度 | -| :-------------------------------------------------------------------------------------------------------------------------------------- | :--- | ------ | -| [34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/) | 💛 | ✔️ | -| [35. 搜索插入位置](https://leetcode.cn/problems/search-insert-position/) | 💚 | ✔️ | -| [704. 二分查找](https://leetcode.cn/problems/binary-search/) | 💚 | ✔️ | -| [LCR 172. 统计目标成绩的出现次数](https://leetcode.cn/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/) | 💚 | ✔️ | -| [875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) | 💛 | ❗ | -| [1011. 在 D 天内送达包裹的能力](https://leetcode.cn/problems/capacity-to-ship-packages-within-d-days/) | 💛 | ✔️ | -| [410. 分割数组的最大值](https://leetcode.cn/problems/split-array-largest-sum/) | ❤️ | ❌ | - -#### 前缀和数组 - -| 题目 | 难度 | 掌握度 | -| ----------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [303. 区域和检索 - 数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/) | 💚 | ✔️ | -| [724. 寻找数组的中心下标](https://leetcode.cn/problems/find-pivot-index/) | 💚 | ✔️ | -| [1013. 将数组分成和相等的三个部分](https://leetcode.cn/problems/partition-array-into-three-parts-with-equal-sum/) | 💚 | ✔️ | -| [304. 二维区域和检索 - 矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/) | 💛 | ❌ | - -#### 差分数组 - -| 题目 | 难度 | 掌握度 | -| ----------------------------------------------------------------------------- | ---- | ------ | -| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | 💛 | ✔️ | -| [1109. 航班预订统计](https://leetcode.cn/problems/corporate-flight-bookings/) | 💛 | ✔️ | - -### 栈和队列 - -#### 队列 - -| 题目 | 难度 | 掌握度 | -| ----------------------------------------------------------------------------------------------------- | ---- | ------ | -| [225. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/) | 💚 | ✔️ | -| [933. 最近的请求次数](https://leetcode.cn/problems/number-of-recent-calls/) | 💚 | ❗ | -| [622. 设计循环队列](https://leetcode.cn/problems/design-circular-queue/) | 💛 | ❌ | -| [641. 设计循环双端队列](https://leetcode.cn/problems/design-circular-deque/) | 💛 | ❌ | -| [1670. 设计前中后队列](https://leetcode.cn/problems/design-front-middle-back-queue/) | 💛 | ❌ | -| [2073. 买票需要的时间](https://leetcode.cn/problems/time-needed-to-buy-tickets/) | 💚 | ✔️ | -| [373. 查找和最小的 K 对数字](https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/) | 💛 | ❌ | -| [378. 有序矩阵中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-sorted-matrix/) | 💛 | ❌ | - -#### 栈 - -| 题目 | 难度 | 掌握度 | -| --------------------------------------------------------------------------------------- | ---- | ------ | -| [20. 有效的括号](https://leetcode.cn/problems/valid-parentheses/) | 💚 | ✔️ | -| [232. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/) | 💚 | ✔️ | -| [682. 棒球比赛](https://leetcode.cn/problems/baseball-game/) | 💚 | ✔️ | -| [844. 比较含退格的字符串](https://leetcode.cn/problems/backspace-string-compare/) | 💚 | ✔️ | -| [71. 简化路径](https://leetcode.cn/problems/simplify-path/) | 💛 | ✔️ | -| [143. 重排链表](https://leetcode.cn/problems/reorder-list/) | 💛 | ✔️ | -| [150. 逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/) | 💛 | ✔️ | -| [388. 文件的最长绝对路径](https://leetcode.cn/problems/longest-absolute-file-path/) | 💛 | ❌ | -| [155. 最小栈](https://leetcode.cn/problems/min-stack/) | 💛 | ✔️ | -| [面试题 03.05. 栈排序](https://leetcode.cn/problems/sort-of-stacks-lcci/) | 💛 | ✔️ | -| [895. 最大频率栈](https://leetcode.cn/problems/maximum-frequency-stack/) | ❤️ | ❌ | - -#### 单调栈 - -| 题目 | 难度 | 掌握度 | -| ----------------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [496. 下一个更大元素 I](https://leetcode.cn/problems/next-greater-element-i/) | 💚 | ✔️ | -| [503. 下一个更大元素 II](https://leetcode.cn/problems/next-greater-element-ii/) | 💛 | ✔️ | -| [739. 每日温度](https://leetcode.cn/problems/daily-temperatures/)
[剑指 Offer II 038. 每日温度](https://leetcode.cn/problems/iIQa4I/) | 💛 | ✔️ | -| [1019. 链表中的下一个更大节点](https://leetcode.cn/problems/next-greater-node-in-linked-list/) | 💛 | ✔️ | -| [1944. 队列中可以看到的人数](https://leetcode.cn/problems/number-of-visible-people-in-a-queue/) | ❤️ | ❌ | -| [1475. 商品折扣后的最终价格](https://leetcode.cn/problems/final-prices-with-a-special-discount-in-a-shop/) | 💛 | ✔️ | -| [901. 股票价格跨度](https://leetcode.cn/problems/online-stock-span/) | 💛 | ❌ | -| [402. 移掉 K 位数字](https://leetcode.cn/problems/remove-k-digits/) | 💛 | ❌ | -| [853. 车队](https://leetcode.cn/problems/car-fleet/) | 💛 | ❌ | -| [581. 最短无序连续子数组](https://leetcode.cn/problems/shortest-unsorted-continuous-subarray/) | 💛 | ❌ | - -#### 单调队列 - -| 题目 | 难度 | 掌握度 | -| -------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [LCR 184. 设计自助结算系统](https://leetcode.cn/problems/dui-lie-de-zui-da-zhi-lcof/) | 💛 | ❌ | -| [239. 滑动窗口最大值](https://leetcode.cn/problems/sliding-window-maximum/) | ❤️ | ❌ | -| [1438. 绝对差不超过限制的最长连续子数组](https://leetcode.cn/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/) | 💛 | ❌ | -| [862. 和至少为 K 的最短子数组](https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/) | ❤️ | ❌ | -| [918. 环形子数组的最大和](https://labuladong.online/algo/problem-set/monotonic-queue/#slug_maximum-sum-circular-subarray) | 💛 | ❌ | - -### 树 - -#### 二叉树 - -| 题目 | 难度 | 掌握度 | -| ---------------------------------------------------------------------------------------------------- | ---- | ------ | -| [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/) | 💚 | ✔️ | -| [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/) | 💚 | ✔️ | -| [543. 二叉树的直径](https://leetcode.cn/problems/diameter-of-binary-tree/) | 💚 | ✔️ | -| [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/) | 💛 | ✔️ | -| [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/) | 💚 | ✔️ | -| [654. 最大二叉树](https://leetcode.cn/problems/maximum-binary-tree/) | 💛 | ✔️ | -| [297. 二叉树的序列化与反序列化](https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/) | ❤️ | ❗ | -| [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/) | 💚 | ✔️ | - -#### DFS - -| 题目 | 难度 | 掌握度 | -| -------------------------------------------------------------------------------------- | ---- | ------ | -| [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/) | 💚 | ✔️ | -| [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/) | 💚 | ✔️ | -| [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/) | 💚 | ✔️ | -| [872. 叶子相似的树](https://leetcode.cn/problems/leaf-similar-trees/) | 💚 | ✔️ | - -#### 用「遍历」思维解题 - -| 题目 | 难度 | 掌握度 | -| ----------------------------------------------------------------------------------------------------- | ---- | ------ | -| [257. 二叉树的所有路径](https://leetcode.cn/problems/binary-tree-paths/) | 💚 | ✔️ | -| [129. 求根节点到叶节点数字之和](https://leetcode.cn/problems/sum-root-to-leaf-numbers/) | 💛 | ✔️ | -| [199. 二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/) | 💛 | ✔️ | -| [988. 从叶结点开始的最小字符串](https://leetcode.cn/problems/smallest-string-starting-from-leaf/) | 💛 | ✔️ | -| [1022. 从根到叶的二进制数之和](https://leetcode.cn/problems/sum-of-root-to-leaf-binary-numbers/) | 💚 | ✔️ | -| [1457. 二叉树中的伪回文路径](https://leetcode.cn/problems/pseudo-palindromic-paths-in-a-binary-tree/) | 💛 | ✔️ | -| [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/) | 💚 | ✔️ | -| [623. 在二叉树中增加一行](https://leetcode.cn/problems/add-one-row-to-tree/) | 💛 | ✔️ | -| [508. 出现次数最多的子树元素和](https://leetcode.cn/problems/most-frequent-subtree-sum/) | 💛 | ✔️ | -| [563. 二叉树的坡度](https://leetcode.cn/problems/binary-tree-tilt/) | 💚 | ✔️ | -| [814. 二叉树剪枝](https://leetcode.cn/problems/binary-tree-pruning/) | 💛 | ✔️ | -| [1325. 删除给定值的叶子节点](https://leetcode.cn/problems/delete-leaves-with-a-given-value/) | 💛 | ✔️ | - -#### 用「分解」思维解题 - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [105. 从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) | 💛 | ✔️ | -| [106. 从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) | 💛 | ✔️ | -| [889. 根据前序和后序遍历构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) | 💛 | ✔️ | -| [331. 验证二叉树的前序序列化](https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/) | 💛 | ❌ | -| [894. 所有可能的真二叉树](https://leetcode.cn/problems/all-possible-full-binary-trees/) | 💛 | ❌ | -| [998. 最大二叉树 II](https://leetcode.cn/problems/maximum-binary-tree-ii/) | 💛 | ❌ | -| [1110. 删点成林](https://leetcode.cn/problems/delete-nodes-and-return-forest/) | 💛 | ❌ | -| [100. 相同的树](https://leetcode.cn/problems/same-tree/) | 💛 | ✔️ | -| [101. 对称二叉树](https://leetcode.cn/problems/symmetric-tree/) | 💛 | ✔️ | -| [951. 翻转等价二叉树](https://leetcode.cn/problems/flip-equivalent-binary-trees/) | 💛 | ✔️ | -| [124. 二叉树中的最大路径和](https://leetcode.cn/problems/binary-tree-maximum-path-sum/) | ❤️ | ❌ | -| [236. 二叉树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/) | 💛 | ❌ | - -#### 用「层序遍历」思维解题 - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------------------------------------------ | ---- | ------ | -| [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/) | 💛 | ✔️ | -| [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/) | 💛 | ✔️ | -| [103. 二叉树的锯齿形层序遍历](https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/) | 💛 | ✔️ | -| [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/) | 💛 | ✔️ | -| [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/) | 💛 | ✔️ | -| [662. 二叉树最大宽度](https://leetcode.cn/problems/maximum-width-of-binary-tree/) | 💛 | ✔️ | -| [515. 在每个树行中找最大值](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/) | 💛 | ✔️ | -| [637. 二叉树的层平均值](https://leetcode.cn/problems/average-of-levels-in-binary-tree/) | 💚 | ✔️ | -| [958. 二叉树的完全性检验](https://leetcode.cn/problems/check-completeness-of-a-binary-tree/) | 💛 | ✔️ | -| [1161. 最大层内元素和](https://leetcode.cn/problems/maximum-level-sum-of-a-binary-tree/) | 💛 | ✔️ | -| [1302. 层数最深叶子节点的和](https://leetcode.cn/problems/deepest-leaves-sum/) | 💛 | ✔️ | -| [1609. 奇偶树](https://leetcode.cn/problems/even-odd-tree/) | 💛 | ✔️ | -| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | 💛 | ✔️ | -| [863. 二叉树中所有距离为 K 的结点](https://leetcode.cn/problems/all-nodes-distance-k-in-binary-tree/) | 💛 | ❌ | -| [LCR 149. 彩灯装饰记录 I](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/) | 💛 | ✔️ | -| [LCR 150. 彩灯装饰记录 II](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/) | 💚 | ✔️ | -| [LCR 151. 彩灯装饰记录 III](https://leetcode.cn/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/) | 💛 | ✔️ | - -#### 二叉搜索树 - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [1038. 从二叉搜索树到更大和树](https://leetcode.cn/problems/binary-search-tree-to-greater-sum-tree/) | 💛 | ✔️ | -| [230. 二叉搜索树中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-bst/) | 💛 | ✔️ | -| [538. 把二叉搜索树转换为累加树](https://leetcode.cn/problems/convert-bst-to-greater-tree/) | 💛 | ✔️ | -| [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/) | 💛 | ✔️ | -| [700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/) | 💚 | ✔️ | -| [701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/) | 💛 | ✔️ | -| [98. 验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/) | 💛 | ✔️ | -| [96. 不同的二叉搜索树](https://leetcode.cn/problems/unique-binary-search-trees/) | 💛 | ❌ | -| [95. 不同的二叉搜索树 II](https://leetcode.cn/problems/unique-binary-search-trees-ii/) | 💛 | ❌ | -| [108. 将有序数组转换为二叉搜索树](https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/) | 💚 | ✔️ | -| [783. 二叉搜索树节点最小距离](https://leetcode.cn/problems/minimum-distance-between-bst-nodes/) | 💚 | ✔️ | -| [235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/) | 💛 | ❌ | -| [1373. 二叉搜索子树的最大键值和](https://leetcode.cn/problems/maximum-sum-bst-in-binary-tree/) | ❤️ | ❌ | - -#### N 叉树 - -| 题目 | 难度 | 掌握度 | -| :-------------------------------------------------------------------------------------- | :--: | ------ | -| [429. N 叉树的层序遍历](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/) | 💛 | ✔️ | -| [559. N 叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-n-ary-tree/) | 💚 | ✔️ | -| [589. N 叉树的前序遍历](https://leetcode.cn/problems/n-ary-tree-preorder-traversal/) | 💚 | ✔️ | -| [590. N 叉树的后序遍历](https://leetcode.cn/problems/n-ary-tree-postorder-traversal/) | 💚 | ✔️ | - -### 图 - -#### BFS/DFS - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------ | ---- | ------ | -| [797. 所有可能的路径](https://leetcode.cn/problems/all-paths-from-source-to-target/) | 💛 | ❗ | - -#### 环检测及拓扑排序算法 - -| 题目 | 难度 | 掌握度 | -| :----------------------------------------------------------------- | ---- | ------ | -| [207. 课程表](https://leetcode.cn/problems/course-schedule/) | 💛 | ❌ | -| [210. 课程表 II](https://leetcode.cn/problems/course-schedule-ii/) | 💛 | ❌ | - -#### 二分图判定算法 - -| 题目 | 难度 | 掌握度 | -| :---------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [785. 判断二分图](https://leetcode.cn/problems/is-graph-bipartite/)
[LCR 106. 判断二分图](https://leetcode.cn/problems/vEAB3K/) | 💛 | ❌ | -| [886. 可能的二分法](https://leetcode.cn/problems/possible-bipartition/) | 💛 | ❗ | - -#### 并查集算法 - -| 题目 | 难度 | 掌握度 | -| :-------------------------------------------------------------------------------------------- | ---- | ------ | -| [130. 被围绕的区域](https://leetcode.cn/problems/surrounded-regions/) | 💛 | ❌ | -| [684. 冗余连接](https://leetcode.cn/problems/redundant-connection/) | 💛 | ✔️ | -| [990. 等式方程的可满足性](https://leetcode.cn/problems/satisfiability-of-equality-equations/) | 💛 | ✔️ | - -#### Dijkstra 算法 - -| 题目 | 难度 | 掌握度 | -| :--------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ | -| [743. 网络延迟时间](https://leetcode.cn/problems/network-delay-time/) | 💛 | ❌ | -| [1631. 最小体力消耗路径](https://leetcode.cn/problems/path-with-minimum-effort/) | 💛 | ❌ | -| [1514. 概率最大的路径](https://leetcode.cn/problems/path-with-maximum-probability/) | 💛 | ❌ | -| [787. K 站中转内最便宜的航班](https://leetcode.cn/problems/cheapest-flights-within-k-stops/) | 💛 | ❌ | -| [1368. 使网格图至少有一条有效路径的最小代价](https://leetcode.cn/problems/minimum-cost-to-make-at-least-one-valid-path-in-a-grid/) | ❤️ | ❌ | - -### DFS / 回溯算法 - -#### 排列、组合、子集问题 - -子集、组合、排列相关问题,都可以考虑使用回溯算法求解。 - -| 题目 | 难度 | 掌握度 | -| :--------------------------------------------------------------------- | ---- | ------ | -| [46. 全排列](https://leetcode.cn/problems/permutations/) | 💛 | ✔️ | -| [47. 全排列 II](https://leetcode.cn/problems/permutations-ii/) | 💛 | ✔️ | -| [78. 子集](https://leetcode.cn/problems/subsets/) | 💛 | ✔️ | -| [90. 子集 II](https://leetcode.cn/problems/subsets-ii/) | 💛 | ✔️ | -| [77. 组合](https://leetcode.cn/problems/combinations/) | 💛 | ✔️ | -| [39. 组合总和](https://leetcode.cn/problems/combination-sum/) | 💛 | ✔️ | -| [40. 组合总和 II](https://leetcode.cn/problems/combination-sum-ii/) | 💛 | ✔️ | -| [216. 组合总和 III](https://leetcode.cn/problems/combination-sum-iii/) | 💛 | ✔️ | - -#### 岛屿问题 - -| 题目 | 难度 | 掌握度 | -| :--------------------------------------------------------------------------------- | ---- | ------ | -| [200. 岛屿数量](https://leetcode.cn/problems/number-of-islands/) | 💛 | ❗ | -| [1254. 统计封闭岛屿的数目](https://leetcode.cn/problems/number-of-closed-islands/) | 💛 | ❗ | -| [1020. 飞地的数量](https://leetcode.cn/problems/number-of-enclaves/) | 💛 | ❗ | -| [695. 岛屿的最大面积](https://leetcode.cn/problems/max-area-of-island/) | 💛 | ❗ | -| [1905. 统计子岛屿](https://leetcode.cn/problems/count-sub-islands/) | 💛 | ❌ | - -#### 数独、N 皇后问题 - -| 题目 | 难度 | 掌握度 | -| :-------------------------------------------------------- | ---- | ------ | -| [37. 解数独](https://leetcode.cn/problems/sudoku-solver/) | ❤️ | ❌ | -| [51. N 皇后](https://leetcode.cn/problems/n-queens/) | ❤️ | ❌ | -| [52. N皇后 II](https://leetcode.cn/problems/n-queens-ii/) | ❤️ | ❌ | - -#### 练习 - -| 题目 | 难度 | 掌握度 | -| :----------------------------------------------------------------------------------------------- | ---- | ------ | -| [967. 连续差相同的数字](https://leetcode.cn/problems/numbers-with-same-consecutive-differences/) | 💛 | ❌ | -| [491. 非递减子序列](https://leetcode.cn/problems/non-decreasing-subsequences/) | 💛 | ❌ | -| [980. 不同路径 III](https://leetcode.cn/problems/unique-paths-iii/) | ❤️ | ❌ | -| [526. 优美的排列](https://leetcode.cn/problems/beautiful-arrangement/) | 💛 | ❌ | -| [131. 分割回文串](https://leetcode.cn/problems/palindrome-partitioning/) | 💛 | ❌ | -| [93. 复原 IP 地址](https://leetcode.cn/problems/restore-ip-addresses/) | 💛 | ❌ | -| [89. 格雷编码](https://leetcode.cn/problems/gray-code/) | 💛 | ❌ | -| [17. 电话号码的字母组合](https://leetcode.cn/problems/letter-combinations-of-a-phone-number/) | 💛 | ❌ | -| [79. 单词搜索](https://leetcode.cn/problems/word-search/) | 💛 | ❌ | - -### BFS - -| 题目 | 难度 | 掌握度 | -| :----------------------------------------------------------------------------------------------- | :--: | ------ | -| [752. 打开转盘锁](https://leetcode.cn/problems/open-the-lock/) | 💛 | ❌ | -| [773. 滑动谜题](https://leetcode.cn/problems/sliding-puzzle/) | ❤️ | ❌ | -| [919. 完全二叉树插入器](https://leetcode.cn/problems/complete-binary-tree-inserter/) | 💛 | ✔️ | -| [841. 钥匙和房间](https://leetcode.cn/problems/keys-and-rooms/) | 💛 | ✔️ | -| [433. 最小基因变化](https://leetcode.cn/problems/minimum-genetic-mutation/) | 💛 | ❗ | -| [1926. 迷宫中离入口最近的出口](https://leetcode.cn/problems/nearest-exit-from-entrance-in-maze/) | 💛 | ✔️ | -| [1091. 二进制矩阵中的最短路径](https://leetcode.cn/problems/shortest-path-in-binary-matrix/) | 💛 | ✔️ | -| [994. 腐烂的橘子](https://leetcode.cn/problems/rotting-oranges/) | 💛 | ✔️ | -| [365. 水壶问题](https://leetcode.cn/problems/water-and-jug-problem/) | 💛 | ❌ | -| [721. 账户合并](https://leetcode.cn/problems/accounts-merge/) | 💛 | ❌ | -| [127. 单词接龙](https://leetcode.cn/problems/word-ladder/) | ❤️ | ❌ | - -### 动态规划 - -#### 斐波那契 - -| 题目 | 难度 | 掌握度 | -| --------------------------------------------------------------------------------- | :--: | :----: | -| [509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/) | 💚 | ✔️ | -| [1137. 第 N 个泰波那契数](https://leetcode.cn/problems/n-th-tribonacci-number/) | 💚 | ✔️ | -| [70. 爬楼梯](https://leetcode.cn/problems/climbing-stairs/) | 💚 | ✔️ | -| [746. 使用最小花费爬楼梯](https://leetcode.cn/problems/min-cost-climbing-stairs/) | 💚 | ✔️ | -| [198. 打家劫舍](https://leetcode.cn/problems/house-robber/) | 💛 | ✔️ | -| [740. 删除并获得点数](https://leetcode.cn/problems/delete-and-earn/) | 💛 | ✔️ | - -#### 一维 - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------------------------ | :--: | :----: | -| [2140. 解决智力问题](https://leetcode.cn/problems/solving-questions-with-brainpower/) | 💛 | ❌ | -| [2466. 统计构造好字符串的方案数](https://leetcode.cn/problems/count-ways-to-build-good-strings/) | 💛 | ❌ | -| [91. 解码方法](https://leetcode.cn/problems/decode-ways/) | 💛 | ❌ | -| [983. 最低票价](https://leetcode.cn/problems/minimum-cost-for-tickets/) | 💛 | ❌ | -| [264. 丑数 II](https://leetcode.cn/problems/ugly-number-ii/) | 💛 | ❗ | -| [1201. 丑数 III](https://leetcode.cn/problems/ugly-number-iii/) | 💛 | ❌ | -| [313. 超级丑数](https://leetcode.cn/problems/super-ugly-number/) | 💛 | ❌ | - -#### 矩阵 - -| 题目 | 难度 | 掌握度 | -| ----------------------------------------------------------------------------- | :--: | :----: | -| [118. 杨辉三角](https://leetcode.cn/problems/pascals-triangle/) | 💚 | ✔️ | -| [119. 杨辉三角 II](https://leetcode.cn/problems/pascals-triangle-ii/) | 💚 | ✔️ | -| [62. 不同路径](https://leetcode.cn/problems/unique-paths/) | 💛 | ✔️ | -| [63. 不同路径 II](https://leetcode.cn/problems/unique-paths-ii/) | 💛 | ✔️ | -| [64. 最小路径和](https://leetcode.cn/problems/minimum-path-sum/) | 💛 | ✔️ | -| [120. 三角形最小路径和](https://leetcode.cn/problems/triangle/) | 💛 | ✔️ | -| [931. 下降路径最小和](https://leetcode.cn/problems/minimum-falling-path-sum/) | 💛 | ✔️ | -| [221. 最大正方形](https://leetcode.cn/problems/maximal-square/) | 💛 | ✔️ | - -#### 字符串 - -| 题目 | 难度 | 掌握度 | -| ---------------------------------------------------------------------------------------------------------- | :--: | :----: | -| [5. 最长回文子串](https://leetcode.cn/problems/longest-palindromic-substring/) | 💛 | ✔️ | -| [139. 单词拆分](https://leetcode.cn/problems/word-break/) | 💛 | ❌ | -| [72. 编辑距离](https://leetcode.cn/problems/edit-distance/) | 💛 | ❗ | -| [583. 两个字符串的删除操作](https://leetcode.cn/problems/delete-operation-for-two-strings/) | 💛 | ❌ | -| [712. 两个字符串的最小ASCII删除和](https://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/) | 💛 | ❌ | -| [516. 最长回文子序列](https://leetcode.cn/problems/longest-palindromic-subsequence/) | 💛 | ❌ | -| [115. 不同的子序列](https://leetcode.cn/problems/distinct-subsequences/) | ❤️ | ❌ | - -#### 最长递增/公共子序列 - -| 题目 | 难度 | 掌握度 | -| --------------------------------------------------------------------------------------------------------------------------- | :--: | :----: | -| [300. 最长递增子序列](https://leetcode.cn/problems/longest-increasing-subsequence/) | 💛 | ❌ | -| [673. 最长递增子序列的个数](https://leetcode.cn/problems/number-of-longest-increasing-subsequence/) | 💛 | ❌ | -| [646. 最长数对链](https://leetcode.cn/problems/maximum-length-of-pair-chain/) | 💛 | ✔️ | -| [1218. 最长定差子序列](https://leetcode.cn/problems/longest-arithmetic-subsequence-of-given-difference/) | 💛 | ❌ | -| [1027. 最长等差数列](https://leetcode.cn/problems/longest-arithmetic-subsequence/) | 💛 | ❌ | -| [1143. 最长公共子序列](https://leetcode.cn/problems/longest-common-subsequence/) | 💛 | ❗ | -| [1035. 不相交的线](https://leetcode.cn/problems/uncrossed-lines/) | 💛 | ❌ | -| [1312. 让字符串成为回文串的最少插入次数](https://leetcode.cn/problems/minimum-insertion-steps-to-make-a-string-palindrome/) | ❤️ | ❌ | - -#### 背包问题 - -| 题目 | 难度 | 掌握度 | -| ----------------------------------------------------------------------------- | ---- | ------ | -| [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/) | 💛 | ❌ | -| [322. 零钱兑换](https://leetcode.cn/problems/coin-change/) | 💛 | ❌ | -| [518. 零钱兑换 II](https://leetcode.cn/problems/coin-change-ii/) | 💛 | ❌ | - -#### 买卖股票的最佳时间/状态机 - -#### 其他 - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------------------------------- | ---- | ------ | -| [53. 最大子数组和](https://leetcode.cn/problems/maximum-subarray/) | 💛 | ❌ | -| [354. 俄罗斯套娃信封问题](https://leetcode.cn/problems/russian-doll-envelopes/) | ❤️ | ❌ | - -### 贪心算法 - -| 题目 | 难度 | 掌握度 | -| -------------------------------------------------------------- | ---- | ------ | -| [561. 数组拆分](https://leetcode.cn/problems/array-partition/) | 💚 | ❌ | -| [55. 跳跃游戏](https://leetcode.cn/problems/jump-game/) | 💛 | ❌ | -| [45. 跳跃游戏 II](https://leetcode.cn/problems/jump-game-ii/) | 💛 | ❌ | - -### 分治算法 - -| 题目 | 掌握度 | -| --------------------------------------------------------------------------- | ------ | -| [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/) | ✔️ | - -### 数学 - -| 题目 | 难度 | 掌握度 | -| ------------------------------------------------------ | ---- | ------ | -| [66. 加一](https://leetcode.cn/problems/plus-one/) | 💚 | ✔️ | -| [263. 丑数](https://leetcode.cn/problems/ugly-number/) | 💚 | ✔️ | - -## 📚 资料 - -- **书籍** - - **刷题必备** - - 《剑指 offer》 - - 《编程之美》 - - 《编程之法:面试和算法心得》 - - 《算法谜题》 都是思维题 - - **基础** - - [《编程珠玑(第 2 版)》](https://www.amazon.cn/gp/product/B00SFZH0DC/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00SFZH0DC&linkCode=as2&tag=vastwork-23) - - [《编程珠玑(续)》](https://www.amazon.cn/gp/product/B0150BMQDM/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B0150BMQDM&linkCode=as2&tag=vastwork-23) - - [《数据结构与算法分析 : C++描述(第 4 版)》](https://www.amazon.cn/gp/product/B01LDG2DSG/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01LDG2DSG&linkCode=as2&tag=vastwork-23) - - [《数据结构与算法分析 : C 语言描述(第 2 版)》](https://www.amazon.cn/gp/product/B002WC7NGS/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B002WC7NGS&linkCode=as2&tag=vastwork-23) - - [《数据结构与算法分析 : Java 语言描述(第 2 版)》](https://www.amazon.cn/gp/product/B01CNP0CG6/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01CNP0CG6&linkCode=as2&tag=vastwork-23) - - [《算法(第 4 版)》](https://www.amazon.cn/gp/product/B009OCFQ0O/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B009OCFQ0O&linkCode=as2&tag=vastwork-23) - - **算法设计** - - [《算法设计与分析基础(第 3 版)》](https://www.amazon.cn/gp/product/B00S4HCQUI/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00S4HCQUI&linkCode=as2&tag=vastwork-23) - - 《Algorithm Design Manual》 - 算法设计手册 红皮书 - - [《算法导论》](https://www.amazon.cn/gp/product/B00AK7BYJY/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00AK7BYJY&linkCode=as2&tag=vastwork-23) - 是一本对算法介绍比较全面的经典书籍 - - 《Algorithms on Strings,Trees and Sequences》 - - 《Advanced Data Structures》 - 各种诡异高级的数据结构和算法 如元胞自动机、斐波纳契堆、线段树 600 块 -- **学习网站** - - https://labuladong.online/algo/ - - https://github.com/TheAlgorithms/Java - - https://github.com/nonstriater/Learn-Algorithms - - https://github.com/trekhleb/javascript-algorithms - - https://github.com/wangzheng0822/algo - - https://github.com/kdn251/interviews/blob/master/README-zh-cn.md#%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84 - - [July 博客](http://blog.csdn.net/v_july_v) - - 《数学建模十大经典算法》 - - 《数据挖掘领域十大经典算法》 - - 《十道海量数据处理面试题》 - - 《数字图像处理领域的二十四个经典算法》 - - 《精选微软等公司经典的算法面试 100 题》 - - [The-Art-Of-Programming-By-July](https://github.com/julycoding/The-Art-Of-Programming-By-July) - - [微软面试 100 题](http://blog.csdn.net/column/details/ms100.html) - - [程序员编程艺术](http://blog.csdn.net/v_JULY_v/article/details/6460494) -- **基本算法演示** - - - - -- **编程网站** - - [leetcode](http://leetcode-cn.com/) - - [openjudge](http://openjudge.cn/) -- **教程** - - [高级数据结构和算法](https://www.coursera.org/learn/gaoji-shuju-jiegou/) 北大教授张铭老师在 coursera 上的课程。完成这门课之时,你将掌握多维数组、广义表、Trie 树、AVL 树、伸展树等高级数据结构,并结合内排序、外排序、检索、索引有关的算法,高效地解决现实生活中一些比较复杂的应用问题。当然 coursera 上也还有很多其它算法方面的视频课程。 - - [算法设计与分析 Design and Analysis of Algorithms](https://class.coursera.org/algorithms-001/lecture) 由北大教授 Wanling Qu 在 coursera 讲授的一门算法课程。首先介绍一些与算法有关的基础知识,然后阐述经典的算法设计思想和分析技术,主要涉及的算法设计技术是:分治策略、动态规划、贪心法、回溯与分支限界等。每个视频都配有相应的讲义(pdf 文件)以便阅读和复习。 - - [算法面试通关 40 讲](https://time.geekbang.org/course/intro/100019701) - - [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) - - [Data Structures - Computer Science Course for Beginners](https://www.youtube.com/watch?v=zg9ih6SVACc) - 高赞 YouTube 视频教程 - -## 🚪 传送 - -| [技术文档归档](https://github.com/dunwu/blog) | [算法和数据结构教程系列](https://github.com/dunwu/algorithm-tutorial) | diff --git a/algorithm-template.html b/algorithm-template.html new file mode 100644 index 0000000..f8a099b --- /dev/null +++ b/algorithm-template.html @@ -0,0 +1,139 @@ + + + + + + 算法代码模板 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/archives/index.html b/archives/index.html new file mode 100644 index 0000000..43966e4 --- /dev/null +++ b/archives/index.html @@ -0,0 +1,104 @@ + + + + + + 归档 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/assets/css/0.styles.5ed860b4.css b/assets/css/0.styles.5ed860b4.css new file mode 100644 index 0000000..8549c38 --- /dev/null +++ b/assets/css/0.styles.5ed860b4.css @@ -0,0 +1 @@ +@import url(//at.alicdn.com/t/font_1678482_4tbhmh589x.css);.code-copy{color:#aaa;fill:#aaa;font-size:14px;display:inline-block;cursor:pointer}div[class*=aside-code] aside .code-copy,div[class*=language-] pre .code-copy{position:absolute;z-index:1000;top:7px;right:35px;opacity:0;font-size:16px}div[class*=aside-code] aside:hover .code-copy,div[class*=language-] pre:hover .code-copy{opacity:1}.content pre,.content pre[class*=language-]{overflow-y:hidden}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{position:static!important}div[class~=language-text]:before{content:"text"}div[class~=language-yml]:before{content:"yml"}div[class*=language-] pre{-webkit-user-select:text;-moz-user-select:text;user-select:text}p code{-webkit-user-select:all;-moz-user-select:all;user-select:all}@keyframes message-move-in{0%{opacity:0;transform:translateY(-100%)}to{opacity:1;transform:translateY(0)}}#message-container .message.move-in{animation:message-move-in .3s ease-in-out}@keyframes message-move-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-100%)}}#message-container .message.move-out{animation:message-move-out .3s ease-in-out;animation-fill-mode:forwards}#message-container .message{background:#fff;margin:10px 0;padding:0 10px;height:40px;box-shadow:0 0 10px 0 #ccc;font-size:14px;border-radius:3px;display:flex;align-items:center;transition:height .2s ease-in-out,margin .2s ease-in-out}#message-container{position:fixed;left:0;top:100px;right:0;display:flex;flex-direction:column;align-items:center}#message-container .message .text{color:#333;padding:0 20px 0 5px}.theme-code-block[data-v-4f1e9d0c]{display:none}.theme-code-block__active[data-v-4f1e9d0c]{display:block}.theme-code-block>pre[data-v-4f1e9d0c]{background-color:orange}@media (max-width:419px){.theme-code-group div[class*=language-][data-v-4f1e9d0c]{margin:0}}.theme-mode-light[data-v-2f5f1757]{--bodyBg:#f4f4f4;--customBlockBg:#f1f1f1;--textColor:#00323c;--borderColor:rgba(0,0,0,0.12)}.theme-mode-dark[data-v-2f5f1757]{--bodyBg:#27272b;--customBlockBg:#27272b;--textColor:#9b9baa;--borderColor:#30363d}.theme-mode-read[data-v-2f5f1757]{--bodyBg:#ececcc;--customBlockBg:#ececcc;--textColor:#704214;--textLightenColor:#963}.theme-style-line.theme-mode-light[data-v-2f5f1757]{--bodyBg:#fff}.theme-style-line.theme-mode-dark[data-v-2f5f1757]{--bodyBg:#1e1e22}.theme-style-line.theme-mode-read[data-v-2f5f1757]{--bodyBg:#f5f5d5}.theme-mode-light[data-v-2f5f1757]{--bodyBg:#fff;--mainBg:#fff;--sidebarBg:hsla(0,0%,100%,0.8);--blurBg:hsla(0,0%,100%,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#f6f6f6;--codeColor:#525252}.theme-mode-light code[class*=language-][data-v-2f5f1757],.theme-mode-light pre[class*=language-][data-v-2f5f1757]{color:#000;background:none;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-light code[class*=language-][data-v-2f5f1757]::-moz-selection,.theme-mode-light code[class*=language-][data-v-2f5f1757] ::-moz-selection,.theme-mode-light pre[class*=language-][data-v-2f5f1757]::-moz-selection,.theme-mode-light pre[class*=language-][data-v-2f5f1757] ::-moz-selection{text-shadow:none;background:#b3d4fc}.theme-mode-light code[class*=language-][data-v-2f5f1757]::selection,.theme-mode-light code[class*=language-][data-v-2f5f1757] ::selection,.theme-mode-light pre[class*=language-][data-v-2f5f1757]::selection,.theme-mode-light pre[class*=language-][data-v-2f5f1757] ::selection{text-shadow:none;background:#b3d4fc}@media print{.theme-mode-light code[class*=language-][data-v-2f5f1757],.theme-mode-light pre[class*=language-][data-v-2f5f1757]{text-shadow:none}}.theme-mode-light pre[class*=language-][data-v-2f5f1757]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-light :not(pre)>code[class*=language-][data-v-2f5f1757],.theme-mode-light pre[class*=language-][data-v-2f5f1757]{background:#f5f2f0}.theme-mode-light :not(pre)>code[class*=language-][data-v-2f5f1757]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-light .token.cdata[data-v-2f5f1757],.theme-mode-light .token.comment[data-v-2f5f1757],.theme-mode-light .token.doctype[data-v-2f5f1757],.theme-mode-light .token.prolog[data-v-2f5f1757]{color:#708090}.theme-mode-light .token.punctuation[data-v-2f5f1757]{color:#999}.theme-mode-light .namespace[data-v-2f5f1757]{opacity:.7}.theme-mode-light .token.boolean[data-v-2f5f1757],.theme-mode-light .token.constant[data-v-2f5f1757],.theme-mode-light .token.deleted[data-v-2f5f1757],.theme-mode-light .token.number[data-v-2f5f1757],.theme-mode-light .token.property[data-v-2f5f1757],.theme-mode-light .token.symbol[data-v-2f5f1757],.theme-mode-light .token.tag[data-v-2f5f1757]{color:#905}.theme-mode-light .token.attr-name[data-v-2f5f1757],.theme-mode-light .token.builtin[data-v-2f5f1757],.theme-mode-light .token.char[data-v-2f5f1757],.theme-mode-light .token.inserted[data-v-2f5f1757],.theme-mode-light .token.selector[data-v-2f5f1757],.theme-mode-light .token.string[data-v-2f5f1757]{color:#690}.theme-mode-light .language-css .token.string[data-v-2f5f1757],.theme-mode-light .style .token.string[data-v-2f5f1757],.theme-mode-light .token.entity[data-v-2f5f1757],.theme-mode-light .token.operator[data-v-2f5f1757],.theme-mode-light .token.url[data-v-2f5f1757]{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.theme-mode-light .token.atrule[data-v-2f5f1757],.theme-mode-light .token.attr-value[data-v-2f5f1757],.theme-mode-light .token.keyword[data-v-2f5f1757]{color:#07a}.theme-mode-light .token.class-name[data-v-2f5f1757],.theme-mode-light .token.function[data-v-2f5f1757]{color:#dd4a68}.theme-mode-light .token.important[data-v-2f5f1757],.theme-mode-light .token.regex[data-v-2f5f1757],.theme-mode-light .token.variable[data-v-2f5f1757]{color:#e90}.theme-mode-light .token.bold[data-v-2f5f1757],.theme-mode-light .token.important[data-v-2f5f1757]{font-weight:700}.theme-mode-light .token.italic[data-v-2f5f1757]{font-style:italic}.theme-mode-light .token.entity[data-v-2f5f1757]{cursor:help}.theme-mode-light div[class*=language-] .highlight-lines .highlighted[data-v-2f5f1757],.theme-mode-light div[class*=language-].line-numbers-mode .highlight-lines .highlighted[data-v-2f5f1757]:before{background-color:hsla(0,0%,78.4%,.4)}.theme-mode-dark[data-v-2f5f1757]{--bodyBg:#1e1e22;--mainBg:#1e1e22;--sidebarBg:rgba(30,30,34,0.8);--blurBg:rgba(30,30,34,0.8);--textColor:#8c8c96;--textLightenColor:#0085ad;--borderColor:#2c2c3a;--codeBg:#252526;--codeColor:#fff}.theme-mode-dark code[class*=language-][data-v-2f5f1757],.theme-mode-dark pre[class*=language-][data-v-2f5f1757]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-dark pre[class*=language-][data-v-2f5f1757]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-dark :not(pre)>code[class*=language-][data-v-2f5f1757],.theme-mode-dark pre[class*=language-][data-v-2f5f1757]{background:#2d2d2d}.theme-mode-dark :not(pre)>code[class*=language-][data-v-2f5f1757]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-dark .token.block-comment[data-v-2f5f1757],.theme-mode-dark .token.cdata[data-v-2f5f1757],.theme-mode-dark .token.comment[data-v-2f5f1757],.theme-mode-dark .token.doctype[data-v-2f5f1757],.theme-mode-dark .token.prolog[data-v-2f5f1757]{color:#999}.theme-mode-dark .token.punctuation[data-v-2f5f1757]{color:#ccc}.theme-mode-dark .token.attr-name[data-v-2f5f1757],.theme-mode-dark .token.deleted[data-v-2f5f1757],.theme-mode-dark .token.namespace[data-v-2f5f1757],.theme-mode-dark .token.tag[data-v-2f5f1757]{color:#e2777a}.theme-mode-dark .token.function-name[data-v-2f5f1757]{color:#6196cc}.theme-mode-dark .token.boolean[data-v-2f5f1757],.theme-mode-dark .token.function[data-v-2f5f1757],.theme-mode-dark .token.number[data-v-2f5f1757]{color:#f08d49}.theme-mode-dark .token.class-name[data-v-2f5f1757],.theme-mode-dark .token.constant[data-v-2f5f1757],.theme-mode-dark .token.property[data-v-2f5f1757],.theme-mode-dark .token.symbol[data-v-2f5f1757]{color:#f8c555}.theme-mode-dark .token.atrule[data-v-2f5f1757],.theme-mode-dark .token.builtin[data-v-2f5f1757],.theme-mode-dark .token.important[data-v-2f5f1757],.theme-mode-dark .token.keyword[data-v-2f5f1757],.theme-mode-dark .token.selector[data-v-2f5f1757]{color:#cc99cd}.theme-mode-dark .token.attr-value[data-v-2f5f1757],.theme-mode-dark .token.char[data-v-2f5f1757],.theme-mode-dark .token.regex[data-v-2f5f1757],.theme-mode-dark .token.string[data-v-2f5f1757],.theme-mode-dark .token.variable[data-v-2f5f1757]{color:#7ec699}.theme-mode-dark .token.entity[data-v-2f5f1757],.theme-mode-dark .token.operator[data-v-2f5f1757],.theme-mode-dark .token.url[data-v-2f5f1757]{color:#67cdcc}.theme-mode-dark .language-css .token.string[data-v-2f5f1757],.theme-mode-dark .style .token.string[data-v-2f5f1757],.theme-mode-dark .token.entity[data-v-2f5f1757],.theme-mode-dark .token.operator[data-v-2f5f1757],.theme-mode-dark .token.url[data-v-2f5f1757]{background:none}.theme-mode-dark .token.bold[data-v-2f5f1757],.theme-mode-dark .token.important[data-v-2f5f1757]{font-weight:700}.theme-mode-dark .token.italic[data-v-2f5f1757]{font-style:italic}.theme-mode-dark .token.entity[data-v-2f5f1757]{cursor:help}.theme-mode-dark .token.inserted[data-v-2f5f1757]{color:green}.theme-mode-read[data-v-2f5f1757]{--bodyBg:#f5f5d5;--mainBg:#f5f5d5;--sidebarBg:rgba(245,245,213,0.8);--blurBg:rgba(245,245,213,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#282c34;--codeColor:#fff}.theme-mode-read code[class*=language-][data-v-2f5f1757],.theme-mode-read pre[class*=language-][data-v-2f5f1757]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-read pre[class*=language-][data-v-2f5f1757]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-read :not(pre)>code[class*=language-][data-v-2f5f1757],.theme-mode-read pre[class*=language-][data-v-2f5f1757]{background:#2d2d2d}.theme-mode-read :not(pre)>code[class*=language-][data-v-2f5f1757]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-read .token.block-comment[data-v-2f5f1757],.theme-mode-read .token.cdata[data-v-2f5f1757],.theme-mode-read .token.comment[data-v-2f5f1757],.theme-mode-read .token.doctype[data-v-2f5f1757],.theme-mode-read .token.prolog[data-v-2f5f1757]{color:#999}.theme-mode-read .token.punctuation[data-v-2f5f1757]{color:#ccc}.theme-mode-read .token.attr-name[data-v-2f5f1757],.theme-mode-read .token.deleted[data-v-2f5f1757],.theme-mode-read .token.namespace[data-v-2f5f1757],.theme-mode-read .token.tag[data-v-2f5f1757]{color:#e2777a}.theme-mode-read .token.function-name[data-v-2f5f1757]{color:#6196cc}.theme-mode-read .token.boolean[data-v-2f5f1757],.theme-mode-read .token.function[data-v-2f5f1757],.theme-mode-read .token.number[data-v-2f5f1757]{color:#f08d49}.theme-mode-read .token.class-name[data-v-2f5f1757],.theme-mode-read .token.constant[data-v-2f5f1757],.theme-mode-read .token.property[data-v-2f5f1757],.theme-mode-read .token.symbol[data-v-2f5f1757]{color:#f8c555}.theme-mode-read .token.atrule[data-v-2f5f1757],.theme-mode-read .token.builtin[data-v-2f5f1757],.theme-mode-read .token.important[data-v-2f5f1757],.theme-mode-read .token.keyword[data-v-2f5f1757],.theme-mode-read .token.selector[data-v-2f5f1757]{color:#cc99cd}.theme-mode-read .token.attr-value[data-v-2f5f1757],.theme-mode-read .token.char[data-v-2f5f1757],.theme-mode-read .token.regex[data-v-2f5f1757],.theme-mode-read .token.string[data-v-2f5f1757],.theme-mode-read .token.variable[data-v-2f5f1757]{color:#7ec699}.theme-mode-read .token.entity[data-v-2f5f1757],.theme-mode-read .token.operator[data-v-2f5f1757],.theme-mode-read .token.url[data-v-2f5f1757]{color:#67cdcc}.theme-mode-read .language-css .token.string[data-v-2f5f1757],.theme-mode-read .style .token.string[data-v-2f5f1757],.theme-mode-read .token.entity[data-v-2f5f1757],.theme-mode-read .token.operator[data-v-2f5f1757],.theme-mode-read .token.url[data-v-2f5f1757]{background:none}.theme-mode-read .token.bold[data-v-2f5f1757],.theme-mode-read .token.important[data-v-2f5f1757]{font-weight:700}.theme-mode-read .token.italic[data-v-2f5f1757]{font-style:italic}.theme-mode-read .token.entity[data-v-2f5f1757]{cursor:help}.theme-mode-read .token.inserted[data-v-2f5f1757]{color:green}.theme-code-group[data-v-2f5f1757],.theme-code-group__nav[data-v-2f5f1757]{background-color:var(--codeBg);padding-bottom:22px;border-radius:6px;padding-left:10px;padding-top:10px}.theme-code-group__nav[data-v-2f5f1757]{margin-bottom:-35px}.theme-code-group__ul[data-v-2f5f1757]{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.theme-code-group__li[data-v-2f5f1757],.theme-code-group__nav-tab[data-v-2f5f1757]{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:var(--codeColor);font-weight:600;opacity:.85}.theme-code-group__nav-tab-active[data-v-2f5f1757]{border-bottom:1px solid #11a8cd;opacity:1}.pre-blank[data-v-2f5f1757]{color:#11a8cd}body .theme-vdoing-content code{color:var(--textLightenColor);padding:.25rem .5rem;margin:0;font-size:.9em;background-color:hsla(0,0%,39.2%,.08);border-radius:3px}body .theme-vdoing-content code .token.deleted{color:#ec5975}body .theme-vdoing-content code .token.inserted{color:#11a8cd}body .theme-vdoing-content pre,body .theme-vdoing-content pre[class*=language-]{line-height:1.4;padding:1.25rem 1.5rem;margin:.85rem 0;background-color:#282c34;border-radius:6px;overflow:auto}body .theme-vdoing-content pre[class*=language-] code,body .theme-vdoing-content pre code{color:var(--codeColor);padding:0;background-color:transparent;border-radius:0}div[class*=language-]{position:relative;background-color:var(--codeBg);border-radius:6px}div[class*=language-] .highlight-lines{-webkit-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.4}div[class*=language-] .highlight-lines .highlighted{background-color:rgba(0,0,0,.3)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent;position:relative!important;z-index:1}div[class*=language-]:before{position:absolute;z-index:3;top:.8em;right:1em;font-size:.8rem;color:hsla(0,0%,58.8%,.7)}div[class*=language-]:not(.line-numbers-mode) .line-numbers-wrapper{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlighted{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{content:" ";position:absolute;z-index:3;left:0;top:0;display:block;width:2.5rem;height:100%;background-color:rgba(0,0,0,.3)}div[class*=language-].line-numbers-mode pre{padding-left:3.5rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers-wrapper{position:absolute;top:0;width:2.5rem;text-align:center;color:hsla(0,0%,49.8%,.5);padding:1.25rem 0;line-height:1.4}div[class*=language-].line-numbers-mode .line-numbers-wrapper br{-webkit-user-select:none;user-select:none}div[class*=language-].line-numbers-mode .line-numbers-wrapper .line-number{position:relative;z-index:4;-webkit-user-select:none;user-select:none;font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;z-index:2;top:0;left:0;width:2.5rem;height:100%;border-radius:6px 0 0 6px;border-right:1px solid var(--borderColor);background-color:var(--codeBg)}div[class~=language-js]:before{content:"js"}div[class~=language-ts]:before{content:"ts"}div[class~=language-html]:before{content:"html"}div[class~=language-md]:before{content:"md"}div[class~=language-vue]:before{content:"vue"}div[class~=language-css]:before{content:"css"}div[class~=language-sass]:before{content:"sass"}div[class~=language-scss]:before{content:"scss"}div[class~=language-less]:before{content:"less"}div[class~=language-stylus]:before{content:"stylus"}div[class~=language-go]:before{content:"go"}div[class~=language-java]:before{content:"java"}div[class~=language-c]:before{content:"c"}div[class~=language-sh]:before{content:"sh"}div[class~=language-yaml]:before{content:"yaml"}div[class~=language-py]:before{content:"py"}div[class~=language-docker]:before{content:"docker"}div[class~=language-dockerfile]:before{content:"dockerfile"}div[class~=language-makefile]:before{content:"makefile"}div[class~=language-javascript]:before{content:"js"}div[class~=language-typescript]:before{content:"ts"}div[class~=language-markup]:before{content:"html"}div[class~=language-markdown]:before{content:"md"}div[class~=language-json]:before{content:"json"}div[class~=language-ruby]:before{content:"rb"}div[class~=language-python]:before{content:"py"}div[class~=language-bash]:before{content:"sh"}div[class~=language-php]:before{content:"php"}.custom-block .custom-block-title{font-weight:600;margin-bottom:.2rem}.custom-block p{margin:0}.custom-block.danger,.custom-block.note,.custom-block.tip,.custom-block.warning{padding:.5rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-block.tip{background-color:#f3f5f7;border-color:#42b983;color:#215d42}.custom-block.warning{background-color:#fff7d0;border-color:#e7c000;color:#6b5900}.custom-block.warning .custom-block-title{color:#b29400}.custom-block.warning a{color:var(--textColor)}.custom-block.danger{background-color:#ffe6e6;border-color:#c00;color:#4d0000}.custom-block.danger .custom-block-title{color:#900}.custom-block.danger a{color:var(--textColor)}.custom-block.note{background-color:#e8f5fa;border-color:#157bae;color:#0d4a68}.custom-block.right{color:var(--textColor);font-size:.9rem;text-align:right}.custom-block.theorem{margin:1rem 0;padding:.8rem 1.5rem;border-radius:2px;background-color:var(--customBlockBg)}.custom-block.theorem .title{font-weight:700;margin:.5rem 0}.custom-block.details{display:block;position:relative;border-radius:2px;margin:1em 0;padding:1.6em;background-color:var(--customBlockBg)}.custom-block.details p{margin:.8rem 0}.custom-block.details h4{margin-top:0}.custom-block.details figure:last-child,.custom-block.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-block.details summary{outline:none;cursor:pointer}.custom-block.details summary:hover{color:#11a8cd}.theme-mode-dark .custom-block.warning{background-color:rgba(255,247,208,.2);color:#e7c000}.theme-mode-dark .custom-block.warning .custom-block-title{color:#ffdc2f}.theme-mode-dark .custom-block.tip{background-color:rgba(243,245,247,.2);color:#42b983}.theme-mode-dark .custom-block.danger{background-color:rgba(255,230,230,.4);color:maroon}.theme-mode-dark .custom-block.danger a{color:#11a8cd}.theme-mode-dark .custom-block.note{background-color:rgba(243,245,247,.2);color:#157bae}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-bottom:6px solid #ccc}.arrow.down,.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent}.arrow.down{border-top:6px solid #ccc}.arrow.right{border-left:6px solid #ccc}.arrow.left,.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent}.arrow.left{border-right:6px solid #ccc}.theme-vdoing-content:not(.custom){max-width:860px}.table-of-contents .badge{vertical-align:middle}.center-container{text-align:center}.center-container>h1,.center-container>h2,.center-container>h3,.center-container>h4,.center-container>h5,.center-container>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.center-container>h1 a.header-anchor,.center-container>h2 a.header-anchor,.center-container>h3 a.header-anchor,.center-container>h4 a.header-anchor,.center-container>h5 a.header-anchor,.center-container>h6 a.header-anchor{float:none;padding-right:0;margin-left:-.9rem}.cardListContainer{margin:.7rem 0}.cardListContainer>:not(.card-list){display:none}.cardListContainer .card-list{margin:-.35rem;display:flex;flex-wrap:wrap;align-items:flex-start}.cardListContainer .card-list .card-item{width:calc(33.33333% - .7rem);margin:.35rem;background:var(--bodyBg);border-radius:3px;color:var(--textColor);display:flex;box-shadow:1px 1px 2px 0 rgba(0,0,0,.06);transition:all .4s}.cardListContainer .card-list .card-item:hover{text-decoration:none;box-shadow:0 10px 20px -10px var(--randomColor,rgba(0,0,0,.15));transform:translateY(-3px) scale(1.01)}.cardListContainer .card-list .card-item:hover img{box-shadow:3px 2px 7px rgba(0,0,0,.15)}.cardListContainer .card-list .card-item:hover div p{text-shadow:3px 2px 5px rgba(0,0,0,.15)}.cardListContainer .card-list .card-item img{width:60px;height:60px;border-radius:50%;border:2px solid #fff;margin:1rem 0 1rem 1rem;box-shadow:3px 2px 5px rgba(0,0,0,.08);transition:all .4s}.cardListContainer .card-list .card-item div{flex:1;display:inline-block;float:right;padding:1rem 0}.cardListContainer .card-list .card-item div p{margin:0;padding:0 1rem;transition:text-shadow .4s;text-align:center}.cardListContainer .card-list .card-item div .name{margin:.2rem 0 .3rem}.cardListContainer .card-list .card-item div .desc{font-size:.8rem;line-height:1.1rem;opacity:.8;margin-bottom:.2rem}.cardListContainer .card-list .card-item.row-1{width:calc(100% - .7rem)}.cardListContainer .card-list .card-item.row-1 img{margin-left:2rem}.cardListContainer .card-list .card-item.row-2{width:calc(50% - .7rem)}.cardListContainer .card-list .card-item.row-2 img{margin-left:1.5rem}.cardListContainer .card-list .card-item.row-3{width:calc(33.33333% - .7rem)}.cardListContainer .card-list .card-item.row-4{width:calc(25% - .7rem)}.cardImgListContainer{margin:1rem 0}.cardImgListContainer>:not(.card-list){display:none}.cardImgListContainer .card-list{margin:-.5rem;display:flex;flex-wrap:wrap;align-items:flex-start}.cardImgListContainer .card-list .card-item{width:calc(33.33333% - 1rem);margin:.5rem;background:var(--mainBg);border:1px solid rgba(0,0,0,.1);box-sizing:border-box;border-radius:3px;overflow:hidden;color:var(--textColor);box-shadow:2px 2px 10px rgba(0,0,0,.04);display:flex;flex-direction:column;justify-content:flex-start;align-items:stretch;align-content:stretch;transition:all .4s}.cardImgListContainer .card-list .card-item:hover{box-shadow:1px 1px 20px rgba(0,0,0,.1);transform:translateY(-3px)}.cardImgListContainer .card-list .card-item .box-img{overflow:hidden;position:relative;background:#eee}.cardImgListContainer .card-list .card-item .box-img img{display:block;width:100%;height:100%;transition:all .3s}.cardImgListContainer .card-list .card-item a{color:var(--textColor);transition:color .3s}.cardImgListContainer .card-list .card-item a:hover{text-decoration:none}.cardImgListContainer .card-list .card-item .box-info{padding:.8rem 1rem}.cardImgListContainer .card-list .card-item .box-info p{margin:0}.cardImgListContainer .card-list .card-item .box-info .desc{margin-top:.3rem;opacity:.8;font-size:.9rem;line-height:1.1rem;overflow:hidden;white-space:normal;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical}.cardImgListContainer .card-list .card-item .box-footer{overflow:hidden;padding:.8rem 1rem;border-top:1px solid rgba(0,0,0,.1)}.cardImgListContainer .card-list .card-item .box-footer img{width:1.8rem;height:1.8rem;border-radius:50%;float:left}.cardImgListContainer .card-list .card-item .box-footer span{line-height:1.8rem;float:left;margin-left:.6rem;font-size:.8rem}.cardImgListContainer .card-list .card-item.row-1{width:calc(100% - 1rem)}.cardImgListContainer .card-list .card-item.row-2{width:calc(50% - 1rem)}.cardImgListContainer .card-list .card-item.row-3{width:calc(33.33333% - 1rem)}.cardImgListContainer .card-list .card-item.row-4{width:calc(25% - 1rem)}.theme-mode-dark .cardImgListContainer .card-list .card-item,.theme-mode-dark .cardImgListContainer .card-list .card-item .box-footer{border-color:var(--borderColor)}@media (max-width:900px){.cardListContainer .card-list .card-item.row-4{width:calc(33.33333% - .7rem)}.cardImgListContainer .card-list .card-item.row-4{width:calc(33.33333% - 1rem)}}@media (max-width:720px){.cardListContainer .card-list .card-item.row-3,.cardListContainer .card-list .card-item.row-4{width:calc(50% - .7rem)}.cardListContainer .card-list .card-item.row-3 img,.cardListContainer .card-list .card-item.row-4 img{margin-left:1.5rem}.cardImgListContainer .card-list .card-item.row-3,.cardImgListContainer .card-list .card-item.row-4{width:calc(50% - 1rem)}}@media (max-width:500px){.cardListContainer .card-list .card-item.row-1,.cardListContainer .card-list .card-item.row-2,.cardListContainer .card-list .card-item.row-3,.cardListContainer .card-list .card-item.row-4{width:calc(100% - .7rem)}.cardListContainer .card-list .card-item.row-1 img,.cardListContainer .card-list .card-item.row-2 img,.cardListContainer .card-list .card-item.row-3 img,.cardListContainer .card-list .card-item.row-4 img{margin-left:1.5rem}.cardImgListContainer .card-list .card-item.row-1,.cardImgListContainer .card-list .card-item.row-2,.cardImgListContainer .card-list .card-item.row-3,.cardImgListContainer .card-list .card-item.row-4{width:calc(100% - 1rem)}}body,html{padding:0;margin:0}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-tap-highlight-color:transparent;font-size:16px;color:#2c3e50;background:var(--bodyBg)}a,button,input{outline:none;-webkit-tap-highlight-color:rgba(255,255,255,0);-webkit-focus-ring-color:transparent}@media (min-width:719px){::-webkit-scrollbar{width:6px;height:5px}::-webkit-scrollbar-track-piece{background-color:rgba(0,0,0,.15);-webkit-border-radius:3px}::-webkit-scrollbar-thumb:vertical{height:5px;background-color:rgba(0,0,0,.28);-webkit-border-radius:3px}::-webkit-scrollbar-thumb:horizontal{width:5px;background-color:rgba(0,0,0,.28);-webkit-border-radius:3px}}.card-box{border-radius:5px;background:var(--mainBg);box-shadow:0 0 4px 0 rgba(0,0,0,.1);transition:box-shadow .5s}.card-box:hover{box-shadow:0 1px 15px 0 rgba(0,0,0,.1)}@media (max-width:719px){.theme-style-line{margin-left:-1px;margin-right:-1px}}.theme-style-line .card-box{box-shadow:0 0;border:1px solid var(--borderColor)}.blur{backdrop-filter:saturate(200%) blur(20px)}.custom-page{min-height:calc(100vh - 3.6rem);padding-top:3.6rem;padding-bottom:.9rem}.custom-page .theme-vdoing-wrapper{margin:0 auto}body .search-box input{background-color:transparent;color:var(--textColor);border:1px solid var(--borderColor,#ccc)}@media (max-width:959px){body .search-box input{border-color:transparent}}.page{transition:padding .2s ease;padding-left:.8rem}.navbar{position:fixed;z-index:20;top:0;left:0;right:0;height:3.6rem;background-color:var(--blurBg);box-sizing:border-box;box-shadow:0 2px 5px rgba(0,0,0,.06)}.sidebar-mask{top:0;width:100vw;height:100vh}.sidebar-hover-trigger,.sidebar-mask{position:fixed;z-index:12;left:0;display:none}.sidebar-hover-trigger{top:8.1rem;bottom:0;width:24px}.sidebar{font-size:16px;background-color:var(--sidebarBg);width:18rem;position:fixed;z-index:13;margin:0;top:3.6rem;left:0;bottom:0;box-sizing:border-box;border-right:1px solid var(--borderColor);overflow-y:auto;transform:translateX(-100%);transition:transform .2s}@media (max-width:719px){.sidebar{background-color:var(--mainBg)}}.theme-vdoing-content:not(.custom){word-wrap:break-word}.theme-vdoing-content:not(.custom) a:hover{text-decoration:underline}.theme-vdoing-content:not(.custom) p.demo{padding:1rem 1.5rem;border:1px solid #ddd;border-radius:4px}.theme-vdoing-content:not(.custom) img{max-width:100%}.theme-vdoing-content.custom{padding:0;margin:0}.theme-vdoing-content.custom img{max-width:100%}a{font-weight:500;text-decoration:none}a,p a code{color:#11a8cd}p a code{font-weight:400}kbd{background:#eee;border:.15rem solid #ddd;border-bottom:.25rem solid #ddd;border-radius:.15rem;padding:0 .15em}blockquote{font-size:1rem;opacity:.75;border-left:.2rem solid hsla(0,0%,39.2%,.3);margin:1rem 0;padding:.25rem 0 .25rem 1rem}blockquote>p{margin:0}ol,ul{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25}.theme-vdoing-content:not(.custom)>h1,.theme-vdoing-content:not(.custom)>h2,.theme-vdoing-content:not(.custom)>h3,.theme-vdoing-content:not(.custom)>h4,.theme-vdoing-content:not(.custom)>h5,.theme-vdoing-content:not(.custom)>h6{margin-top:-3.1rem;padding-top:4.6rem;margin-bottom:0}.theme-vdoing-content:not(.custom)>h1:first-child,.theme-vdoing-content:not(.custom)>h2:first-child,.theme-vdoing-content:not(.custom)>h3:first-child,.theme-vdoing-content:not(.custom)>h4:first-child,.theme-vdoing-content:not(.custom)>h5:first-child,.theme-vdoing-content:not(.custom)>h6:first-child{margin-bottom:1rem}.theme-vdoing-content:not(.custom)>h1:first-child+.custom-block,.theme-vdoing-content:not(.custom)>h1:first-child+p,.theme-vdoing-content:not(.custom)>h1:first-child+pre,.theme-vdoing-content:not(.custom)>h2:first-child+.custom-block,.theme-vdoing-content:not(.custom)>h2:first-child+p,.theme-vdoing-content:not(.custom)>h2:first-child+pre,.theme-vdoing-content:not(.custom)>h3:first-child+.custom-block,.theme-vdoing-content:not(.custom)>h3:first-child+p,.theme-vdoing-content:not(.custom)>h3:first-child+pre,.theme-vdoing-content:not(.custom)>h4:first-child+.custom-block,.theme-vdoing-content:not(.custom)>h4:first-child+p,.theme-vdoing-content:not(.custom)>h4:first-child+pre,.theme-vdoing-content:not(.custom)>h5:first-child+.custom-block,.theme-vdoing-content:not(.custom)>h5:first-child+p,.theme-vdoing-content:not(.custom)>h5:first-child+pre,.theme-vdoing-content:not(.custom)>h6:first-child+.custom-block,.theme-vdoing-content:not(.custom)>h6:first-child+p,.theme-vdoing-content:not(.custom)>h6:first-child+pre{margin-top:2rem}h1:focus .header-anchor,h1:hover .header-anchor,h2:focus .header-anchor,h2:hover .header-anchor,h3:focus .header-anchor,h3:hover .header-anchor,h4:focus .header-anchor,h4:hover .header-anchor,h5:focus .header-anchor,h5:hover .header-anchor,h6:focus .header-anchor,h6:hover .header-anchor{opacity:1}.theme-vdoing-content:not(.custom)>.custom-block:first-child,.theme-vdoing-content:not(.custom)>p:first-child,.theme-vdoing-content:not(.custom)>pre:first-child{margin-top:2rem}h1{font-size:1.9rem}.theme-vdoing-content:not(.custom)>h1:first-child{display:none}h2{font-size:1.5rem;padding-bottom:.3rem;border-bottom:1px solid var(--borderColor)}h3{font-size:1.35rem}.page h4{font-size:1.25rem}.page h5{font-size:1.15rem}.page h6{font-size:1.05rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0}a.header-anchor:focus,a.header-anchor:hover{text-decoration:none}.line-number,code,kbd{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}ol,p,ul{line-height:1.7}hr{border:0;border-top:1px solid var(--borderColor)}table{border-collapse:collapse;margin:1rem 0;overflow-x:auto;width:100%;display:inline-table}@media (max-width:719px){table{display:block}}tr{border-top:1px solid var(--borderColor)}tr:nth-child(2n){background-color:hsla(0,0%,58.8%,.1)}td,th{border:1px solid var(--borderColor);padding:.6em 1em}@media (max-width:719px){td,th{padding:.3em .5em}}td a,th a{word-break:break-all}.theme-container{color:var(--textColor);min-height:100vh}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .theme-vdoing-content:not(.custom)>h1,.theme-container.no-navbar h2,.theme-container.no-navbar h3,.theme-container.no-navbar h4,.theme-container.no-navbar h5,.theme-container.no-navbar h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .sidebar{top:0}@media (min-width:720px){.theme-container.no-sidebar .sidebar{display:none}.theme-container.no-sidebar .page{padding-left:0}}@media (max-width:959px){.sidebar{font-size:15px}}@media (max-width:719px){.sidebar{width:17.099999999999998rem}}@media (min-width:720px) and (max-width:959px){.sidebar{width:16.2rem}.theme-container.sidebar-open .page{padding-left:17rem!important}}@media (max-width:719px){.sidebar{top:0;height:100vh;padding-top:3.6rem;transform:translateX(-100%);transition:transform .2s ease}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width:419px){h1{font-size:1.9rem}.theme-vdoing-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}@media (min-width:720px){.theme-container .sidebar-hover-trigger{display:block}.theme-container .sidebar-hover-trigger:hover~.sidebar,.theme-container:not(.sidebar-open) .sidebar-hover-trigger~.sidebar:hover{transform:translateX(0);z-index:100}.theme-container.sidebar-open .sidebar-mask{display:none}.theme-container.sidebar-open .sidebar{transform:translateX(0)}.theme-container.sidebar-open .sidebar-button{left:18rem}.theme-container.sidebar-open .page{padding-left:18.8rem;padding-right:.8rem}.theme-container.sidebar-open .sidebar-hover-trigger{display:none}.theme-container.have-rightmenu .page{padding-right:250px}.theme-container.no-sidebar .page{padding-left:0!important}.theme-container.no-sidebar .sidebar-hover-trigger{display:none}.theme-container.hide-navbar .sidebar-hover-trigger{top:4.5rem}.theme-container.hide-navbar .sidebar{top:0}.theme-container.no-sidebar .sidebar-button{display:none}}@media print{.buttons,.navbar,.sidebar{display:none}.page{padding-top:0!important}}@media (min-width:720px) and (max-width:959px){.theme-container.sidebar-open:not(.on-sidebar) .sidebar-button{left:12.6rem}}.home-wrapper .banner .banner-conent .hero h1{font-size:2.8rem!important}table{width:auto}.card-box,.page>:not(.footer){box-shadow:none!important}@media (min-width:940px){.page{padding-top:3.6rem!important}}.home-wrapper .banner .banner-conent{padding:0 2.9rem;box-sizing:border-box}.home-wrapper .banner .slide-banner .slide-banner-wrapper .slide-item a h2{margin-top:2rem;font-size:1.2rem!important}.home-wrapper .banner .slide-banner .slide-banner-wrapper .slide-item a p{padding:0 1rem}.gt-container .gt-ico-tip:after{content:"。( Win + . ) or ( ⌃ + ⌘ + ␣ ) open Emoji";color:#999}.gt-container .gt-meta{border-color:var(--borderColor)!important}.gt-container .gt-comments-null{color:var(--textColor);opacity:.5}.gt-container .gt-header-textarea{color:var(--textColor);background:hsla(0,0%,70.6%,.1)!important}.gt-container .gt-btn{border-color:#11a8cd!important;background-color:#11a8cd!important}.gt-container .gt-btn-preview{background-color:hsla(0,0%,100%,0)!important;color:#11a8cd!important}.gt-container a{color:#11a8cd!important}.gt-container .gt-svg svg{fill:#11a8cd!important}.gt-container .gt-comment-admin .gt-comment-content,.gt-container .gt-comment-content{background-color:hsla(0,0%,58.8%,.1)!important}.gt-container .gt-comment-admin .gt-comment-content:hover,.gt-container .gt-comment-content:hover{box-shadow:0 0 25px hsla(0,0%,58.8%,.5)!important}.gt-container .gt-comment-admin .gt-comment-content .gt-comment-body,.gt-container .gt-comment-content .gt-comment-body{color:var(--textColor)!important}.qq{position:relative}.qq:after{content:"可撩";background:#11a8cd;color:#fff;padding:0 5px;border-radius:10px;font-size:12px;position:absolute;top:-4px;right:-35px;transform:scale(.85)}body .vuepress-plugin-demo-block__wrapper,body .vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__display{border-color:hsla(0,0%,62.7%,.3)}body .vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer:hover .vuepress-plugin-demo-block__expand:before{border-top-color:#11a8cd!important;border-bottom-color:#11a8cd!important}body .vuepress-plugin-demo-block__wrapper .vuepress-plugin-demo-block__footer:hover svg{fill:#11a8cd!important}.suggestions{overflow:auto;max-height:calc(100vh - 6rem)}@media (max-width:719px){.suggestions{width:90vw;min-width:90vw!important;margin-right:-20px}}.suggestions .highlight{color:#11a8cd;font-weight:700}#nprogress{pointer-events:none}#nprogress .bar{background:#11a8cd;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}#nprogress .peg{display:block;position:absolute;right:0;width:100px;height:100%;box-shadow:0 0 10px #11a8cd,0 0 5px #11a8cd;opacity:1;transform:rotate(3deg) translateY(-4px)}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border-color:#11a8cd transparent transparent #11a8cd;border-style:solid;border-width:2px;border-radius:50%;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent #nprogress .bar,.nprogress-custom-parent #nprogress .spinner{position:absolute}@keyframes nprogress-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.icon.outbound{color:#aaa;display:inline-block;vertical-align:middle;position:relative;top:-1px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.theme-mode-light[data-v-439bb2a8]{--bodyBg:#f4f4f4;--customBlockBg:#f1f1f1;--textColor:#00323c;--borderColor:rgba(0,0,0,0.12)}.theme-mode-dark[data-v-439bb2a8]{--bodyBg:#27272b;--customBlockBg:#27272b;--textColor:#9b9baa;--borderColor:#30363d}.theme-mode-read[data-v-439bb2a8]{--bodyBg:#ececcc;--customBlockBg:#ececcc;--textColor:#704214;--textLightenColor:#963}.theme-style-line.theme-mode-light[data-v-439bb2a8]{--bodyBg:#fff}.theme-style-line.theme-mode-dark[data-v-439bb2a8]{--bodyBg:#1e1e22}.theme-style-line.theme-mode-read[data-v-439bb2a8]{--bodyBg:#f5f5d5}.theme-mode-light[data-v-439bb2a8]{--bodyBg:#fff;--mainBg:#fff;--sidebarBg:hsla(0,0%,100%,0.8);--blurBg:hsla(0,0%,100%,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#f6f6f6;--codeColor:#525252}.theme-mode-light code[class*=language-][data-v-439bb2a8],.theme-mode-light pre[class*=language-][data-v-439bb2a8]{color:#000;background:none;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-light code[class*=language-][data-v-439bb2a8]::-moz-selection,.theme-mode-light code[class*=language-][data-v-439bb2a8] ::-moz-selection,.theme-mode-light pre[class*=language-][data-v-439bb2a8]::-moz-selection,.theme-mode-light pre[class*=language-][data-v-439bb2a8] ::-moz-selection{text-shadow:none;background:#b3d4fc}.theme-mode-light code[class*=language-][data-v-439bb2a8]::selection,.theme-mode-light code[class*=language-][data-v-439bb2a8] ::selection,.theme-mode-light pre[class*=language-][data-v-439bb2a8]::selection,.theme-mode-light pre[class*=language-][data-v-439bb2a8] ::selection{text-shadow:none;background:#b3d4fc}@media print{.theme-mode-light code[class*=language-][data-v-439bb2a8],.theme-mode-light pre[class*=language-][data-v-439bb2a8]{text-shadow:none}}.theme-mode-light pre[class*=language-][data-v-439bb2a8]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-light :not(pre)>code[class*=language-][data-v-439bb2a8],.theme-mode-light pre[class*=language-][data-v-439bb2a8]{background:#f5f2f0}.theme-mode-light :not(pre)>code[class*=language-][data-v-439bb2a8]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-light .token.cdata[data-v-439bb2a8],.theme-mode-light .token.comment[data-v-439bb2a8],.theme-mode-light .token.doctype[data-v-439bb2a8],.theme-mode-light .token.prolog[data-v-439bb2a8]{color:#708090}.theme-mode-light .token.punctuation[data-v-439bb2a8]{color:#999}.theme-mode-light .namespace[data-v-439bb2a8]{opacity:.7}.theme-mode-light .token.boolean[data-v-439bb2a8],.theme-mode-light .token.constant[data-v-439bb2a8],.theme-mode-light .token.deleted[data-v-439bb2a8],.theme-mode-light .token.number[data-v-439bb2a8],.theme-mode-light .token.property[data-v-439bb2a8],.theme-mode-light .token.symbol[data-v-439bb2a8],.theme-mode-light .token.tag[data-v-439bb2a8]{color:#905}.theme-mode-light .token.attr-name[data-v-439bb2a8],.theme-mode-light .token.builtin[data-v-439bb2a8],.theme-mode-light .token.char[data-v-439bb2a8],.theme-mode-light .token.inserted[data-v-439bb2a8],.theme-mode-light .token.selector[data-v-439bb2a8],.theme-mode-light .token.string[data-v-439bb2a8]{color:#690}.theme-mode-light .language-css .token.string[data-v-439bb2a8],.theme-mode-light .style .token.string[data-v-439bb2a8],.theme-mode-light .token.entity[data-v-439bb2a8],.theme-mode-light .token.operator[data-v-439bb2a8],.theme-mode-light .token.url[data-v-439bb2a8]{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.theme-mode-light .token.atrule[data-v-439bb2a8],.theme-mode-light .token.attr-value[data-v-439bb2a8],.theme-mode-light .token.keyword[data-v-439bb2a8]{color:#07a}.theme-mode-light .token.class-name[data-v-439bb2a8],.theme-mode-light .token.function[data-v-439bb2a8]{color:#dd4a68}.theme-mode-light .token.important[data-v-439bb2a8],.theme-mode-light .token.regex[data-v-439bb2a8],.theme-mode-light .token.variable[data-v-439bb2a8]{color:#e90}.theme-mode-light .token.bold[data-v-439bb2a8],.theme-mode-light .token.important[data-v-439bb2a8]{font-weight:700}.theme-mode-light .token.italic[data-v-439bb2a8]{font-style:italic}.theme-mode-light .token.entity[data-v-439bb2a8]{cursor:help}.theme-mode-light div[class*=language-] .highlight-lines .highlighted[data-v-439bb2a8],.theme-mode-light div[class*=language-].line-numbers-mode .highlight-lines .highlighted[data-v-439bb2a8]:before{background-color:hsla(0,0%,78.4%,.4)}.theme-mode-dark[data-v-439bb2a8]{--bodyBg:#1e1e22;--mainBg:#1e1e22;--sidebarBg:rgba(30,30,34,0.8);--blurBg:rgba(30,30,34,0.8);--textColor:#8c8c96;--textLightenColor:#0085ad;--borderColor:#2c2c3a;--codeBg:#252526;--codeColor:#fff}.theme-mode-dark code[class*=language-][data-v-439bb2a8],.theme-mode-dark pre[class*=language-][data-v-439bb2a8]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-dark pre[class*=language-][data-v-439bb2a8]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-dark :not(pre)>code[class*=language-][data-v-439bb2a8],.theme-mode-dark pre[class*=language-][data-v-439bb2a8]{background:#2d2d2d}.theme-mode-dark :not(pre)>code[class*=language-][data-v-439bb2a8]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-dark .token.block-comment[data-v-439bb2a8],.theme-mode-dark .token.cdata[data-v-439bb2a8],.theme-mode-dark .token.comment[data-v-439bb2a8],.theme-mode-dark .token.doctype[data-v-439bb2a8],.theme-mode-dark .token.prolog[data-v-439bb2a8]{color:#999}.theme-mode-dark .token.punctuation[data-v-439bb2a8]{color:#ccc}.theme-mode-dark .token.attr-name[data-v-439bb2a8],.theme-mode-dark .token.deleted[data-v-439bb2a8],.theme-mode-dark .token.namespace[data-v-439bb2a8],.theme-mode-dark .token.tag[data-v-439bb2a8]{color:#e2777a}.theme-mode-dark .token.function-name[data-v-439bb2a8]{color:#6196cc}.theme-mode-dark .token.boolean[data-v-439bb2a8],.theme-mode-dark .token.function[data-v-439bb2a8],.theme-mode-dark .token.number[data-v-439bb2a8]{color:#f08d49}.theme-mode-dark .token.class-name[data-v-439bb2a8],.theme-mode-dark .token.constant[data-v-439bb2a8],.theme-mode-dark .token.property[data-v-439bb2a8],.theme-mode-dark .token.symbol[data-v-439bb2a8]{color:#f8c555}.theme-mode-dark .token.atrule[data-v-439bb2a8],.theme-mode-dark .token.builtin[data-v-439bb2a8],.theme-mode-dark .token.important[data-v-439bb2a8],.theme-mode-dark .token.keyword[data-v-439bb2a8],.theme-mode-dark .token.selector[data-v-439bb2a8]{color:#cc99cd}.theme-mode-dark .token.attr-value[data-v-439bb2a8],.theme-mode-dark .token.char[data-v-439bb2a8],.theme-mode-dark .token.regex[data-v-439bb2a8],.theme-mode-dark .token.string[data-v-439bb2a8],.theme-mode-dark .token.variable[data-v-439bb2a8]{color:#7ec699}.theme-mode-dark .token.entity[data-v-439bb2a8],.theme-mode-dark .token.operator[data-v-439bb2a8],.theme-mode-dark .token.url[data-v-439bb2a8]{color:#67cdcc}.theme-mode-dark .language-css .token.string[data-v-439bb2a8],.theme-mode-dark .style .token.string[data-v-439bb2a8],.theme-mode-dark .token.entity[data-v-439bb2a8],.theme-mode-dark .token.operator[data-v-439bb2a8],.theme-mode-dark .token.url[data-v-439bb2a8]{background:none}.theme-mode-dark .token.bold[data-v-439bb2a8],.theme-mode-dark .token.important[data-v-439bb2a8]{font-weight:700}.theme-mode-dark .token.italic[data-v-439bb2a8]{font-style:italic}.theme-mode-dark .token.entity[data-v-439bb2a8]{cursor:help}.theme-mode-dark .token.inserted[data-v-439bb2a8]{color:green}.theme-mode-read[data-v-439bb2a8]{--bodyBg:#f5f5d5;--mainBg:#f5f5d5;--sidebarBg:rgba(245,245,213,0.8);--blurBg:rgba(245,245,213,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#282c34;--codeColor:#fff}.theme-mode-read code[class*=language-][data-v-439bb2a8],.theme-mode-read pre[class*=language-][data-v-439bb2a8]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-read pre[class*=language-][data-v-439bb2a8]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-read :not(pre)>code[class*=language-][data-v-439bb2a8],.theme-mode-read pre[class*=language-][data-v-439bb2a8]{background:#2d2d2d}.theme-mode-read :not(pre)>code[class*=language-][data-v-439bb2a8]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-read .token.block-comment[data-v-439bb2a8],.theme-mode-read .token.cdata[data-v-439bb2a8],.theme-mode-read .token.comment[data-v-439bb2a8],.theme-mode-read .token.doctype[data-v-439bb2a8],.theme-mode-read .token.prolog[data-v-439bb2a8]{color:#999}.theme-mode-read .token.punctuation[data-v-439bb2a8]{color:#ccc}.theme-mode-read .token.attr-name[data-v-439bb2a8],.theme-mode-read .token.deleted[data-v-439bb2a8],.theme-mode-read .token.namespace[data-v-439bb2a8],.theme-mode-read .token.tag[data-v-439bb2a8]{color:#e2777a}.theme-mode-read .token.function-name[data-v-439bb2a8]{color:#6196cc}.theme-mode-read .token.boolean[data-v-439bb2a8],.theme-mode-read .token.function[data-v-439bb2a8],.theme-mode-read .token.number[data-v-439bb2a8]{color:#f08d49}.theme-mode-read .token.class-name[data-v-439bb2a8],.theme-mode-read .token.constant[data-v-439bb2a8],.theme-mode-read .token.property[data-v-439bb2a8],.theme-mode-read .token.symbol[data-v-439bb2a8]{color:#f8c555}.theme-mode-read .token.atrule[data-v-439bb2a8],.theme-mode-read .token.builtin[data-v-439bb2a8],.theme-mode-read .token.important[data-v-439bb2a8],.theme-mode-read .token.keyword[data-v-439bb2a8],.theme-mode-read .token.selector[data-v-439bb2a8]{color:#cc99cd}.theme-mode-read .token.attr-value[data-v-439bb2a8],.theme-mode-read .token.char[data-v-439bb2a8],.theme-mode-read .token.regex[data-v-439bb2a8],.theme-mode-read .token.string[data-v-439bb2a8],.theme-mode-read .token.variable[data-v-439bb2a8]{color:#7ec699}.theme-mode-read .token.entity[data-v-439bb2a8],.theme-mode-read .token.operator[data-v-439bb2a8],.theme-mode-read .token.url[data-v-439bb2a8]{color:#67cdcc}.theme-mode-read .language-css .token.string[data-v-439bb2a8],.theme-mode-read .style .token.string[data-v-439bb2a8],.theme-mode-read .token.entity[data-v-439bb2a8],.theme-mode-read .token.operator[data-v-439bb2a8],.theme-mode-read .token.url[data-v-439bb2a8]{background:none}.theme-mode-read .token.bold[data-v-439bb2a8],.theme-mode-read .token.important[data-v-439bb2a8]{font-weight:700}.theme-mode-read .token.italic[data-v-439bb2a8]{font-style:italic}.theme-mode-read .token.entity[data-v-439bb2a8]{cursor:help}.theme-mode-read .token.inserted[data-v-439bb2a8]{color:green}.theme-vdoing-content[data-v-439bb2a8]{margin:3rem auto;padding:1.5rem}.theme-vdoing-content span[data-v-439bb2a8]{font-size:6rem;color:#11a8cd}.main-wrapper{margin:1.5rem auto 0;max-width:1100px;padding:0 .9rem;box-sizing:border-box;position:relative;display:flex}.main-wrapper .main-left{flex:1}.main-wrapper .main-left .theme-vdoing-content.card-box{padding:1rem 1.5rem;margin-bottom:.9rem}.main-wrapper .main-left .home-content{padding:1rem 1.5rem 0}.main-wrapper .main-right>*{width:245px;box-sizing:border-box}@media (max-width:900px){.main-wrapper .main-right>*{width:235px}}.main-wrapper .main-right .card-box{margin:0 0 .8rem .8rem;padding-top:.95rem;padding-bottom:.95rem}@media (max-width:719px){.main-wrapper{margin:.9rem 0;padding:0;display:block}.main-wrapper .main-left{width:100%}.main-wrapper .main-left .post-list{margin-bottom:3rem}.main-wrapper .main-left .post-list .post{border-radius:0}.main-wrapper .main-left .pagination{margin-bottom:3rem}.main-wrapper .main-right .blogger-wrapper{display:none}.main-wrapper .main-right .card-box{margin:0 0 .9rem;border-radius:0;width:100%}.theme-style-line .main-wrapper .main-right .card-box{margin:-1px 0 0}}.post-list{margin-bottom:3rem}.post-list .post{position:relative;padding:1rem 1.5rem;margin-bottom:.8rem;transition:all .3s}.post-list .post:last-child{border-bottom:none}.post-list .post.post-leave-active{display:none}.post-list .post.post-enter{opacity:0;transform:translateX(-20px)}.post-list .post:before{position:absolute;top:-1px;right:0;font-size:2.5rem;color:#ff5722;opacity:.85}.post-list .post .title-wrapper a{color:var(--textColor)}.post-list .post .title-wrapper a:hover{color:#11a8cd}.post-list .post .title-wrapper h2{margin:.5rem 0;font-size:1.4rem;border:none}.post-list .post .title-wrapper h2 .title-tag{height:1.2rem;line-height:1.2rem;border:1px solid #ff5722;color:#ff5722;font-size:.8rem;padding:0 .35rem;border-radius:.2rem;margin-left:0;transform:translateY(-.15rem);display:inline-block}.post-list .post .title-wrapper h2 a{display:block}@media (max-width:719px){.post-list .post .title-wrapper h2 a{font-weight:400}}.post-list .post .title-wrapper .article-info>a,.post-list .post .title-wrapper .article-info>span{opacity:.7;font-size:.8rem;margin-right:1rem;cursor:pointer}.post-list .post .title-wrapper .article-info>a:before,.post-list .post .title-wrapper .article-info>span:before{margin-right:.3rem}.post-list .post .title-wrapper .article-info>a a,.post-list .post .title-wrapper .article-info>span a{margin:0}.post-list .post .title-wrapper .article-info>a a:not(:first-child):before,.post-list .post .title-wrapper .article-info>span a:not(:first-child):before{content:"/"}.post-list .post .title-wrapper .article-info .tags a:not(:first-child):before{content:"、"}.post-list .post .excerpt-wrapper{border-top:1px solid var(--borderColor);margin:.5rem 0;overflow:hidden}.post-list .post .excerpt-wrapper .excerpt{margin-bottom:.3rem;font-size:.92rem}.post-list .post .excerpt-wrapper .excerpt h1,.post-list .post .excerpt-wrapper .excerpt h2,.post-list .post .excerpt-wrapper .excerpt h3{display:none}.post-list .post .excerpt-wrapper .excerpt img{max-height:280px;max-width:100%!important;margin:0 auto}.post-list .post .excerpt-wrapper .readmore{float:right;margin-right:1rem;line-height:1rem}.post-list .post .excerpt-wrapper .readmore:before{float:right;font-size:.8rem;margin:.1rem 0 0 .2rem}.theme-style-line .post-list{border:1px solid var(--borderColor);border-bottom:none;border-radius:5px;overflow:hidden}.theme-style-line .post-list .post{margin-bottom:0;border:none;border-bottom:1px solid var(--borderColor);border-radius:0}.article-list{padding:1rem 2rem}@media (max-width:959px){.article-list{padding:1rem 1.5rem}}.article-list.no-article-list{display:none}.article-list .article-title{border-bottom:1px solid var(--borderColor);font-size:1.3rem;padding:1rem}.article-list .article-title a{font-size:1.2rem;color:var(--textColor);opacity:.9}.article-list .article-title a:before{margin-right:.4rem;font-size:1.1rem}.article-list .article-wrapper{overflow:hidden}.article-list .article-wrapper dl{border-bottom:1px dotted var(--borderColor);float:left;display:flex;padding:8px 0;margin:0;height:45px;width:100%}.article-list .article-wrapper dl dd{font-size:1.1rem;color:#f17229;width:50px;text-align:center;margin:0;line-height:45px}.article-list .article-wrapper dl dt{flex:1;display:flex}.article-list .article-wrapper dl dt a{color:var(--textColor);flex:1;display:flex;height:45px;align-items:center;font-weight:400}.article-list .article-wrapper dl dt a div{overflow:hidden;white-space:normal;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.article-list .article-wrapper dl dt a div .title-tag{border:1px solid #ff5722;color:#ff5722;font-size:.8rem;padding:0 .35rem;border-radius:.2rem;margin-left:0;transform:translateY(-.05rem);display:inline-block}.article-list .article-wrapper dl dt a:hover{text-decoration:underline}.article-list .article-wrapper dl dt a.more{color:#11a8cd}.article-list .article-wrapper dl dt .date{width:50px;margin-right:15px;color:#999;text-align:right;font-size:.9rem;line-height:45px}.pagination{position:relative;height:60px;text-align:center}@media (max-width:720px){.pagination{margin-left:1px;margin-right:1px}}.pagination span{line-height:1rem;opacity:.9;cursor:pointer}.pagination span:hover{color:#11a8cd}.pagination span.ellipsis{opacity:.5}.pagination span.ellipsis:before{content:"...";font-size:1.2rem}@media (any-hover:hover){.pagination span.ellipsis.ell-two:hover:before{content:"«"}.pagination span.ellipsis.ell-four:hover:before{content:"»"}}.pagination>span{position:absolute;top:0;padding:1rem 1.2rem;font-size:.95rem}.pagination>span:before{font-size:.4rem}.pagination>span.disabled{color:hsla(0,0%,49%,.5)}.pagination>span.prev{left:0}.pagination>span.prev:before{margin-right:.3rem}.pagination>span.next{right:0}.pagination>span.next:before{float:right;margin-left:.3rem}.pagination>span p{display:inline;line-height:.95rem}.pagination .pagination-list span{display:inline-block;width:2.5rem;height:2.5rem;line-height:2.5rem;margin:.3rem}.pagination .pagination-list span.active{background:#11a8cd;color:var(--mainBg)}@media (max-width:800px){.pagination>span{padding:1rem 1.5rem}.pagination>span p{display:none}}@media (max-width:719px){.pagination>span{padding:.9rem 1.5rem}.pagination .pagination-list span{width:2.3rem;height:2.3rem;line-height:2.3rem;margin:.25rem}}@media (max-width:390px){.pagination>span{padding:.8rem 1.3rem}.pagination .pagination-list span{width:2rem;height:2rem;line-height:2rem;margin:.3rem .1rem .1rem}}.blogger-wrapper{height:auto;display:inline-table;padding-top:0!important;overflow:hidden}.blogger-wrapper .avatar{width:100%;overflow:hidden}.blogger-wrapper .avatar img{width:100%;height:100%}.blogger-wrapper .icons{border-top:none;height:35px;line-height:35px}.blogger-wrapper .icons a{font-size:20px;width:33%;color:var(--textColor);display:block;float:left;text-align:center;opacity:.8}.blogger-wrapper .icons a:hover{color:#11a8cd}.blogger-wrapper .blogger{padding:.3rem .95rem 0}.blogger-wrapper .blogger .name{font-size:1.3rem;display:block;margin-bottom:6px}.blogger-wrapper .blogger .slogan{color:var(--textColor)}.categories-wrapper .title{color:var(--textColor);opacity:.9;font-size:1.2rem;padding:0 .95rem}.categories-wrapper .title:before{margin-right:.3rem}.categories-wrapper .categories{margin-top:.6rem}.categories-wrapper .categories a{display:block;padding:8px 2.4rem 7px .95rem;color:var(--textColor);opacity:.8;font-size:.95rem;line-height:.95rem;position:relative;transition:all .2s;border-left:2px solid transparent;margin-top:-1px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}@media (max-width:719px){.categories-wrapper .categories a{font-weight:400}}.categories-wrapper .categories a:not(.active):hover{color:#11a8cd;background:#f8f8f8;border-color:#11a8cd}.categories-wrapper .categories a:not(.active):hover span{opacity:.8}.categories-wrapper .categories a span{background-color:var(--textColor);color:var(--mainBg);border-radius:8px;padding:0 .13rem;min-width:1rem;height:1rem;line-height:1rem;font-size:12px;text-align:center;opacity:.6;transition:opacity .3s;position:absolute;right:.95rem;top:8px}.categories-wrapper .categories a.active{background:#11a8cd;color:var(--mainBg);padding-left:.8rem;border-radius:1px;border-color:transparent}.theme-mode-dark .categories-wrapper .categories a:not(.active):hover,.theme-mode-read .categories-wrapper .categories a:not(.active):hover{background:var(--customBlockBg)}.tags-wrapper{padding:0 .95rem}.tags-wrapper .title{color:var(--textColor);opacity:.9;font-size:1.2rem}.tags-wrapper .title:before{margin-right:.3rem}.tags-wrapper .tags{text-align:justify;padding:.8rem .5rem .5rem;margin:0 -.5rem -.5rem}.tags-wrapper .tags a{opacity:.8;display:inline-block;padding:.2rem .4rem;transition:all .4s;background-color:var(--textColor);color:var(--mainBg);border-radius:3px;margin:0 .3rem .5rem 0;min-width:2rem;height:1rem;line-height:1rem;font-size:.8rem;text-align:center}@media (max-width:719px){.tags-wrapper .tags a{font-weight:400}}.tags-wrapper .tags a:hover{opacity:1;transform:scale(1.1)}.tags-wrapper .tags a.active{box-shadow:0 5px 10px -5px var(--randomColor,rgba(0,0,0,.15));transform:scale(1.22);opacity:1}.tags-wrapper .tags a.active:hover{text-decoration:none}.theme-mode-light[data-v-7d2bb426]{--bodyBg:#f4f4f4;--customBlockBg:#f1f1f1;--textColor:#00323c;--borderColor:rgba(0,0,0,0.12)}.theme-mode-dark[data-v-7d2bb426]{--bodyBg:#27272b;--customBlockBg:#27272b;--textColor:#9b9baa;--borderColor:#30363d}.theme-mode-read[data-v-7d2bb426]{--bodyBg:#ececcc;--customBlockBg:#ececcc;--textColor:#704214;--textLightenColor:#963}.theme-style-line.theme-mode-light[data-v-7d2bb426]{--bodyBg:#fff}.theme-style-line.theme-mode-dark[data-v-7d2bb426]{--bodyBg:#1e1e22}.theme-style-line.theme-mode-read[data-v-7d2bb426]{--bodyBg:#f5f5d5}.theme-mode-light[data-v-7d2bb426]{--bodyBg:#fff;--mainBg:#fff;--sidebarBg:hsla(0,0%,100%,0.8);--blurBg:hsla(0,0%,100%,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#f6f6f6;--codeColor:#525252}.theme-mode-light code[class*=language-][data-v-7d2bb426],.theme-mode-light pre[class*=language-][data-v-7d2bb426]{color:#000;background:none;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-light code[class*=language-][data-v-7d2bb426]::-moz-selection,.theme-mode-light code[class*=language-][data-v-7d2bb426] ::-moz-selection,.theme-mode-light pre[class*=language-][data-v-7d2bb426]::-moz-selection,.theme-mode-light pre[class*=language-][data-v-7d2bb426] ::-moz-selection{text-shadow:none;background:#b3d4fc}.theme-mode-light code[class*=language-][data-v-7d2bb426]::selection,.theme-mode-light code[class*=language-][data-v-7d2bb426] ::selection,.theme-mode-light pre[class*=language-][data-v-7d2bb426]::selection,.theme-mode-light pre[class*=language-][data-v-7d2bb426] ::selection{text-shadow:none;background:#b3d4fc}@media print{.theme-mode-light code[class*=language-][data-v-7d2bb426],.theme-mode-light pre[class*=language-][data-v-7d2bb426]{text-shadow:none}}.theme-mode-light pre[class*=language-][data-v-7d2bb426]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-light :not(pre)>code[class*=language-][data-v-7d2bb426],.theme-mode-light pre[class*=language-][data-v-7d2bb426]{background:#f5f2f0}.theme-mode-light :not(pre)>code[class*=language-][data-v-7d2bb426]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-light .token.cdata[data-v-7d2bb426],.theme-mode-light .token.comment[data-v-7d2bb426],.theme-mode-light .token.doctype[data-v-7d2bb426],.theme-mode-light .token.prolog[data-v-7d2bb426]{color:#708090}.theme-mode-light .token.punctuation[data-v-7d2bb426]{color:#999}.theme-mode-light .namespace[data-v-7d2bb426]{opacity:.7}.theme-mode-light .token.boolean[data-v-7d2bb426],.theme-mode-light .token.constant[data-v-7d2bb426],.theme-mode-light .token.deleted[data-v-7d2bb426],.theme-mode-light .token.number[data-v-7d2bb426],.theme-mode-light .token.property[data-v-7d2bb426],.theme-mode-light .token.symbol[data-v-7d2bb426],.theme-mode-light .token.tag[data-v-7d2bb426]{color:#905}.theme-mode-light .token.attr-name[data-v-7d2bb426],.theme-mode-light .token.builtin[data-v-7d2bb426],.theme-mode-light .token.char[data-v-7d2bb426],.theme-mode-light .token.inserted[data-v-7d2bb426],.theme-mode-light .token.selector[data-v-7d2bb426],.theme-mode-light .token.string[data-v-7d2bb426]{color:#690}.theme-mode-light .language-css .token.string[data-v-7d2bb426],.theme-mode-light .style .token.string[data-v-7d2bb426],.theme-mode-light .token.entity[data-v-7d2bb426],.theme-mode-light .token.operator[data-v-7d2bb426],.theme-mode-light .token.url[data-v-7d2bb426]{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.theme-mode-light .token.atrule[data-v-7d2bb426],.theme-mode-light .token.attr-value[data-v-7d2bb426],.theme-mode-light .token.keyword[data-v-7d2bb426]{color:#07a}.theme-mode-light .token.class-name[data-v-7d2bb426],.theme-mode-light .token.function[data-v-7d2bb426]{color:#dd4a68}.theme-mode-light .token.important[data-v-7d2bb426],.theme-mode-light .token.regex[data-v-7d2bb426],.theme-mode-light .token.variable[data-v-7d2bb426]{color:#e90}.theme-mode-light .token.bold[data-v-7d2bb426],.theme-mode-light .token.important[data-v-7d2bb426]{font-weight:700}.theme-mode-light .token.italic[data-v-7d2bb426]{font-style:italic}.theme-mode-light .token.entity[data-v-7d2bb426]{cursor:help}.theme-mode-light div[class*=language-] .highlight-lines .highlighted[data-v-7d2bb426],.theme-mode-light div[class*=language-].line-numbers-mode .highlight-lines .highlighted[data-v-7d2bb426]:before{background-color:hsla(0,0%,78.4%,.4)}.theme-mode-dark[data-v-7d2bb426]{--bodyBg:#1e1e22;--mainBg:#1e1e22;--sidebarBg:rgba(30,30,34,0.8);--blurBg:rgba(30,30,34,0.8);--textColor:#8c8c96;--textLightenColor:#0085ad;--borderColor:#2c2c3a;--codeBg:#252526;--codeColor:#fff}.theme-mode-dark code[class*=language-][data-v-7d2bb426],.theme-mode-dark pre[class*=language-][data-v-7d2bb426]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-dark pre[class*=language-][data-v-7d2bb426]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-dark :not(pre)>code[class*=language-][data-v-7d2bb426],.theme-mode-dark pre[class*=language-][data-v-7d2bb426]{background:#2d2d2d}.theme-mode-dark :not(pre)>code[class*=language-][data-v-7d2bb426]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-dark .token.block-comment[data-v-7d2bb426],.theme-mode-dark .token.cdata[data-v-7d2bb426],.theme-mode-dark .token.comment[data-v-7d2bb426],.theme-mode-dark .token.doctype[data-v-7d2bb426],.theme-mode-dark .token.prolog[data-v-7d2bb426]{color:#999}.theme-mode-dark .token.punctuation[data-v-7d2bb426]{color:#ccc}.theme-mode-dark .token.attr-name[data-v-7d2bb426],.theme-mode-dark .token.deleted[data-v-7d2bb426],.theme-mode-dark .token.namespace[data-v-7d2bb426],.theme-mode-dark .token.tag[data-v-7d2bb426]{color:#e2777a}.theme-mode-dark .token.function-name[data-v-7d2bb426]{color:#6196cc}.theme-mode-dark .token.boolean[data-v-7d2bb426],.theme-mode-dark .token.function[data-v-7d2bb426],.theme-mode-dark .token.number[data-v-7d2bb426]{color:#f08d49}.theme-mode-dark .token.class-name[data-v-7d2bb426],.theme-mode-dark .token.constant[data-v-7d2bb426],.theme-mode-dark .token.property[data-v-7d2bb426],.theme-mode-dark .token.symbol[data-v-7d2bb426]{color:#f8c555}.theme-mode-dark .token.atrule[data-v-7d2bb426],.theme-mode-dark .token.builtin[data-v-7d2bb426],.theme-mode-dark .token.important[data-v-7d2bb426],.theme-mode-dark .token.keyword[data-v-7d2bb426],.theme-mode-dark .token.selector[data-v-7d2bb426]{color:#cc99cd}.theme-mode-dark .token.attr-value[data-v-7d2bb426],.theme-mode-dark .token.char[data-v-7d2bb426],.theme-mode-dark .token.regex[data-v-7d2bb426],.theme-mode-dark .token.string[data-v-7d2bb426],.theme-mode-dark .token.variable[data-v-7d2bb426]{color:#7ec699}.theme-mode-dark .token.entity[data-v-7d2bb426],.theme-mode-dark .token.operator[data-v-7d2bb426],.theme-mode-dark .token.url[data-v-7d2bb426]{color:#67cdcc}.theme-mode-dark .language-css .token.string[data-v-7d2bb426],.theme-mode-dark .style .token.string[data-v-7d2bb426],.theme-mode-dark .token.entity[data-v-7d2bb426],.theme-mode-dark .token.operator[data-v-7d2bb426],.theme-mode-dark .token.url[data-v-7d2bb426]{background:none}.theme-mode-dark .token.bold[data-v-7d2bb426],.theme-mode-dark .token.important[data-v-7d2bb426]{font-weight:700}.theme-mode-dark .token.italic[data-v-7d2bb426]{font-style:italic}.theme-mode-dark .token.entity[data-v-7d2bb426]{cursor:help}.theme-mode-dark .token.inserted[data-v-7d2bb426]{color:green}.theme-mode-read[data-v-7d2bb426]{--bodyBg:#f5f5d5;--mainBg:#f5f5d5;--sidebarBg:rgba(245,245,213,0.8);--blurBg:rgba(245,245,213,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#282c34;--codeColor:#fff}.theme-mode-read code[class*=language-][data-v-7d2bb426],.theme-mode-read pre[class*=language-][data-v-7d2bb426]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-read pre[class*=language-][data-v-7d2bb426]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-read :not(pre)>code[class*=language-][data-v-7d2bb426],.theme-mode-read pre[class*=language-][data-v-7d2bb426]{background:#2d2d2d}.theme-mode-read :not(pre)>code[class*=language-][data-v-7d2bb426]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-read .token.block-comment[data-v-7d2bb426],.theme-mode-read .token.cdata[data-v-7d2bb426],.theme-mode-read .token.comment[data-v-7d2bb426],.theme-mode-read .token.doctype[data-v-7d2bb426],.theme-mode-read .token.prolog[data-v-7d2bb426]{color:#999}.theme-mode-read .token.punctuation[data-v-7d2bb426]{color:#ccc}.theme-mode-read .token.attr-name[data-v-7d2bb426],.theme-mode-read .token.deleted[data-v-7d2bb426],.theme-mode-read .token.namespace[data-v-7d2bb426],.theme-mode-read .token.tag[data-v-7d2bb426]{color:#e2777a}.theme-mode-read .token.function-name[data-v-7d2bb426]{color:#6196cc}.theme-mode-read .token.boolean[data-v-7d2bb426],.theme-mode-read .token.function[data-v-7d2bb426],.theme-mode-read .token.number[data-v-7d2bb426]{color:#f08d49}.theme-mode-read .token.class-name[data-v-7d2bb426],.theme-mode-read .token.constant[data-v-7d2bb426],.theme-mode-read .token.property[data-v-7d2bb426],.theme-mode-read .token.symbol[data-v-7d2bb426]{color:#f8c555}.theme-mode-read .token.atrule[data-v-7d2bb426],.theme-mode-read .token.builtin[data-v-7d2bb426],.theme-mode-read .token.important[data-v-7d2bb426],.theme-mode-read .token.keyword[data-v-7d2bb426],.theme-mode-read .token.selector[data-v-7d2bb426]{color:#cc99cd}.theme-mode-read .token.attr-value[data-v-7d2bb426],.theme-mode-read .token.char[data-v-7d2bb426],.theme-mode-read .token.regex[data-v-7d2bb426],.theme-mode-read .token.string[data-v-7d2bb426],.theme-mode-read .token.variable[data-v-7d2bb426]{color:#7ec699}.theme-mode-read .token.entity[data-v-7d2bb426],.theme-mode-read .token.operator[data-v-7d2bb426],.theme-mode-read .token.url[data-v-7d2bb426]{color:#67cdcc}.theme-mode-read .language-css .token.string[data-v-7d2bb426],.theme-mode-read .style .token.string[data-v-7d2bb426],.theme-mode-read .token.entity[data-v-7d2bb426],.theme-mode-read .token.operator[data-v-7d2bb426],.theme-mode-read .token.url[data-v-7d2bb426]{background:none}.theme-mode-read .token.bold[data-v-7d2bb426],.theme-mode-read .token.important[data-v-7d2bb426]{font-weight:700}.theme-mode-read .token.italic[data-v-7d2bb426]{font-style:italic}.theme-mode-read .token.entity[data-v-7d2bb426]{cursor:help}.theme-mode-read .token.inserted[data-v-7d2bb426]{color:green}.home-wrapper .banner[data-v-7d2bb426]{width:100%;min-height:450px;margin-top:3.6rem;color:#fff;position:relative;overflow:hidden}.home-wrapper .banner .banner-conent[data-v-7d2bb426]{max-width:1100px;margin:0 auto;position:relative;z-index:1;overflow:hidden}.home-wrapper .banner .banner-conent .hero[data-v-7d2bb426]{text-align:center;margin-top:3rem}.home-wrapper .banner .banner-conent .hero img[data-v-7d2bb426]{max-width:100%;max-height:240px;display:block;margin:2rem auto 1.5rem}.home-wrapper .banner .banner-conent .hero h1[data-v-7d2bb426]{margin:0;font-size:3.2rem}.home-wrapper .banner .banner-conent .hero .action[data-v-7d2bb426],.home-wrapper .banner .banner-conent .hero .description[data-v-7d2bb426]{margin:1.5rem auto}.home-wrapper .banner .banner-conent .hero .description[data-v-7d2bb426]{max-width:40rem;font-size:1.1rem;line-height:1.3;opacity:.9}.home-wrapper .banner .banner-conent .hero .action-button[data-v-7d2bb426]{display:inline-block;font-size:1.2rem;background-color:#11a8cd;padding:.8rem 1.6rem;border-radius:4px;transition:background-color .1s ease;box-sizing:border-box;border-bottom:1px solid #0f97b9;color:#fff}.home-wrapper .banner .banner-conent .hero .action-button[data-v-7d2bb426]:hover{background-color:#13bee8}.home-wrapper .banner .banner-conent .features[data-v-7d2bb426]{padding:2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home-wrapper .banner .banner-conent .feature[data-v-7d2bb426]{flex-grow:1;flex-basis:30%;max-width:30%;text-align:center}.home-wrapper .banner .banner-conent .feature a[data-v-7d2bb426]{color:inherit}.home-wrapper .banner .banner-conent .feature a .feature-img[data-v-7d2bb426]{width:10rem;height:10rem;animation:heart-7d2bb426 1.2s ease-in-out 0s infinite alternate;animation-play-state:paused}.home-wrapper .banner .banner-conent .feature a h2[data-v-7d2bb426]{font-weight:500;font-size:1.3rem;border-bottom:none;padding-bottom:0}.home-wrapper .banner .banner-conent .feature a p[data-v-7d2bb426]{opacity:.8;padding:0 .8rem}.home-wrapper .banner .banner-conent .feature:hover .feature-img[data-v-7d2bb426]{animation-play-state:running}.home-wrapper .banner .banner-conent .feature:hover h2[data-v-7d2bb426],.home-wrapper .banner .banner-conent .feature:hover p[data-v-7d2bb426]{color:#11a8cd}.home-wrapper .banner .slide-banner[data-v-7d2bb426]{margin-top:2rem}.home-wrapper .banner .slide-banner .banner-wrapper[data-v-7d2bb426]{position:relative}.home-wrapper .banner .slide-banner .slide-banner-scroll[data-v-7d2bb426]{min-height:1px;overflow:hidden}.home-wrapper .banner .slide-banner .slide-banner-wrapper[data-v-7d2bb426]{height:300px}.home-wrapper .banner .slide-banner .slide-banner-wrapper .slide-item[data-v-7d2bb426]{display:inline-block;height:300px;width:100%;text-align:center}.home-wrapper .banner .slide-banner .slide-banner-wrapper .slide-item a[data-v-7d2bb426]{color:inherit}.home-wrapper .banner .slide-banner .slide-banner-wrapper .slide-item a .feature-img[data-v-7d2bb426]{width:10rem;height:10rem}.home-wrapper .banner .slide-banner .slide-banner-wrapper .slide-item a h2[data-v-7d2bb426]{font-size:1.1rem;font-weight:500;border-bottom:none;padding-bottom:0}.home-wrapper .banner .slide-banner .slide-banner-wrapper .slide-item a p[data-v-7d2bb426]{opacity:.8;padding:0 .8rem}.home-wrapper .banner .slide-banner .docs-wrapper[data-v-7d2bb426]{position:absolute;bottom:25px;left:50%;transform:translateX(-50%)}.home-wrapper .banner .slide-banner .docs-wrapper .doc[data-v-7d2bb426]{display:inline-block;margin:0 4px;width:8px;height:8px;border-radius:50%;background:var(--textColor);opacity:.9}.home-wrapper .banner .slide-banner .docs-wrapper .doc.active[data-v-7d2bb426]{opacity:.5}.home-wrapper .banner.hide-banner[data-v-7d2bb426]{display:none}.home-wrapper .banner.hide-banner+.main-wrapper[data-v-7d2bb426]{margin-top:4.5rem}.home-wrapper .main-wrapper[data-v-7d2bb426]{margin-top:2rem}.home-wrapper .main-wrapper .main-left .card-box[data-v-7d2bb426]{margin-bottom:2rem}.home-wrapper .main-wrapper .main-left .pagination[data-v-7d2bb426]{margin-bottom:3rem}.home-wrapper .main-wrapper .main-left .theme-vdoing-content[data-v-7d2bb426]{padding:0 2rem;overflow:hidden;border:none}.home-wrapper .main-wrapper .main-left .theme-vdoing-content[data-v-7d2bb426]>:first-child{padding-top:2rem}.home-wrapper .main-wrapper .main-left .theme-vdoing-content[data-v-7d2bb426]>:last-child{padding-bottom:2rem}.home-wrapper .main-wrapper .main-right .custom-html-box[data-v-7d2bb426]{padding:0;overflow:hidden}@media (max-width:1025px){.home-wrapper .banner .banner-conent .hero h1[data-v-7d2bb426]{font-size:2.5rem}.home-wrapper .banner .banner-conent .hero .description[data-v-7d2bb426]{font-size:1rem}.home-wrapper .banner .banner-conent .feature a h2[data-v-7d2bb426]{font-size:1.1rem}.home-wrapper .banner .banner-conent .feature a .feature-img[data-v-7d2bb426]{width:9rem;height:9rem}}@media (max-width:719px){.home-wrapper .banner .banner-conent .features[data-v-7d2bb426]{display:none!important}}@media (max-width:419px){.home-wrapper .banner-conent[data-v-7d2bb426]{padding-left:1.5rem;padding-right:1.5rem}.home-wrapper .banner-conent .hero img[data-v-7d2bb426]{max-height:210px;margin:2rem auto 1.2rem}.home-wrapper .banner-conent .hero h1[data-v-7d2bb426]{font-size:2rem}.home-wrapper .banner-conent .hero .action[data-v-7d2bb426],.home-wrapper .banner-conent .hero .description[data-v-7d2bb426],.home-wrapper .banner-conent .hero h1[data-v-7d2bb426]{margin:1.2rem auto}.home-wrapper .banner-conent .hero .description[data-v-7d2bb426]{font-size:1.2rem}.home-wrapper .banner-conent .hero .action-button[data-v-7d2bb426]{font-size:1rem;padding:.6rem 1.2rem}.home-wrapper .banner-conent .feature h2[data-v-7d2bb426]{font-size:1.25rem}}@media (max-width:719px){.theme-style-line .main-wrapper[data-v-7d2bb426]{margin-top:-1px}}@keyframes heart-7d2bb426{0%{transform:translate(0)}to{transform:translateY(8px)}}.search-box{display:inline-block;position:relative;margin-right:1rem}.search-box input{cursor:text;width:10rem;height:2rem;color:#4e6e8e;display:inline-block;border:1px solid #cfd4db;border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all .2s ease;background:#fff url(/algorithm-tutorial/assets/img/search.237d6f6a.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:#11a8cd}.search-box .suggestions{background:#fff;min-width:500px;max-width:700px;position:absolute;top:2rem;border:1px solid #cfd4db;border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestions.align-right{right:0}.search-box .suggestion{line-height:1.4;border-radius:4px;cursor:pointer;width:100%}.search-box .suggestion a{display:block;white-space:normal;color:#415b75;width:100%}.search-box .suggestion a .parent-page-title{color:#fff;font-weight:600;background-color:#11a8cd;padding:5px}.search-box .suggestion a .suggestion-row{border-collapse:collapse;width:100%;display:table}.search-box .suggestion a .suggestion-row .page-title{width:35%;background:#f5f5f5;border:1px solid #eaecef;border-left:none;display:table-cell;text-align:right;padding:5px;font-weight:600}.search-box .suggestion a .suggestion-row .suggestion-content{font-weight:400;border:1px solid #eaecef;border-right:none;width:65%;display:table-cell;padding:5px}.search-box .suggestion a .suggestion-row .suggestion-content .highlight{text-decoration:underline}.search-box .suggestion a .suggestion-row .suggestion-content .header{font-weight:600}.search-box .suggestion.focused{background-color:#f3f4f5}@media (max-width:959px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (-ms-high-contrast:none){.search-box input{height:2rem}}@media (max-width:959px) and (min-width:719px){.search-box .suggestions{left:0}}@media (max-width:719px){.search-box{margin-right:0}.search-box input{left:1rem}.search-box .suggestions{right:0}}@media (max-width:419px){.search-box .suggestions{width:calc(100vw - 4rem)}.search-box input:focus{width:8rem}}.sidebar-button{cursor:pointer;display:none;width:1.25rem;height:1.25rem;position:absolute;padding:.6rem;top:.6rem;left:1rem}@media (max-width:719px){.sidebar-button{display:block}}.sidebar-button .icon{display:block;width:1.25rem;height:1.25rem}@media (min-width:720px){.sidebar-button{width:40px;height:40px;display:inline-block;position:fixed;left:0;top:4.6rem;text-align:center;line-height:44px;margin:5px 8px;color:#888;border-radius:50%;padding:0;transition:all .2s}.sidebar-button:hover{background:#11a8cd;color:#fff;box-shadow:0 0 6px #11a8cd}.sidebar-button .icon{display:inline;width:1rem;height:1rem}}.dropdown-enter,.dropdown-leave-to{height:0!important}.dropdown-wrapper{cursor:pointer}.dropdown-wrapper .dropdown-title{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:var(--textColor)}.dropdown-wrapper .dropdown-title:hover{border-color:transparent}.dropdown-wrapper .dropdown-title .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.dropdown-wrapper .nav-dropdown .dropdown-item{color:inherit;line-height:1.7rem}.dropdown-wrapper .nav-dropdown .dropdown-item h4{margin:.45rem 0 0;border-top:1px solid var(--borderColor);padding:.45rem 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper{padding:0;list-style:none}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem-wrapper .dropdown-subitem{font-size:.9em}.dropdown-wrapper .nav-dropdown .dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active,.dropdown-wrapper .nav-dropdown .dropdown-item a:hover{color:#11a8cd}.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid #11a8cd;border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.dropdown-wrapper .nav-dropdown .dropdown-item:first-child h4{margin-top:0;padding-top:0;border-top:0}@media (max-width:719px){.dropdown-wrapper.open .dropdown-title{margin-bottom:.5rem}.dropdown-wrapper .dropdown-title{font-weight:600;font-size:inherit}.dropdown-wrapper .dropdown-title:hover{color:#11a8cd}.dropdown-wrapper .dropdown-title .link-title{display:none}.dropdown-wrapper .dropdown-title .title{display:inline-block!important}.dropdown-wrapper .nav-dropdown{transition:height .1s ease-out;overflow:hidden}.dropdown-wrapper .nav-dropdown .dropdown-item h4{border-top:0;margin-top:0;padding-top:0}.dropdown-wrapper .nav-dropdown .dropdown-item>a,.dropdown-wrapper .nav-dropdown .dropdown-item h4{font-size:15px;line-height:2rem}.dropdown-wrapper .nav-dropdown .dropdown-item .dropdown-subitem{font-size:14px;padding-left:1rem}}@media (min-width:719px){.dropdown-wrapper{height:1.8rem}.dropdown-wrapper.open .nav-dropdown,.dropdown-wrapper:hover .nav-dropdown{display:block!important}.dropdown-wrapper.open:blur{display:none}.dropdown-wrapper .dropdown-title .arrow{border-left:4px solid transparent;border-right:4px solid transparent;border-top:6px solid #ccc;border-bottom:0}.dropdown-wrapper .nav-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:var(--mainBg);padding:.6rem 0;border-bottom-color:var(--borderColor);border:1px solid var(--borderColor);text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}.nav-item .dropdown-title a.router-link-active,.nav-item .dropdown-title a:hover{margin-bottom:-2px;border-bottom:2px solid #13b9e2}}.nav-links{display:inline-block}.nav-links a{line-height:1.4rem;color:inherit}.nav-links a.router-link-active,.nav-links a:hover{color:#11a8cd}.nav-links .nav-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:2rem}.nav-links .nav-item:first-child{margin-left:0}.nav-links .repo-link{margin-left:1.5rem}@media (max-width:959px){.nav-links .nav-item{margin-left:1.2rem}}@media (max-width:719px){.nav-links .nav-item,.nav-links .repo-link{margin-left:0}}@media (min-width:719px){.nav-links a.router-link-active,.nav-links a:hover{color:var(--textColor)}.nav-item>a:not(.external).router-link-active,.nav-item>a:not(.external):hover{margin-bottom:-2px;border-bottom:2px solid #13b9e2}}.navbar{padding:.7rem 1.5rem;line-height:2.2rem;transition:transform .3s}.navbar a,.navbar img,.navbar span{display:inline-block}.navbar .logo{height:2.2rem;min-width:2.2rem;margin-right:.8rem;vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:var(--textColor);position:relative}.navbar .links{padding-left:1.5rem;box-sizing:border-box;white-space:nowrap;font-size:.9rem;position:absolute;right:1.5rem;top:.7rem;display:flex}.navbar .links .search-box{flex:0 0 auto;vertical-align:top}.hide-navbar .navbar{transform:translateY(-100%)}@media (max-width:959px){.navbar .site-name{display:none}}@media (max-width:719px){.navbar{padding-left:4rem}.navbar .can-hide{display:none}.navbar .links{padding-left:1.5rem}.navbar .site-name{width:calc(100vw - 9.4rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}}.page-edit{max-width:860px;padding-top:1rem;padding-bottom:1rem;overflow:auto}.page-edit .edit-link{display:inline-block;float:left;margin:0 2rem .5rem 0}.page-edit .edit-link a{margin-right:.25rem}.page-edit .tags{float:left}.page-edit .tags a{margin:0 .8rem .5rem 0;display:inline-block;color:var(--textLightenColor);padding:.2rem .7rem;font-size:.9em;background-color:hsla(0,0%,50.2%,.08);border-radius:3px;opacity:.8}.page-edit .last-updated{float:right;font-size:.9em}.page-edit .last-updated .prefix{font-weight:500;color:var(--textColor);opacity:.8}.page-edit .last-updated .time{font-weight:400;color:#aaa}@media (max-width:719px){.page-edit .edit-link,.page-edit .tags{margin-bottom:.5rem}.page-edit .last-updated{width:100%;font-size:.8em;text-align:left}}.page-nav{max-width:860px;padding-top:1rem;padding-bottom:0}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid var(--borderColor);padding-top:1rem;overflow:auto}.page-nav .next{float:right}.page-nav-centre-wrap .page-nav-centre{position:fixed;top:50%;width:80px;height:70px;margin-top:-35px;outline:0;transition:all .2s;border-radius:3px;opacity:.55;z-index:99}@media (max-width:1340px){.page-nav-centre-wrap .page-nav-centre{width:50px}}@media (max-width:960px){.page-nav-centre-wrap .page-nav-centre{display:none}}.page-nav-centre-wrap .page-nav-centre:hover{background:hsla(0,0%,60%,.15);opacity:1}.page-nav-centre-wrap .page-nav-centre:hover .tooltip{display:block}.page-nav-centre-wrap .page-nav-centre:before{content:"";display:block;width:10px;height:10px;border-top:2px solid #999;border-right:2px solid #999;position:absolute;top:0;right:0;bottom:0;left:0;margin:auto}.page-nav-centre-wrap .page-nav-centre .tooltip{display:none;background:rgba(0,0,0,.5);color:#fff;padding:4px 8px;font-size:13px;border-radius:3px;position:fixed;max-width:200px;z-index:99}.page-nav-centre-wrap .page-nav-centre-prev{left:0}.page-nav-centre-wrap .page-nav-centre-prev:before{transform:rotate(-135deg)}.page-nav-centre-wrap .page-nav-centre-next{right:0}.page-nav-centre-wrap .page-nav-centre-next:before{transform:rotate(45deg)}.sidebar-open .page-nav-centre-wrap .page-nav-centre-prev{left:18rem}.no-sidebar .page-nav-centre-wrap .page-nav-centre-prev{left:0}.theme-mode-light[data-v-06225672]{--bodyBg:#f4f4f4;--customBlockBg:#f1f1f1;--textColor:#00323c;--borderColor:rgba(0,0,0,0.12)}.theme-mode-dark[data-v-06225672]{--bodyBg:#27272b;--customBlockBg:#27272b;--textColor:#9b9baa;--borderColor:#30363d}.theme-mode-read[data-v-06225672]{--bodyBg:#ececcc;--customBlockBg:#ececcc;--textColor:#704214;--textLightenColor:#963}.theme-style-line.theme-mode-light[data-v-06225672]{--bodyBg:#fff}.theme-style-line.theme-mode-dark[data-v-06225672]{--bodyBg:#1e1e22}.theme-style-line.theme-mode-read[data-v-06225672]{--bodyBg:#f5f5d5}.theme-mode-light[data-v-06225672]{--bodyBg:#fff;--mainBg:#fff;--sidebarBg:hsla(0,0%,100%,0.8);--blurBg:hsla(0,0%,100%,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#f6f6f6;--codeColor:#525252}.theme-mode-light code[class*=language-][data-v-06225672],.theme-mode-light pre[class*=language-][data-v-06225672]{color:#000;background:none;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-light code[class*=language-][data-v-06225672]::-moz-selection,.theme-mode-light code[class*=language-][data-v-06225672] ::-moz-selection,.theme-mode-light pre[class*=language-][data-v-06225672]::-moz-selection,.theme-mode-light pre[class*=language-][data-v-06225672] ::-moz-selection{text-shadow:none;background:#b3d4fc}.theme-mode-light code[class*=language-][data-v-06225672]::selection,.theme-mode-light code[class*=language-][data-v-06225672] ::selection,.theme-mode-light pre[class*=language-][data-v-06225672]::selection,.theme-mode-light pre[class*=language-][data-v-06225672] ::selection{text-shadow:none;background:#b3d4fc}@media print{.theme-mode-light code[class*=language-][data-v-06225672],.theme-mode-light pre[class*=language-][data-v-06225672]{text-shadow:none}}.theme-mode-light pre[class*=language-][data-v-06225672]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-light :not(pre)>code[class*=language-][data-v-06225672],.theme-mode-light pre[class*=language-][data-v-06225672]{background:#f5f2f0}.theme-mode-light :not(pre)>code[class*=language-][data-v-06225672]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-light .token.cdata[data-v-06225672],.theme-mode-light .token.comment[data-v-06225672],.theme-mode-light .token.doctype[data-v-06225672],.theme-mode-light .token.prolog[data-v-06225672]{color:#708090}.theme-mode-light .token.punctuation[data-v-06225672]{color:#999}.theme-mode-light .namespace[data-v-06225672]{opacity:.7}.theme-mode-light .token.boolean[data-v-06225672],.theme-mode-light .token.constant[data-v-06225672],.theme-mode-light .token.deleted[data-v-06225672],.theme-mode-light .token.number[data-v-06225672],.theme-mode-light .token.property[data-v-06225672],.theme-mode-light .token.symbol[data-v-06225672],.theme-mode-light .token.tag[data-v-06225672]{color:#905}.theme-mode-light .token.attr-name[data-v-06225672],.theme-mode-light .token.builtin[data-v-06225672],.theme-mode-light .token.char[data-v-06225672],.theme-mode-light .token.inserted[data-v-06225672],.theme-mode-light .token.selector[data-v-06225672],.theme-mode-light .token.string[data-v-06225672]{color:#690}.theme-mode-light .language-css .token.string[data-v-06225672],.theme-mode-light .style .token.string[data-v-06225672],.theme-mode-light .token.entity[data-v-06225672],.theme-mode-light .token.operator[data-v-06225672],.theme-mode-light .token.url[data-v-06225672]{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.theme-mode-light .token.atrule[data-v-06225672],.theme-mode-light .token.attr-value[data-v-06225672],.theme-mode-light .token.keyword[data-v-06225672]{color:#07a}.theme-mode-light .token.class-name[data-v-06225672],.theme-mode-light .token.function[data-v-06225672]{color:#dd4a68}.theme-mode-light .token.important[data-v-06225672],.theme-mode-light .token.regex[data-v-06225672],.theme-mode-light .token.variable[data-v-06225672]{color:#e90}.theme-mode-light .token.bold[data-v-06225672],.theme-mode-light .token.important[data-v-06225672]{font-weight:700}.theme-mode-light .token.italic[data-v-06225672]{font-style:italic}.theme-mode-light .token.entity[data-v-06225672]{cursor:help}.theme-mode-light div[class*=language-] .highlight-lines .highlighted[data-v-06225672],.theme-mode-light div[class*=language-].line-numbers-mode .highlight-lines .highlighted[data-v-06225672]:before{background-color:hsla(0,0%,78.4%,.4)}.theme-mode-dark[data-v-06225672]{--bodyBg:#1e1e22;--mainBg:#1e1e22;--sidebarBg:rgba(30,30,34,0.8);--blurBg:rgba(30,30,34,0.8);--textColor:#8c8c96;--textLightenColor:#0085ad;--borderColor:#2c2c3a;--codeBg:#252526;--codeColor:#fff}.theme-mode-dark code[class*=language-][data-v-06225672],.theme-mode-dark pre[class*=language-][data-v-06225672]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-dark pre[class*=language-][data-v-06225672]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-dark :not(pre)>code[class*=language-][data-v-06225672],.theme-mode-dark pre[class*=language-][data-v-06225672]{background:#2d2d2d}.theme-mode-dark :not(pre)>code[class*=language-][data-v-06225672]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-dark .token.block-comment[data-v-06225672],.theme-mode-dark .token.cdata[data-v-06225672],.theme-mode-dark .token.comment[data-v-06225672],.theme-mode-dark .token.doctype[data-v-06225672],.theme-mode-dark .token.prolog[data-v-06225672]{color:#999}.theme-mode-dark .token.punctuation[data-v-06225672]{color:#ccc}.theme-mode-dark .token.attr-name[data-v-06225672],.theme-mode-dark .token.deleted[data-v-06225672],.theme-mode-dark .token.namespace[data-v-06225672],.theme-mode-dark .token.tag[data-v-06225672]{color:#e2777a}.theme-mode-dark .token.function-name[data-v-06225672]{color:#6196cc}.theme-mode-dark .token.boolean[data-v-06225672],.theme-mode-dark .token.function[data-v-06225672],.theme-mode-dark .token.number[data-v-06225672]{color:#f08d49}.theme-mode-dark .token.class-name[data-v-06225672],.theme-mode-dark .token.constant[data-v-06225672],.theme-mode-dark .token.property[data-v-06225672],.theme-mode-dark .token.symbol[data-v-06225672]{color:#f8c555}.theme-mode-dark .token.atrule[data-v-06225672],.theme-mode-dark .token.builtin[data-v-06225672],.theme-mode-dark .token.important[data-v-06225672],.theme-mode-dark .token.keyword[data-v-06225672],.theme-mode-dark .token.selector[data-v-06225672]{color:#cc99cd}.theme-mode-dark .token.attr-value[data-v-06225672],.theme-mode-dark .token.char[data-v-06225672],.theme-mode-dark .token.regex[data-v-06225672],.theme-mode-dark .token.string[data-v-06225672],.theme-mode-dark .token.variable[data-v-06225672]{color:#7ec699}.theme-mode-dark .token.entity[data-v-06225672],.theme-mode-dark .token.operator[data-v-06225672],.theme-mode-dark .token.url[data-v-06225672]{color:#67cdcc}.theme-mode-dark .language-css .token.string[data-v-06225672],.theme-mode-dark .style .token.string[data-v-06225672],.theme-mode-dark .token.entity[data-v-06225672],.theme-mode-dark .token.operator[data-v-06225672],.theme-mode-dark .token.url[data-v-06225672]{background:none}.theme-mode-dark .token.bold[data-v-06225672],.theme-mode-dark .token.important[data-v-06225672]{font-weight:700}.theme-mode-dark .token.italic[data-v-06225672]{font-style:italic}.theme-mode-dark .token.entity[data-v-06225672]{cursor:help}.theme-mode-dark .token.inserted[data-v-06225672]{color:green}.theme-mode-read[data-v-06225672]{--bodyBg:#f5f5d5;--mainBg:#f5f5d5;--sidebarBg:rgba(245,245,213,0.8);--blurBg:rgba(245,245,213,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#282c34;--codeColor:#fff}.theme-mode-read code[class*=language-][data-v-06225672],.theme-mode-read pre[class*=language-][data-v-06225672]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-read pre[class*=language-][data-v-06225672]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-read :not(pre)>code[class*=language-][data-v-06225672],.theme-mode-read pre[class*=language-][data-v-06225672]{background:#2d2d2d}.theme-mode-read :not(pre)>code[class*=language-][data-v-06225672]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-read .token.block-comment[data-v-06225672],.theme-mode-read .token.cdata[data-v-06225672],.theme-mode-read .token.comment[data-v-06225672],.theme-mode-read .token.doctype[data-v-06225672],.theme-mode-read .token.prolog[data-v-06225672]{color:#999}.theme-mode-read .token.punctuation[data-v-06225672]{color:#ccc}.theme-mode-read .token.attr-name[data-v-06225672],.theme-mode-read .token.deleted[data-v-06225672],.theme-mode-read .token.namespace[data-v-06225672],.theme-mode-read .token.tag[data-v-06225672]{color:#e2777a}.theme-mode-read .token.function-name[data-v-06225672]{color:#6196cc}.theme-mode-read .token.boolean[data-v-06225672],.theme-mode-read .token.function[data-v-06225672],.theme-mode-read .token.number[data-v-06225672]{color:#f08d49}.theme-mode-read .token.class-name[data-v-06225672],.theme-mode-read .token.constant[data-v-06225672],.theme-mode-read .token.property[data-v-06225672],.theme-mode-read .token.symbol[data-v-06225672]{color:#f8c555}.theme-mode-read .token.atrule[data-v-06225672],.theme-mode-read .token.builtin[data-v-06225672],.theme-mode-read .token.important[data-v-06225672],.theme-mode-read .token.keyword[data-v-06225672],.theme-mode-read .token.selector[data-v-06225672]{color:#cc99cd}.theme-mode-read .token.attr-value[data-v-06225672],.theme-mode-read .token.char[data-v-06225672],.theme-mode-read .token.regex[data-v-06225672],.theme-mode-read .token.string[data-v-06225672],.theme-mode-read .token.variable[data-v-06225672]{color:#7ec699}.theme-mode-read .token.entity[data-v-06225672],.theme-mode-read .token.operator[data-v-06225672],.theme-mode-read .token.url[data-v-06225672]{color:#67cdcc}.theme-mode-read .language-css .token.string[data-v-06225672],.theme-mode-read .style .token.string[data-v-06225672],.theme-mode-read .token.entity[data-v-06225672],.theme-mode-read .token.operator[data-v-06225672],.theme-mode-read .token.url[data-v-06225672]{background:none}.theme-mode-read .token.bold[data-v-06225672],.theme-mode-read .token.important[data-v-06225672]{font-weight:700}.theme-mode-read .token.italic[data-v-06225672]{font-style:italic}.theme-mode-read .token.entity[data-v-06225672]{cursor:help}.theme-mode-read .token.inserted[data-v-06225672]{color:green}.articleInfo-wrap[data-v-06225672]{max-width:860px}.theme-style-line .articleInfo-wrap .articleInfo[data-v-06225672]{padding-top:.5rem}.articleInfo-wrap[data-v-06225672]{position:relative;z-index:1;color:#888}.articleInfo-wrap .articleInfo[data-v-06225672]{overflow:hidden;font-size:.92rem}.articleInfo-wrap .articleInfo .breadcrumbs[data-v-06225672]{margin:0;padding:0;overflow:hidden;display:inline-block;line-height:2rem}@media (max-width:960px){.articleInfo-wrap .articleInfo .breadcrumbs[data-v-06225672]{width:100%}}.articleInfo-wrap .articleInfo .breadcrumbs li[data-v-06225672]{list-style-type:none;float:left;padding-right:5px}.articleInfo-wrap .articleInfo .breadcrumbs li[data-v-06225672]:after{content:"/";margin-left:5px;color:#999}.articleInfo-wrap .articleInfo .breadcrumbs li[data-v-06225672]:last-child:after{content:""}.articleInfo-wrap .articleInfo .breadcrumbs li a[data-v-06225672]{color:#888}.articleInfo-wrap .articleInfo .breadcrumbs li a[data-v-06225672]:before{font-size:.92rem}.articleInfo-wrap .articleInfo .breadcrumbs li a[data-v-06225672]:hover{color:#11a8cd}.articleInfo-wrap .articleInfo .breadcrumbs li .icon-home[data-v-06225672]{text-decoration:none}.articleInfo-wrap .articleInfo .info[data-v-06225672]{float:right;line-height:32px}@media (max-width:960px){.articleInfo-wrap .articleInfo .info[data-v-06225672]{float:left}}.articleInfo-wrap .articleInfo .info div[data-v-06225672]{float:left;margin-left:20px;font-size:.8rem}@media (max-width:960px){.articleInfo-wrap .articleInfo .info div[data-v-06225672]{margin:0 20px 0 0}}.articleInfo-wrap .articleInfo .info div[data-v-06225672]:before{margin-right:3px}.articleInfo-wrap .articleInfo .info div a[data-v-06225672]{color:#888}.articleInfo-wrap .articleInfo .info div a[data-v-06225672]:hover{text-decoration:none}.articleInfo-wrap .articleInfo .info div a.beLink[data-v-06225672]:hover{color:#11a8cd;text-decoration:underline}.theme-mode-light[data-v-2cf874fa]{--bodyBg:#f4f4f4;--customBlockBg:#f1f1f1;--textColor:#00323c;--borderColor:rgba(0,0,0,0.12)}.theme-mode-dark[data-v-2cf874fa]{--bodyBg:#27272b;--customBlockBg:#27272b;--textColor:#9b9baa;--borderColor:#30363d}.theme-mode-read[data-v-2cf874fa]{--bodyBg:#ececcc;--customBlockBg:#ececcc;--textColor:#704214;--textLightenColor:#963}.theme-style-line.theme-mode-light[data-v-2cf874fa]{--bodyBg:#fff}.theme-style-line.theme-mode-dark[data-v-2cf874fa]{--bodyBg:#1e1e22}.theme-style-line.theme-mode-read[data-v-2cf874fa]{--bodyBg:#f5f5d5}.theme-mode-light[data-v-2cf874fa]{--bodyBg:#fff;--mainBg:#fff;--sidebarBg:hsla(0,0%,100%,0.8);--blurBg:hsla(0,0%,100%,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#f6f6f6;--codeColor:#525252}.theme-mode-light code[class*=language-][data-v-2cf874fa],.theme-mode-light pre[class*=language-][data-v-2cf874fa]{color:#000;background:none;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-light code[class*=language-][data-v-2cf874fa]::-moz-selection,.theme-mode-light code[class*=language-][data-v-2cf874fa] ::-moz-selection,.theme-mode-light pre[class*=language-][data-v-2cf874fa]::-moz-selection,.theme-mode-light pre[class*=language-][data-v-2cf874fa] ::-moz-selection{text-shadow:none;background:#b3d4fc}.theme-mode-light code[class*=language-][data-v-2cf874fa]::selection,.theme-mode-light code[class*=language-][data-v-2cf874fa] ::selection,.theme-mode-light pre[class*=language-][data-v-2cf874fa]::selection,.theme-mode-light pre[class*=language-][data-v-2cf874fa] ::selection{text-shadow:none;background:#b3d4fc}@media print{.theme-mode-light code[class*=language-][data-v-2cf874fa],.theme-mode-light pre[class*=language-][data-v-2cf874fa]{text-shadow:none}}.theme-mode-light pre[class*=language-][data-v-2cf874fa]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-light :not(pre)>code[class*=language-][data-v-2cf874fa],.theme-mode-light pre[class*=language-][data-v-2cf874fa]{background:#f5f2f0}.theme-mode-light :not(pre)>code[class*=language-][data-v-2cf874fa]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-light .token.cdata[data-v-2cf874fa],.theme-mode-light .token.comment[data-v-2cf874fa],.theme-mode-light .token.doctype[data-v-2cf874fa],.theme-mode-light .token.prolog[data-v-2cf874fa]{color:#708090}.theme-mode-light .token.punctuation[data-v-2cf874fa]{color:#999}.theme-mode-light .namespace[data-v-2cf874fa]{opacity:.7}.theme-mode-light .token.boolean[data-v-2cf874fa],.theme-mode-light .token.constant[data-v-2cf874fa],.theme-mode-light .token.deleted[data-v-2cf874fa],.theme-mode-light .token.number[data-v-2cf874fa],.theme-mode-light .token.property[data-v-2cf874fa],.theme-mode-light .token.symbol[data-v-2cf874fa],.theme-mode-light .token.tag[data-v-2cf874fa]{color:#905}.theme-mode-light .token.attr-name[data-v-2cf874fa],.theme-mode-light .token.builtin[data-v-2cf874fa],.theme-mode-light .token.char[data-v-2cf874fa],.theme-mode-light .token.inserted[data-v-2cf874fa],.theme-mode-light .token.selector[data-v-2cf874fa],.theme-mode-light .token.string[data-v-2cf874fa]{color:#690}.theme-mode-light .language-css .token.string[data-v-2cf874fa],.theme-mode-light .style .token.string[data-v-2cf874fa],.theme-mode-light .token.entity[data-v-2cf874fa],.theme-mode-light .token.operator[data-v-2cf874fa],.theme-mode-light .token.url[data-v-2cf874fa]{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.theme-mode-light .token.atrule[data-v-2cf874fa],.theme-mode-light .token.attr-value[data-v-2cf874fa],.theme-mode-light .token.keyword[data-v-2cf874fa]{color:#07a}.theme-mode-light .token.class-name[data-v-2cf874fa],.theme-mode-light .token.function[data-v-2cf874fa]{color:#dd4a68}.theme-mode-light .token.important[data-v-2cf874fa],.theme-mode-light .token.regex[data-v-2cf874fa],.theme-mode-light .token.variable[data-v-2cf874fa]{color:#e90}.theme-mode-light .token.bold[data-v-2cf874fa],.theme-mode-light .token.important[data-v-2cf874fa]{font-weight:700}.theme-mode-light .token.italic[data-v-2cf874fa]{font-style:italic}.theme-mode-light .token.entity[data-v-2cf874fa]{cursor:help}.theme-mode-light div[class*=language-] .highlight-lines .highlighted[data-v-2cf874fa],.theme-mode-light div[class*=language-].line-numbers-mode .highlight-lines .highlighted[data-v-2cf874fa]:before{background-color:hsla(0,0%,78.4%,.4)}.theme-mode-dark[data-v-2cf874fa]{--bodyBg:#1e1e22;--mainBg:#1e1e22;--sidebarBg:rgba(30,30,34,0.8);--blurBg:rgba(30,30,34,0.8);--textColor:#8c8c96;--textLightenColor:#0085ad;--borderColor:#2c2c3a;--codeBg:#252526;--codeColor:#fff}.theme-mode-dark code[class*=language-][data-v-2cf874fa],.theme-mode-dark pre[class*=language-][data-v-2cf874fa]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-dark pre[class*=language-][data-v-2cf874fa]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-dark :not(pre)>code[class*=language-][data-v-2cf874fa],.theme-mode-dark pre[class*=language-][data-v-2cf874fa]{background:#2d2d2d}.theme-mode-dark :not(pre)>code[class*=language-][data-v-2cf874fa]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-dark .token.block-comment[data-v-2cf874fa],.theme-mode-dark .token.cdata[data-v-2cf874fa],.theme-mode-dark .token.comment[data-v-2cf874fa],.theme-mode-dark .token.doctype[data-v-2cf874fa],.theme-mode-dark .token.prolog[data-v-2cf874fa]{color:#999}.theme-mode-dark .token.punctuation[data-v-2cf874fa]{color:#ccc}.theme-mode-dark .token.attr-name[data-v-2cf874fa],.theme-mode-dark .token.deleted[data-v-2cf874fa],.theme-mode-dark .token.namespace[data-v-2cf874fa],.theme-mode-dark .token.tag[data-v-2cf874fa]{color:#e2777a}.theme-mode-dark .token.function-name[data-v-2cf874fa]{color:#6196cc}.theme-mode-dark .token.boolean[data-v-2cf874fa],.theme-mode-dark .token.function[data-v-2cf874fa],.theme-mode-dark .token.number[data-v-2cf874fa]{color:#f08d49}.theme-mode-dark .token.class-name[data-v-2cf874fa],.theme-mode-dark .token.constant[data-v-2cf874fa],.theme-mode-dark .token.property[data-v-2cf874fa],.theme-mode-dark .token.symbol[data-v-2cf874fa]{color:#f8c555}.theme-mode-dark .token.atrule[data-v-2cf874fa],.theme-mode-dark .token.builtin[data-v-2cf874fa],.theme-mode-dark .token.important[data-v-2cf874fa],.theme-mode-dark .token.keyword[data-v-2cf874fa],.theme-mode-dark .token.selector[data-v-2cf874fa]{color:#cc99cd}.theme-mode-dark .token.attr-value[data-v-2cf874fa],.theme-mode-dark .token.char[data-v-2cf874fa],.theme-mode-dark .token.regex[data-v-2cf874fa],.theme-mode-dark .token.string[data-v-2cf874fa],.theme-mode-dark .token.variable[data-v-2cf874fa]{color:#7ec699}.theme-mode-dark .token.entity[data-v-2cf874fa],.theme-mode-dark .token.operator[data-v-2cf874fa],.theme-mode-dark .token.url[data-v-2cf874fa]{color:#67cdcc}.theme-mode-dark .language-css .token.string[data-v-2cf874fa],.theme-mode-dark .style .token.string[data-v-2cf874fa],.theme-mode-dark .token.entity[data-v-2cf874fa],.theme-mode-dark .token.operator[data-v-2cf874fa],.theme-mode-dark .token.url[data-v-2cf874fa]{background:none}.theme-mode-dark .token.bold[data-v-2cf874fa],.theme-mode-dark .token.important[data-v-2cf874fa]{font-weight:700}.theme-mode-dark .token.italic[data-v-2cf874fa]{font-style:italic}.theme-mode-dark .token.entity[data-v-2cf874fa]{cursor:help}.theme-mode-dark .token.inserted[data-v-2cf874fa]{color:green}.theme-mode-read[data-v-2cf874fa]{--bodyBg:#f5f5d5;--mainBg:#f5f5d5;--sidebarBg:rgba(245,245,213,0.8);--blurBg:rgba(245,245,213,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#282c34;--codeColor:#fff}.theme-mode-read code[class*=language-][data-v-2cf874fa],.theme-mode-read pre[class*=language-][data-v-2cf874fa]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-read pre[class*=language-][data-v-2cf874fa]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-read :not(pre)>code[class*=language-][data-v-2cf874fa],.theme-mode-read pre[class*=language-][data-v-2cf874fa]{background:#2d2d2d}.theme-mode-read :not(pre)>code[class*=language-][data-v-2cf874fa]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-read .token.block-comment[data-v-2cf874fa],.theme-mode-read .token.cdata[data-v-2cf874fa],.theme-mode-read .token.comment[data-v-2cf874fa],.theme-mode-read .token.doctype[data-v-2cf874fa],.theme-mode-read .token.prolog[data-v-2cf874fa]{color:#999}.theme-mode-read .token.punctuation[data-v-2cf874fa]{color:#ccc}.theme-mode-read .token.attr-name[data-v-2cf874fa],.theme-mode-read .token.deleted[data-v-2cf874fa],.theme-mode-read .token.namespace[data-v-2cf874fa],.theme-mode-read .token.tag[data-v-2cf874fa]{color:#e2777a}.theme-mode-read .token.function-name[data-v-2cf874fa]{color:#6196cc}.theme-mode-read .token.boolean[data-v-2cf874fa],.theme-mode-read .token.function[data-v-2cf874fa],.theme-mode-read .token.number[data-v-2cf874fa]{color:#f08d49}.theme-mode-read .token.class-name[data-v-2cf874fa],.theme-mode-read .token.constant[data-v-2cf874fa],.theme-mode-read .token.property[data-v-2cf874fa],.theme-mode-read .token.symbol[data-v-2cf874fa]{color:#f8c555}.theme-mode-read .token.atrule[data-v-2cf874fa],.theme-mode-read .token.builtin[data-v-2cf874fa],.theme-mode-read .token.important[data-v-2cf874fa],.theme-mode-read .token.keyword[data-v-2cf874fa],.theme-mode-read .token.selector[data-v-2cf874fa]{color:#cc99cd}.theme-mode-read .token.attr-value[data-v-2cf874fa],.theme-mode-read .token.char[data-v-2cf874fa],.theme-mode-read .token.regex[data-v-2cf874fa],.theme-mode-read .token.string[data-v-2cf874fa],.theme-mode-read .token.variable[data-v-2cf874fa]{color:#7ec699}.theme-mode-read .token.entity[data-v-2cf874fa],.theme-mode-read .token.operator[data-v-2cf874fa],.theme-mode-read .token.url[data-v-2cf874fa]{color:#67cdcc}.theme-mode-read .language-css .token.string[data-v-2cf874fa],.theme-mode-read .style .token.string[data-v-2cf874fa],.theme-mode-read .token.entity[data-v-2cf874fa],.theme-mode-read .token.operator[data-v-2cf874fa],.theme-mode-read .token.url[data-v-2cf874fa]{background:none}.theme-mode-read .token.bold[data-v-2cf874fa],.theme-mode-read .token.important[data-v-2cf874fa]{font-weight:700}.theme-mode-read .token.italic[data-v-2cf874fa]{font-style:italic}.theme-mode-read .token.entity[data-v-2cf874fa]{cursor:help}.theme-mode-read .token.inserted[data-v-2cf874fa]{color:green}.theme-vdoing-content[data-v-2cf874fa]{margin-bottom:3.6rem}.title-tag[data-v-2cf874fa]{border:1px solid #ff5722;color:#ff5722;font-size:.8rem;padding:0 .35rem;border-radius:.2rem;margin-left:0;transform:translateY(-.05rem);display:inline-block}dd[data-v-2cf874fa],dl[data-v-2cf874fa]{margin:0}.column-wrapper[data-v-2cf874fa]{margin-top:1rem;display:flex;padding-bottom:2rem;border-bottom:1px solid var(--borderColor)}.column-wrapper img[data-v-2cf874fa]{width:80px;height:80px;border-radius:2px;margin-right:1rem}.column-wrapper .column-info .title[data-v-2cf874fa]{font-size:1.6rem}.column-wrapper .column-info .description[data-v-2cf874fa]{color:var(--textColor);opacity:.8;margin:.5rem 0}.catalogue-wrapper .catalogue-title[data-v-2cf874fa]{font-size:1.45rem;margin:2rem 0}.catalogue-wrapper .catalogue-content dl[data-v-2cf874fa]{margin-bottom:1.8rem}.catalogue-wrapper .catalogue-content dl.inline[data-v-2cf874fa]{display:inline-block;width:50%;margin-bottom:1rem}@media (max-width:419px){.catalogue-wrapper .catalogue-content dl.inline[data-v-2cf874fa]{width:100%}}.catalogue-wrapper .catalogue-content dl.inline a[data-v-2cf874fa]{width:100%}.catalogue-wrapper .catalogue-content dl:not(.inline) dt[data-v-2cf874fa]{margin-top:-3.6rem;padding-top:3.6rem}.catalogue-wrapper .catalogue-content dl dt[data-v-2cf874fa]{font-size:1.1rem}.catalogue-wrapper .catalogue-content dl dt:hover .header-anchor[data-v-2cf874fa]{opacity:1}.catalogue-wrapper .catalogue-content dl dd[data-v-2cf874fa]{margin-top:.7rem;margin-left:1rem}.catalogue-wrapper .catalogue-content dl dd a[data-v-2cf874fa]:not(.header-anchor){margin-bottom:.5rem;display:inline-block;width:50%}.catalogue-wrapper .catalogue-content dl dd a[data-v-2cf874fa]:not(.header-anchor):hover{color:#ff5722;text-decoration:none}@media (max-width:720px){.catalogue-wrapper .catalogue-content dl dd a[data-v-2cf874fa]:not(.header-anchor){width:100%}}.catalogue-wrapper .catalogue-content dl .sub-cat-wrap[data-v-2cf874fa]{margin:5px 0 8px;font-size:.95rem}.catalogue-wrapper .catalogue-content dl .sub-cat-wrap>a[data-v-2cf874fa]{padding-left:1rem;box-sizing:border-box}.catalogue-wrapper .catalogue-content dl .sub-cat-wrap .sub-title[data-v-2cf874fa]{margin-top:-3.6rem;padding-top:3.6rem;margin-bottom:6px;font-size:1rem}.catalogue-wrapper .catalogue-content dl .sub-cat-wrap:hover .header-anchor[data-v-2cf874fa]{opacity:1}.theme-style-line .right-menu-wrapper .right-menu-margin{border-left:1px solid var(--borderColor)}.right-menu-wrapper{width:230px;float:right;margin-right:-285px;position:sticky;top:0;font-size:.8rem}.right-menu-wrapper .right-menu-margin{margin-top:4.6rem;border-radius:3px;overflow:hidden}.right-menu-wrapper .right-menu-title{padding:10px 15px 0;background:var(--mainBg);font-size:1rem}.right-menu-wrapper .right-menu-title:after{content:"";display:block;width:100%;height:1px;background:var(--borderColor);margin-top:10px}.right-menu-wrapper .right-menu-content{max-height:80vh;position:relative;overflow:hidden;background:var(--mainBg);padding:4px 3px 4px 0}.right-menu-wrapper .right-menu-content::-webkit-scrollbar{width:3px;height:3px}.right-menu-wrapper .right-menu-content::-webkit-scrollbar-track-piece{background:none}.right-menu-wrapper .right-menu-content::-webkit-scrollbar-thumb:vertical{background-color:hsla(0,0%,49%,.3)}.right-menu-wrapper .right-menu-content:hover{overflow-y:auto;padding-right:0}.right-menu-wrapper .right-menu-content .right-menu-item{padding:4px 15px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;position:relative}.right-menu-wrapper .right-menu-content .right-menu-item.level2{font-size:.8rem}.right-menu-wrapper .right-menu-content .right-menu-item.level3{padding-left:27px}.right-menu-wrapper .right-menu-content .right-menu-item.level4{padding-left:37px}.right-menu-wrapper .right-menu-content .right-menu-item.level5{padding-left:47px}.right-menu-wrapper .right-menu-content .right-menu-item.level6{padding-left:57px}.right-menu-wrapper .right-menu-content .right-menu-item.active:before{content:"";position:absolute;top:5px;left:0;width:3px;height:14px;background:#11a8cd;border-radius:0 4px 4px 0}.right-menu-wrapper .right-menu-content .right-menu-item.active a{color:#11a8cd;opacity:1}.right-menu-wrapper .right-menu-content .right-menu-item a{color:var(--textColor);opacity:.75;display:inline-block;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.right-menu-wrapper .right-menu-content .right-menu-item a:hover{opacity:1}.right-menu-wrapper .right-menu-content:hover{color:#11a8cd}.page>*{max-width:860px;margin:0 auto;padding:1rem 2.5rem 2rem}.page>:not(.footer){background:var(--mainBg);box-shadow:0 1px 2px 0 rgba(0,0,0,.1);margin-bottom:1rem}@media (min-width:940px){.page>:not(.footer){border-radius:2px}}@media (max-width:959px){.page>*{padding:1rem 2rem}}@media (max-width:419px){.page>*{padding:1rem 1.5rem}}.page{padding-bottom:2rem;display:block}@media (max-width:719px){.page{padding-top:3.6rem}}@media (min-width:719px){.page{padding-top:5.1rem}}@media (min-width:719px){.theme-style-line .page{padding-top:3.6rem}}.theme-style-line .page>:not(.footer){box-shadow:0 0}@media (min-width:720px){.theme-style-line .page .placeholder{height:1.2rem}}.theme-vdoing-wrapper .content-wrapper{position:relative}.theme-vdoing-wrapper h1 .title-tag{height:1.5rem;line-height:1.5rem;border:1px solid #ff5722;color:#ff5722;font-size:1rem;padding:0 .4rem;border-radius:.2rem;margin-left:.5rem;transform:translateY(-.25rem);display:inline-block}.theme-vdoing-wrapper h1 img{margin-bottom:-.2rem;margin-right:.2rem;max-width:2.2rem;max-height:2.2rem}.theme-vdoing-wrapper{--linesColor:rgba(50,0,0,0.05)}.theme-vdoing-wrapper.bg-style-1{background-image:linear-gradient(90deg,var(--linesColor) 3%,transparent 0),linear-gradient(0deg,var(--linesColor) 3%,transparent 0);background-position:50%;background-size:20px 20px}.theme-vdoing-wrapper.bg-style-2{background-image:repeating-linear-gradient(0,var(--linesColor),var(--linesColor) 1px,transparent 0,transparent 50%);background-size:30px 30px}.theme-vdoing-wrapper.bg-style-3{background-image:repeating-linear-gradient(90deg,var(--linesColor),var(--linesColor) 1px,transparent 0,transparent 50%);background-size:30px 30px}.theme-vdoing-wrapper.bg-style-4{background-image:repeating-linear-gradient(-45deg,var(--linesColor),var(--linesColor) 1px,transparent 0,transparent 50%);background-size:20px 20px}.theme-vdoing-wrapper.bg-style-5{background-image:repeating-linear-gradient(45deg,var(--linesColor),var(--linesColor) 1px,transparent 0,transparent 50%);background-size:20px 20px}.theme-vdoing-wrapper.bg-style-6{background-image:radial-gradient(var(--linesColor) 1px,transparent 0);background-size:10px 10px}.theme-mode-dark .theme-vdoing-wrapper{--linesColor:hsla(0,0%,49%,0.05)}@media (min-width:720px) and (max-width:1279px){.have-rightmenu .page{padding-right:.8rem!important}}@media (max-width:1279px){.have-rightmenu .right-menu-wrapper{display:none}}@media (min-width:1280px){.have-rightmenu .sidebar .sidebar-sub-headers{display:none}}.theme-container.only-sidebarItem:not(.have-rightmenu) .sidebar,.theme-container.only-sidebarItem:not(.have-rightmenu) .sidebar-button{display:none}@media (min-width:720px){.theme-container.only-sidebarItem:not(.have-rightmenu) .page{padding-left:.8rem!important}}@media (max-width:719px){.theme-container.only-sidebarItem:not(.have-rightmenu) .page{padding-left:0!important}.theme-container.only-sidebarItem:not(.have-rightmenu) .sidebar,.theme-container.only-sidebarItem:not(.have-rightmenu) .sidebar-button{display:block}}@media (min-width:720px) and (max-width:1279px){.theme-container.only-sidebarItem.have-rightmenu .sidebar,.theme-container.only-sidebarItem.have-rightmenu .sidebar-button{display:block}}@media (min-width:1280px){.theme-container.only-sidebarItem.have-rightmenu .sidebar,.theme-container.only-sidebarItem.have-rightmenu .sidebar-button{display:none}}.categories-page .categories-wrapper{position:sticky;top:4.5rem;max-height:calc(100vh - 10rem);min-height:4.2rem}@media (max-width:719px){.categories-page .categories-wrapper{display:none}}.categories-page .categories-wrapper .categories{max-height:calc(100vh - 14rem);min-height:2.2rem;overflow-y:auto;transition:all .2s;position:relative}.categories-page .categories-wrapper .categories a{padding-right:1.8rem}.categories-page .categories-wrapper .categories a span{right:.4rem}.categories-page .categories-wrapper .categories::-webkit-scrollbar-track-piece{background-color:rgba(0,0,0,.05)}.categories-page .categories-wrapper .categories::-webkit-scrollbar-thumb:vertical{background-color:rgba(0,0,0,.15)}.categories-page .categories-wrapper .categories:hover::-webkit-scrollbar-track-piece{background-color:rgba(0,0,0,.1)}.categories-page .categories-wrapper .categories:hover::-webkit-scrollbar-thumb:vertical{background-color:rgba(0,0,0,.25)}.categories-page .main-left .categories-wrapper{position:relative;top:0;padding:.9rem 1.5rem;margin-bottom:.9rem;max-height:15rem;border-radius:0;display:none}@media (max-width:719px){.categories-page .main-left .categories-wrapper{display:block}}.categories-page .main-left .categories-wrapper .categories{max-height:12.3rem}@media (max-width:719px){.theme-style-line .categories-page .main-left .categories-wrapper{margin-top:-.91rem;margin-bottom:-1px;padding:.9rem .2rem .5rem}}.tags-page .tags-wrapper{position:sticky;top:4.5rem;max-height:calc(100vh - 10rem);min-height:4.2rem}@media (max-width:719px){.tags-page .tags-wrapper{display:none}}.tags-page .tags-wrapper .tags{max-height:calc(100vh - 14rem);min-height:2.2rem;overflow-x:hidden;overflow-y:auto;transition:all .2s}.tags-page .tags-wrapper .tags::-webkit-scrollbar-track-piece{background-color:rgba(0,0,0,.05)}.tags-page .tags-wrapper .tags::-webkit-scrollbar-thumb:vertical{background-color:rgba(0,0,0,.15)}.tags-page .tags-wrapper .tags:hover::-webkit-scrollbar-track-piece{background-color:rgba(0,0,0,.1)}.tags-page .tags-wrapper .tags:hover::-webkit-scrollbar-thumb:vertical{background-color:rgba(0,0,0,.25)}.tags-page .main-left .tags-wrapper{position:relative;top:0;padding:.9rem 1.5rem;margin-bottom:.9rem;max-height:15rem;border-radius:0;display:none}@media (max-width:719px){.tags-page .main-left .tags-wrapper{display:block}}.tags-page .main-left .tags-wrapper .tags{max-height:11.5rem}@media (max-width:719px){.theme-style-line .tags-page .main-left .tags-wrapper{margin-top:-.91rem;margin-bottom:-1px}}.archives-page .theme-vdoing-wrapper{max-width:860px;margin:0 auto;padding:1rem 2.5rem 2rem}.archives-page .theme-vdoing-wrapper:not(.footer){background:var(--mainBg);box-shadow:0 1px 2px 0 rgba(0,0,0,.1);margin-bottom:1rem}@media (min-width:940px){.archives-page .theme-vdoing-wrapper:not(.footer){border-radius:2px}}@media (max-width:959px){.archives-page .theme-vdoing-wrapper{padding:1rem 2rem}}@media (max-width:419px){.archives-page .theme-vdoing-wrapper{padding:1rem 1.5rem}}.theme-style-line .archives-page .theme-vdoing-wrapper{box-shadow:0 0}.archives-page .theme-vdoing-wrapper{position:relative}@media (min-width:940px){.archives-page .theme-vdoing-wrapper{margin-top:1.5rem!important}}.archives-page .theme-vdoing-wrapper .count{text-align:right;margin-top:-2.5rem;font-size:.85rem;opacity:.8}.archives-page .theme-vdoing-wrapper li,.archives-page .theme-vdoing-wrapper ul{margin:0;padding:0}.archives-page .theme-vdoing-wrapper ul{margin-top:2rem}.archives-page .theme-vdoing-wrapper li{list-style:none}.archives-page .theme-vdoing-wrapper li.year{position:sticky;top:3.6rem;background:var(--mainBg);z-index:1}.archives-page .theme-vdoing-wrapper li.year:not(:first-child){margin-top:3.5rem}.archives-page .theme-vdoing-wrapper li h2{margin-bottom:.8rem;font-weight:400;padding:.5rem 0}.archives-page .theme-vdoing-wrapper li h2 span{font-size:.85rem;font-weight:300;float:right;margin-top:1rem}.archives-page .theme-vdoing-wrapper li a{display:block;color:var(--textColor);transition:padding .3s;padding:.5rem 2rem;line-height:1.2rem}.archives-page .theme-vdoing-wrapper li a:hover{padding-left:2.5rem;color:#11a8cd;background:#f9f9f9}@media (max-width:940px){.archives-page .theme-vdoing-wrapper li a{padding:.5rem 1rem;font-weight:400}.archives-page .theme-vdoing-wrapper li a:hover{padding-left:1.5rem}}.archives-page .theme-vdoing-wrapper li a span.date{opacity:.6;font-size:.85rem;font-weight:400;margin-right:.3rem}.archives-page .theme-vdoing-wrapper li a .title-tag{border:1px solid #ff5722;color:#ff5722;font-size:.8rem;padding:0 .35rem;border-radius:.2rem;margin-left:0;transform:translateY(-.05rem);display:inline-block}.archives-page .theme-vdoing-wrapper .loadmore{text-align:center;margin-top:1rem;opacity:.5}.theme-mode-dark .archives-page .theme-vdoing-wrapper li a:hover,.theme-mode-read .archives-page .theme-vdoing-wrapper li a:hover{background:var(--customBlockBg)}.hide-navbar .archives-page .theme-vdoing-wrapper li.year{top:0}.sidebar-group .sidebar-group{padding-left:.5em}.sidebar-group:not(.collapsable) .sidebar-heading:not(.clickable){cursor:auto;color:inherit}.sidebar-group.is-sub-group{padding-left:0}.sidebar-group.is-sub-group>.sidebar-heading{font-size:1.01em;line-height:1.4;font-weight:700;padding-left:2rem}.sidebar-group.is-sub-group>.sidebar-group-items{padding-left:1rem}.sidebar-group.is-sub-group>.sidebar-group-items>li>.sidebar-link{font-size:.98em;border-left:none}.sidebar-group.depth-2>.sidebar-heading{border-left:none}.sidebar-heading{color:var(--textColor);transition:color .15s ease;cursor:pointer;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0;border-left:.25rem solid transparent}.sidebar-heading.open,.sidebar-heading:hover{color:inherit}.sidebar-heading .arrow{position:relative;top:-.12em;left:.5em}.sidebar-heading.clickable.active{font-weight:600;color:#11a8cd;border-left-color:#11a8cd}.sidebar-heading.clickable:hover{color:#11a8cd}.sidebar-group-items{transition:height .1s ease-out;font-size:.95em;overflow:hidden}.sidebar .sidebar-sub-headers{padding-left:1rem;font-size:.95em}.sidebar .sidebar-sub-headers .level4{padding-left:.2rem}.sidebar .sidebar-sub-headers .level5{padding-left:.4rem}.sidebar .sidebar-sub-headers .level6{padding-left:.6rem}a.sidebar-link{font-size:1em;font-weight:400;display:inline-block;color:var(--textColor);border-left:.25rem solid transparent;padding:.35rem 1rem .35rem 1.25rem;line-height:1.4;width:100%;box-sizing:border-box}a.sidebar-link:hover{color:#11a8cd}a.sidebar-link.active{font-weight:600;color:#11a8cd;border-left-color:#11a8cd}.sidebar-group a.sidebar-link{padding-left:2rem}.sidebar-sub-headers a.sidebar-link{padding-top:.25rem;padding-bottom:.25rem;border-left:none}.sidebar-sub-headers a.sidebar-link.active{font-weight:500}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .nav-links{display:none;border-bottom:1px solid var(--borderColor);padding:.5rem 0 .75rem}.sidebar .nav-links a{font-weight:600}.sidebar .nav-links .nav-item,.sidebar .nav-links .repo-link{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar>.sidebar-links{padding:1.5rem 0}.sidebar>.sidebar-links>li>a.sidebar-link{font-size:1.1em;line-height:1.7;font-weight:700}.sidebar>.sidebar-links>li:not(:first-child){margin-top:.75rem}.sidebar .blogger{display:none;border-bottom:1px solid var(--borderColor)}.sidebar .blogger img{width:60px;height:60px;border-radius:5px;margin:.75rem 1rem}.sidebar .blogger .blogger-info{flex:1;padding:0 .3rem .3rem 0}.sidebar .blogger .blogger-info h3{margin:.95rem 0 .6rem;font-size:1.1rem}.sidebar .blogger .blogger-info .icons .iconfont{font-size:1.2rem;padding-right:.6rem;color:#777}.sidebar .sidebar-slot{margin-bottom:-.5rem;font-size:.85rem}.sidebar .sidebar-slot.sidebar-slot-top{padding:1.5rem 1.5rem 0}.sidebar .sidebar-slot.sidebar-slot-bottom{padding:0 1.5rem 1.5rem}@media (max-width:719px){.sidebar .blogger{display:flex}.sidebar .nav-links{display:block}.sidebar .nav-links .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar>.sidebar-links{padding:1rem 0}}.yellowBorder{border-radius:5px;box-shadow:0 0 15px #ffe089!important}.buttons{position:fixed;right:2rem;bottom:2.5rem;z-index:11}@media (max-width:959px){.buttons{right:1rem;bottom:1.5rem}}.buttons .button{width:2.2rem;height:2.2rem;line-height:2.2rem;border-radius:50%;box-shadow:0 2px 6px rgba(0,0,0,.15);margin-top:.9rem;text-align:center;cursor:pointer;transition:all .5s;background:var(--blurBg)}.buttons .button.hover{background:#11a8cd;box-shadow:0 0 15px #11a8cd}.buttons .button.hover:before{color:#fff}@media (any-hover:hover){.buttons .button:hover{background:#11a8cd;box-shadow:0 0 15px #11a8cd}.buttons .button:hover:before{color:#fff}}.buttons .button .select-box{margin:0;padding:.8rem 0;position:absolute;bottom:0;right:1.5rem;background:var(--mainBg);border:1px solid var(--borderColor);width:120px;border-radius:6px;box-shadow:0 0 15px hsla(0,0%,100%,.2)}.buttons .button .select-box li{list-style:none;line-height:2rem;font-size:.95rem}.buttons .button .select-box li:hover{color:#11a8cd}.buttons .button .select-box li.active{background-color:hsla(0,0%,58.8%,.2);color:#11a8cd}.mode-enter-active,.mode-leave-active{transition:all .3s}.mode-enter,.mode-leave-to{opacity:0;transform:scale(.8)}.fade-enter-active,.fade-leave-active{transition:opacity .2s}.fade-enter,.fade-leave-to{opacity:0}.footer{padding:5rem 1.5rem 2.5rem;text-align:center;color:#666;box-sizing:border-box;font-size:.85rem;transition:all .2s ease}.footer>span{line-height:1.5rem}.footer .icons{margin-bottom:12px}.footer .icons .iconfont{padding:0 10px;font-size:1.3rem}.footer a{color:inherit}.footer a:hover{color:#11a8cd}@media (min-width:720px){.sidebar-open .footer{width:auto;padding-left:19.5rem}}@media (min-width:1520px){.have-rightmenu .footer{padding-right:231.5px}}.no-sidebar .footer{width:auto;padding-left:1.5rem}.body-bg{position:fixed;left:0;top:0;z-index:-999999;height:100vh;width:100vw;transition:background .5s}.theme-mode-light{--bodyBg:#f4f4f4;--customBlockBg:#f1f1f1;--textColor:#00323c;--borderColor:rgba(0,0,0,0.12)}.theme-mode-dark{--bodyBg:#27272b;--customBlockBg:#27272b;--textColor:#9b9baa;--borderColor:#30363d}.theme-mode-read{--bodyBg:#ececcc;--customBlockBg:#ececcc;--textColor:#704214;--textLightenColor:#963}.theme-style-line.theme-mode-light{--bodyBg:#fff}.theme-style-line.theme-mode-dark{--bodyBg:#1e1e22}.theme-style-line.theme-mode-read{--bodyBg:#f5f5d5}.theme-mode-light{--bodyBg:#fff;--mainBg:#fff;--sidebarBg:hsla(0,0%,100%,0.8);--blurBg:hsla(0,0%,100%,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#f6f6f6;--codeColor:#525252}.theme-mode-light code[class*=language-],.theme-mode-light pre[class*=language-]{color:#000;background:none;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-light code[class*=language-]::-moz-selection,.theme-mode-light code[class*=language-] ::-moz-selection,.theme-mode-light pre[class*=language-]::-moz-selection,.theme-mode-light pre[class*=language-] ::-moz-selection{text-shadow:none;background:#b3d4fc}.theme-mode-light code[class*=language-]::selection,.theme-mode-light code[class*=language-] ::selection,.theme-mode-light pre[class*=language-]::selection,.theme-mode-light pre[class*=language-] ::selection{text-shadow:none;background:#b3d4fc}@media print{.theme-mode-light code[class*=language-],.theme-mode-light pre[class*=language-]{text-shadow:none}}.theme-mode-light pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-light :not(pre)>code[class*=language-],.theme-mode-light pre[class*=language-]{background:#f5f2f0}.theme-mode-light :not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-light .token.cdata,.theme-mode-light .token.comment,.theme-mode-light .token.doctype,.theme-mode-light .token.prolog{color:#708090}.theme-mode-light .token.punctuation{color:#999}.theme-mode-light .namespace{opacity:.7}.theme-mode-light .token.boolean,.theme-mode-light .token.constant,.theme-mode-light .token.deleted,.theme-mode-light .token.number,.theme-mode-light .token.property,.theme-mode-light .token.symbol,.theme-mode-light .token.tag{color:#905}.theme-mode-light .token.attr-name,.theme-mode-light .token.builtin,.theme-mode-light .token.char,.theme-mode-light .token.inserted,.theme-mode-light .token.selector,.theme-mode-light .token.string{color:#690}.theme-mode-light .language-css .token.string,.theme-mode-light .style .token.string,.theme-mode-light .token.entity,.theme-mode-light .token.operator,.theme-mode-light .token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.theme-mode-light .token.atrule,.theme-mode-light .token.attr-value,.theme-mode-light .token.keyword{color:#07a}.theme-mode-light .token.class-name,.theme-mode-light .token.function{color:#dd4a68}.theme-mode-light .token.important,.theme-mode-light .token.regex,.theme-mode-light .token.variable{color:#e90}.theme-mode-light .token.bold,.theme-mode-light .token.important{font-weight:700}.theme-mode-light .token.italic{font-style:italic}.theme-mode-light .token.entity{cursor:help}.theme-mode-light div[class*=language-] .highlight-lines .highlighted,.theme-mode-light div[class*=language-].line-numbers-mode .highlight-lines .highlighted:before{background-color:hsla(0,0%,78.4%,.4)}.theme-mode-dark{--bodyBg:#1e1e22;--mainBg:#1e1e22;--sidebarBg:rgba(30,30,34,0.8);--blurBg:rgba(30,30,34,0.8);--textColor:#8c8c96;--textLightenColor:#0085ad;--borderColor:#2c2c3a;--codeBg:#252526;--codeColor:#fff}.theme-mode-dark code[class*=language-],.theme-mode-dark pre[class*=language-]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-dark pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-dark :not(pre)>code[class*=language-],.theme-mode-dark pre[class*=language-]{background:#2d2d2d}.theme-mode-dark :not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-dark .token.block-comment,.theme-mode-dark .token.cdata,.theme-mode-dark .token.comment,.theme-mode-dark .token.doctype,.theme-mode-dark .token.prolog{color:#999}.theme-mode-dark .token.punctuation{color:#ccc}.theme-mode-dark .token.attr-name,.theme-mode-dark .token.deleted,.theme-mode-dark .token.namespace,.theme-mode-dark .token.tag{color:#e2777a}.theme-mode-dark .token.function-name{color:#6196cc}.theme-mode-dark .token.boolean,.theme-mode-dark .token.function,.theme-mode-dark .token.number{color:#f08d49}.theme-mode-dark .token.class-name,.theme-mode-dark .token.constant,.theme-mode-dark .token.property,.theme-mode-dark .token.symbol{color:#f8c555}.theme-mode-dark .token.atrule,.theme-mode-dark .token.builtin,.theme-mode-dark .token.important,.theme-mode-dark .token.keyword,.theme-mode-dark .token.selector{color:#cc99cd}.theme-mode-dark .token.attr-value,.theme-mode-dark .token.char,.theme-mode-dark .token.regex,.theme-mode-dark .token.string,.theme-mode-dark .token.variable{color:#7ec699}.theme-mode-dark .token.entity,.theme-mode-dark .token.operator,.theme-mode-dark .token.url{color:#67cdcc}.theme-mode-dark .language-css .token.string,.theme-mode-dark .style .token.string,.theme-mode-dark .token.entity,.theme-mode-dark .token.operator,.theme-mode-dark .token.url{background:none}.theme-mode-dark .token.bold,.theme-mode-dark .token.important{font-weight:700}.theme-mode-dark .token.italic{font-style:italic}.theme-mode-dark .token.entity{cursor:help}.theme-mode-dark .token.inserted{color:green}.theme-mode-read{--bodyBg:#f5f5d5;--mainBg:#f5f5d5;--sidebarBg:rgba(245,245,213,0.8);--blurBg:rgba(245,245,213,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#282c34;--codeColor:#fff}.theme-mode-read code[class*=language-],.theme-mode-read pre[class*=language-]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-read pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-read :not(pre)>code[class*=language-],.theme-mode-read pre[class*=language-]{background:#2d2d2d}.theme-mode-read :not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-read .token.block-comment,.theme-mode-read .token.cdata,.theme-mode-read .token.comment,.theme-mode-read .token.doctype,.theme-mode-read .token.prolog{color:#999}.theme-mode-read .token.punctuation{color:#ccc}.theme-mode-read .token.attr-name,.theme-mode-read .token.deleted,.theme-mode-read .token.namespace,.theme-mode-read .token.tag{color:#e2777a}.theme-mode-read .token.function-name{color:#6196cc}.theme-mode-read .token.boolean,.theme-mode-read .token.function,.theme-mode-read .token.number{color:#f08d49}.theme-mode-read .token.class-name,.theme-mode-read .token.constant,.theme-mode-read .token.property,.theme-mode-read .token.symbol{color:#f8c555}.theme-mode-read .token.atrule,.theme-mode-read .token.builtin,.theme-mode-read .token.important,.theme-mode-read .token.keyword,.theme-mode-read .token.selector{color:#cc99cd}.theme-mode-read .token.attr-value,.theme-mode-read .token.char,.theme-mode-read .token.regex,.theme-mode-read .token.string,.theme-mode-read .token.variable{color:#7ec699}.theme-mode-read .token.entity,.theme-mode-read .token.operator,.theme-mode-read .token.url{color:#67cdcc}.theme-mode-read .language-css .token.string,.theme-mode-read .style .token.string,.theme-mode-read .token.entity,.theme-mode-read .token.operator,.theme-mode-read .token.url{background:none}.theme-mode-read .token.bold,.theme-mode-read .token.important{font-weight:700}.theme-mode-read .token.italic{font-style:italic}.theme-mode-read .token.entity{cursor:help}.theme-mode-read .token.inserted{color:green}.custom-html-window{position:fixed;bottom:0;display:flex;overflow:hidden;font-weight:350}@media (max-width:960px){.custom-html-window{display:none}}.custom-html-window .custom-wrapper{position:relative;max-width:200px;max-height:400px}.custom-html-window .custom-wrapper .close-but{cursor:pointer;position:absolute;right:0;top:0;font-size:1.5rem;line-height:1.5rem;width:1.5rem;height:1.5rem;opacity:0;transition:all .2s}.custom-html-window .custom-wrapper .close-but:hover{opacity:.9}.custom-html-window .custom-wrapper:hover .close-but{opacity:.7}.custom-html-window.custom-html-window-lb{left:0;z-index:99}.custom-html-window.custom-html-window-lb>*{align-self:flex-end}.custom-html-window.custom-html-window-rb{right:80px;z-index:10;justify-content:flex-end}.custom-html-window.custom-html-window-rb>*{align-self:flex-end}.theme-mode-light[data-v-d5affa18]{--bodyBg:#f4f4f4;--customBlockBg:#f1f1f1;--textColor:#00323c;--borderColor:rgba(0,0,0,0.12)}.theme-mode-dark[data-v-d5affa18]{--bodyBg:#27272b;--customBlockBg:#27272b;--textColor:#9b9baa;--borderColor:#30363d}.theme-mode-read[data-v-d5affa18]{--bodyBg:#ececcc;--customBlockBg:#ececcc;--textColor:#704214;--textLightenColor:#963}.theme-style-line.theme-mode-light[data-v-d5affa18]{--bodyBg:#fff}.theme-style-line.theme-mode-dark[data-v-d5affa18]{--bodyBg:#1e1e22}.theme-style-line.theme-mode-read[data-v-d5affa18]{--bodyBg:#f5f5d5}.theme-mode-light[data-v-d5affa18]{--bodyBg:#fff;--mainBg:#fff;--sidebarBg:hsla(0,0%,100%,0.8);--blurBg:hsla(0,0%,100%,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#f6f6f6;--codeColor:#525252}.theme-mode-light code[class*=language-][data-v-d5affa18],.theme-mode-light pre[class*=language-][data-v-d5affa18]{color:#000;background:none;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-light code[class*=language-][data-v-d5affa18]::-moz-selection,.theme-mode-light code[class*=language-][data-v-d5affa18] ::-moz-selection,.theme-mode-light pre[class*=language-][data-v-d5affa18]::-moz-selection,.theme-mode-light pre[class*=language-][data-v-d5affa18] ::-moz-selection{text-shadow:none;background:#b3d4fc}.theme-mode-light code[class*=language-][data-v-d5affa18]::selection,.theme-mode-light code[class*=language-][data-v-d5affa18] ::selection,.theme-mode-light pre[class*=language-][data-v-d5affa18]::selection,.theme-mode-light pre[class*=language-][data-v-d5affa18] ::selection{text-shadow:none;background:#b3d4fc}@media print{.theme-mode-light code[class*=language-][data-v-d5affa18],.theme-mode-light pre[class*=language-][data-v-d5affa18]{text-shadow:none}}.theme-mode-light pre[class*=language-][data-v-d5affa18]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-light :not(pre)>code[class*=language-][data-v-d5affa18],.theme-mode-light pre[class*=language-][data-v-d5affa18]{background:#f5f2f0}.theme-mode-light :not(pre)>code[class*=language-][data-v-d5affa18]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-light .token.cdata[data-v-d5affa18],.theme-mode-light .token.comment[data-v-d5affa18],.theme-mode-light .token.doctype[data-v-d5affa18],.theme-mode-light .token.prolog[data-v-d5affa18]{color:#708090}.theme-mode-light .token.punctuation[data-v-d5affa18]{color:#999}.theme-mode-light .namespace[data-v-d5affa18]{opacity:.7}.theme-mode-light .token.boolean[data-v-d5affa18],.theme-mode-light .token.constant[data-v-d5affa18],.theme-mode-light .token.deleted[data-v-d5affa18],.theme-mode-light .token.number[data-v-d5affa18],.theme-mode-light .token.property[data-v-d5affa18],.theme-mode-light .token.symbol[data-v-d5affa18],.theme-mode-light .token.tag[data-v-d5affa18]{color:#905}.theme-mode-light .token.attr-name[data-v-d5affa18],.theme-mode-light .token.builtin[data-v-d5affa18],.theme-mode-light .token.char[data-v-d5affa18],.theme-mode-light .token.inserted[data-v-d5affa18],.theme-mode-light .token.selector[data-v-d5affa18],.theme-mode-light .token.string[data-v-d5affa18]{color:#690}.theme-mode-light .language-css .token.string[data-v-d5affa18],.theme-mode-light .style .token.string[data-v-d5affa18],.theme-mode-light .token.entity[data-v-d5affa18],.theme-mode-light .token.operator[data-v-d5affa18],.theme-mode-light .token.url[data-v-d5affa18]{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.theme-mode-light .token.atrule[data-v-d5affa18],.theme-mode-light .token.attr-value[data-v-d5affa18],.theme-mode-light .token.keyword[data-v-d5affa18]{color:#07a}.theme-mode-light .token.class-name[data-v-d5affa18],.theme-mode-light .token.function[data-v-d5affa18]{color:#dd4a68}.theme-mode-light .token.important[data-v-d5affa18],.theme-mode-light .token.regex[data-v-d5affa18],.theme-mode-light .token.variable[data-v-d5affa18]{color:#e90}.theme-mode-light .token.bold[data-v-d5affa18],.theme-mode-light .token.important[data-v-d5affa18]{font-weight:700}.theme-mode-light .token.italic[data-v-d5affa18]{font-style:italic}.theme-mode-light .token.entity[data-v-d5affa18]{cursor:help}.theme-mode-light div[class*=language-] .highlight-lines .highlighted[data-v-d5affa18],.theme-mode-light div[class*=language-].line-numbers-mode .highlight-lines .highlighted[data-v-d5affa18]:before{background-color:hsla(0,0%,78.4%,.4)}.theme-mode-dark[data-v-d5affa18]{--bodyBg:#1e1e22;--mainBg:#1e1e22;--sidebarBg:rgba(30,30,34,0.8);--blurBg:rgba(30,30,34,0.8);--textColor:#8c8c96;--textLightenColor:#0085ad;--borderColor:#2c2c3a;--codeBg:#252526;--codeColor:#fff}.theme-mode-dark code[class*=language-][data-v-d5affa18],.theme-mode-dark pre[class*=language-][data-v-d5affa18]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-dark pre[class*=language-][data-v-d5affa18]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-dark :not(pre)>code[class*=language-][data-v-d5affa18],.theme-mode-dark pre[class*=language-][data-v-d5affa18]{background:#2d2d2d}.theme-mode-dark :not(pre)>code[class*=language-][data-v-d5affa18]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-dark .token.block-comment[data-v-d5affa18],.theme-mode-dark .token.cdata[data-v-d5affa18],.theme-mode-dark .token.comment[data-v-d5affa18],.theme-mode-dark .token.doctype[data-v-d5affa18],.theme-mode-dark .token.prolog[data-v-d5affa18]{color:#999}.theme-mode-dark .token.punctuation[data-v-d5affa18]{color:#ccc}.theme-mode-dark .token.attr-name[data-v-d5affa18],.theme-mode-dark .token.deleted[data-v-d5affa18],.theme-mode-dark .token.namespace[data-v-d5affa18],.theme-mode-dark .token.tag[data-v-d5affa18]{color:#e2777a}.theme-mode-dark .token.function-name[data-v-d5affa18]{color:#6196cc}.theme-mode-dark .token.boolean[data-v-d5affa18],.theme-mode-dark .token.function[data-v-d5affa18],.theme-mode-dark .token.number[data-v-d5affa18]{color:#f08d49}.theme-mode-dark .token.class-name[data-v-d5affa18],.theme-mode-dark .token.constant[data-v-d5affa18],.theme-mode-dark .token.property[data-v-d5affa18],.theme-mode-dark .token.symbol[data-v-d5affa18]{color:#f8c555}.theme-mode-dark .token.atrule[data-v-d5affa18],.theme-mode-dark .token.builtin[data-v-d5affa18],.theme-mode-dark .token.important[data-v-d5affa18],.theme-mode-dark .token.keyword[data-v-d5affa18],.theme-mode-dark .token.selector[data-v-d5affa18]{color:#cc99cd}.theme-mode-dark .token.attr-value[data-v-d5affa18],.theme-mode-dark .token.char[data-v-d5affa18],.theme-mode-dark .token.regex[data-v-d5affa18],.theme-mode-dark .token.string[data-v-d5affa18],.theme-mode-dark .token.variable[data-v-d5affa18]{color:#7ec699}.theme-mode-dark .token.entity[data-v-d5affa18],.theme-mode-dark .token.operator[data-v-d5affa18],.theme-mode-dark .token.url[data-v-d5affa18]{color:#67cdcc}.theme-mode-dark .language-css .token.string[data-v-d5affa18],.theme-mode-dark .style .token.string[data-v-d5affa18],.theme-mode-dark .token.entity[data-v-d5affa18],.theme-mode-dark .token.operator[data-v-d5affa18],.theme-mode-dark .token.url[data-v-d5affa18]{background:none}.theme-mode-dark .token.bold[data-v-d5affa18],.theme-mode-dark .token.important[data-v-d5affa18]{font-weight:700}.theme-mode-dark .token.italic[data-v-d5affa18]{font-style:italic}.theme-mode-dark .token.entity[data-v-d5affa18]{cursor:help}.theme-mode-dark .token.inserted[data-v-d5affa18]{color:green}.theme-mode-read[data-v-d5affa18]{--bodyBg:#f5f5d5;--mainBg:#f5f5d5;--sidebarBg:rgba(245,245,213,0.8);--blurBg:rgba(245,245,213,0.9);--textColor:#004050;--textLightenColor:#0085ad;--borderColor:rgba(0,0,0,0.15);--codeBg:#282c34;--codeColor:#fff}.theme-mode-read code[class*=language-][data-v-d5affa18],.theme-mode-read pre[class*=language-][data-v-d5affa18]{color:#ccc;background:none;text-shadow:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;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;hyphens:none}.theme-mode-read pre[class*=language-][data-v-d5affa18]{padding:1em;margin:.5em 0;overflow:auto}.theme-mode-read :not(pre)>code[class*=language-][data-v-d5affa18],.theme-mode-read pre[class*=language-][data-v-d5affa18]{background:#2d2d2d}.theme-mode-read :not(pre)>code[class*=language-][data-v-d5affa18]{padding:.1em;border-radius:.3em;white-space:normal}.theme-mode-read .token.block-comment[data-v-d5affa18],.theme-mode-read .token.cdata[data-v-d5affa18],.theme-mode-read .token.comment[data-v-d5affa18],.theme-mode-read .token.doctype[data-v-d5affa18],.theme-mode-read .token.prolog[data-v-d5affa18]{color:#999}.theme-mode-read .token.punctuation[data-v-d5affa18]{color:#ccc}.theme-mode-read .token.attr-name[data-v-d5affa18],.theme-mode-read .token.deleted[data-v-d5affa18],.theme-mode-read .token.namespace[data-v-d5affa18],.theme-mode-read .token.tag[data-v-d5affa18]{color:#e2777a}.theme-mode-read .token.function-name[data-v-d5affa18]{color:#6196cc}.theme-mode-read .token.boolean[data-v-d5affa18],.theme-mode-read .token.function[data-v-d5affa18],.theme-mode-read .token.number[data-v-d5affa18]{color:#f08d49}.theme-mode-read .token.class-name[data-v-d5affa18],.theme-mode-read .token.constant[data-v-d5affa18],.theme-mode-read .token.property[data-v-d5affa18],.theme-mode-read .token.symbol[data-v-d5affa18]{color:#f8c555}.theme-mode-read .token.atrule[data-v-d5affa18],.theme-mode-read .token.builtin[data-v-d5affa18],.theme-mode-read .token.important[data-v-d5affa18],.theme-mode-read .token.keyword[data-v-d5affa18],.theme-mode-read .token.selector[data-v-d5affa18]{color:#cc99cd}.theme-mode-read .token.attr-value[data-v-d5affa18],.theme-mode-read .token.char[data-v-d5affa18],.theme-mode-read .token.regex[data-v-d5affa18],.theme-mode-read .token.string[data-v-d5affa18],.theme-mode-read .token.variable[data-v-d5affa18]{color:#7ec699}.theme-mode-read .token.entity[data-v-d5affa18],.theme-mode-read .token.operator[data-v-d5affa18],.theme-mode-read .token.url[data-v-d5affa18]{color:#67cdcc}.theme-mode-read .language-css .token.string[data-v-d5affa18],.theme-mode-read .style .token.string[data-v-d5affa18],.theme-mode-read .token.entity[data-v-d5affa18],.theme-mode-read .token.operator[data-v-d5affa18],.theme-mode-read .token.url[data-v-d5affa18]{background:none}.theme-mode-read .token.bold[data-v-d5affa18],.theme-mode-read .token.important[data-v-d5affa18]{font-weight:700}.theme-mode-read .token.italic[data-v-d5affa18]{font-style:italic}.theme-mode-read .token.entity[data-v-d5affa18]{cursor:help}.theme-mode-read .token.inserted[data-v-d5affa18]{color:green}.badge[data-v-d5affa18]{display:inline-block;font-size:14px;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:#fff}.badge.green[data-v-d5affa18],.badge.tip[data-v-d5affa18],.badge[data-v-d5affa18]{background-color:#42b983}.badge.error[data-v-d5affa18]{background-color:#da5961}.badge.warn[data-v-d5affa18],.badge.warning[data-v-d5affa18],.badge.yellow[data-v-d5affa18]{background-color:#e7c000}.badge+.badge[data-v-d5affa18]{margin-left:5px} \ No newline at end of file diff --git a/assets/img/search.237d6f6a.svg b/assets/img/search.237d6f6a.svg new file mode 100644 index 0000000..18ed22a --- /dev/null +++ b/assets/img/search.237d6f6a.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/js/10.107c327e.js b/assets/js/10.107c327e.js new file mode 100644 index 0000000..553438f --- /dev/null +++ b/assets/js/10.107c327e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{375:function(t,s,a){"use strict";a.r(s);var n=a(15),r=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"线性表的排序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#线性表的排序"}},[t._v("#")]),t._v(" 线性表的排序")]),t._v(" "),s("blockquote",[s("p",[t._v("📦 本文已归档到:「"),s("a",{attrs:{href:"https://github.com/dunwu/blog/tree/master/source/_posts/algorithm",target:"_blank",rel:"noopener noreferrer"}},[t._v("blog"),s("OutboundLink")],1),t._v("」")]),t._v(" "),s("p",[t._v("🔁 本文中的示例代码已归档到:「"),s("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("algorithm-tutorial"),s("OutboundLink")],1),t._v("」")])]),t._v(" "),s("h2",{attrs:{id:"冒泡排序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#冒泡排序"}},[t._v("#")]),t._v(" 冒泡排序")]),t._v(" "),s("h3",{attrs:{id:"要点"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#要点"}},[t._v("#")]),t._v(" 要点")]),t._v(" "),s("p",[t._v("冒泡排序是一种交换排序。")]),t._v(" "),s("p",[t._v("什么是交换排序呢?")]),t._v(" "),s("blockquote",[s("p",[t._v("交换排序:两两比较待排序的关键字,并交换不满足次序要求的那对数,直到整个表都满足次序要求为止。")])]),t._v(" "),s("h3",{attrs:{id:"算法思想"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法思想"}},[t._v("#")]),t._v(" 算法思想")]),t._v(" "),s("p",[t._v("它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。")]),t._v(" "),s("p",[t._v("这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端,故名。")]),t._v(" "),s("p",[t._v("假设有一个大小为 N 的无序序列。冒泡排序就是要每趟排序过程中通过两两比较,找到第 i 个小(大)的元素,将其往上排。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/bubble-sort.png",alt:"img"}})]),t._v(" "),s("p",[t._v("以上图为例,演示一下冒泡排序的实际流程:")]),t._v(" "),s("p",[t._v("假设有一个无序序列 { 4. 3. 1. 2, 5 }")]),t._v(" "),s("ul",[s("li",[t._v("第一趟排序:通过两两比较,找到第一小的数值 1 ,将其放在序列的第一位。")]),t._v(" "),s("li",[t._v("第二趟排序:通过两两比较,找到第二小的数值 2 ,将其放在序列的第二位。")]),t._v(" "),s("li",[t._v("第三趟排序:通过两两比较,找到第三小的数值 3 ,将其放在序列的第三位。")])]),t._v(" "),s("p",[t._v("至此,所有元素已经有序,排序结束。")]),t._v(" "),s("p",[t._v("要将以上流程转化为代码,我们需要像机器一样去思考,不然编译器可看不懂。")]),t._v(" "),s("ul",[s("li",[t._v("假设要对一个大小为 N 的无序序列进行升序排序(即从小到大)。\n"),s("ul",[s("li",[t._v("每趟排序过程中需要通过比较找到第 i 个小的元素。")]),t._v(" "),s("li",[t._v("所以,我们需要一个外部循环,从数组首端(下标 0) 开始,一直扫描到倒数第二个元素(即下标 N - 2) ,剩下最后一个元素,必然为最大。")])])]),t._v(" "),s("li",[t._v("假设是第 i 趟排序,可知,前 i-1 个元素已经有序。现在要找第 i 个元素,只需从数组末端开始,扫描到第 i 个元素,将它们两两比较即可。\n"),s("ul",[s("li",[t._v("所以,需要一个内部循环,从数组末端开始(下标 N - 1),扫描到 (下标 i + 1)。")])])])]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bubbleSort")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 用来交换的临时数")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 要遍历的次数")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 从后向前依次的比较相邻两个数的大小,遍历一次后,把数组中第i小的数放在第i个位置上")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("--")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 比较相邻的元素,如果前面的数大于后面的数,则交换")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" temp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"第 %d 趟:\\t"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printAll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"算法分析"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法分析"}},[t._v("#")]),t._v(" 算法分析")]),t._v(" "),s("p",[s("strong",[t._v("冒泡排序算法的性能")])]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("参数")]),t._v(" "),s("th",[t._v("结果")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("排序类别")]),t._v(" "),s("td",[t._v("交换排序")])]),t._v(" "),s("tr",[s("td",[t._v("排序方法")]),t._v(" "),s("td",[t._v("冒泡排序")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度平均情况")]),t._v(" "),s("td",[t._v("O(N2)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最坏情况")]),t._v(" "),s("td",[t._v("O(N3)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最好情况")]),t._v(" "),s("td",[t._v("O(N)")])]),t._v(" "),s("tr",[s("td",[t._v("空间复杂度")]),t._v(" "),s("td",[t._v("O(1)")])]),t._v(" "),s("tr",[s("td",[t._v("稳定性")]),t._v(" "),s("td",[t._v("稳定")])]),t._v(" "),s("tr",[s("td",[t._v("复杂性")]),t._v(" "),s("td",[t._v("简单")])])])]),t._v(" "),s("h4",{attrs:{id:"时间复杂度"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度"}},[t._v("#")]),t._v(" 时间复杂度")]),t._v(" "),s("p",[t._v("若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数 C 和记录移动次数 M 均达到最小值:Cmin = N - 1, Mmin = 0。所以,冒泡排序最好时间复杂度为 O(N)。")]),t._v(" "),s("p",[t._v("若初始文件是反序的,需要进行 N -1 趟排序。每趟排序要进行 N - i 次关键字的比较(1 ≤ i ≤ N - 1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:")]),t._v(" "),s("p",[t._v("Cmax = N(N-1)/2 = O(N2)")]),t._v(" "),s("p",[t._v("Mmax = 3N(N-1)/2 = O(N2)")]),t._v(" "),s("p",[t._v("冒泡排序的最坏时间复杂度为 O(N2)。")]),t._v(" "),s("p",[t._v("因此,冒泡排序的平均时间复杂度为 O(N2)。")]),t._v(" "),s("p",[t._v("总结起来,其实就是一句话:当数据越接近正序时,冒泡排序性能越好。")]),t._v(" "),s("h4",{attrs:{id:"算法稳定性"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法稳定性"}},[t._v("#")]),t._v(" 算法稳定性")]),t._v(" "),s("p",[t._v("冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。")]),t._v(" "),s("p",[t._v("所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。")]),t._v(" "),s("h4",{attrs:{id:"优化"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#优化"}},[t._v("#")]),t._v(" 优化")]),t._v(" "),s("p",[t._v("对冒泡排序常见的改进方法是加入标志性变量 exchange,用于标志某一趟排序过程中是否有数据交换。")]),t._v(" "),s("p",[t._v("如果进行某一趟排序时并没有进行数据交换,则说明所有数据已经有序,可立即结束排序,避免不必要的比较过程。")]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 对 bubbleSort 的优化算法")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bubbleSort_2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 用来交换的临时数")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("boolean")]),t._v(" bChange "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 交换标志")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 要遍历的次数")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n bChange "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 从后向前依次的比较相邻两个数的大小,遍历一次后,把数组中第i小的数放在第i个位置上")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("--")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 比较相邻的元素,如果前面的数大于后面的数,则交换")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" temp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n bChange "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 如果标志为false,说明本轮遍历没有交换,已经是有序数列,可以结束排序")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" bChange"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("break")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"第 %d 趟:\\t"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printAll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"示例代码"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#示例代码"}},[t._v("#")]),t._v(" 示例代码")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的 Github 测试例"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。")]),t._v(" "),s("h2",{attrs:{id:"快速排序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#快速排序"}},[t._v("#")]),t._v(" 快速排序")]),t._v(" "),s("h3",{attrs:{id:"要点-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#要点-2"}},[t._v("#")]),t._v(" 要点")]),t._v(" "),s("blockquote",[s("p",[t._v("快速排序是一种交换排序。")])]),t._v(" "),s("p",[t._v("快速排序由 C. A. R. Hoare 在 1962 年提出。")]),t._v(" "),s("h3",{attrs:{id:"算法思想-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法思想-2"}},[t._v("#")]),t._v(" 算法思想")]),t._v(" "),s("p",[t._v("它的基本思想是:")]),t._v(" "),s("p",[t._v("通过一趟排序将要排序的数据分割成独立的两部分:分割点左边都是比它小的数,右边都是比它大的数。")]),t._v(" "),s("p",[t._v("然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。")]),t._v(" "),s("p",[t._v("详细的图解往往比大堆的文字更有说明力,所以直接上图:")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/quick-sort.png",alt:"img"}})]),t._v(" "),s("p",[t._v("上图中,演示了快速排序的处理过程:")]),t._v(" "),s("ol",[s("li",[t._v("初始状态为一组无序的数组:2、4、5、1、3。")]),t._v(" "),s("li",[t._v("经过以上操作步骤后,完成了第一次的排序,得到新的数组:1、2、5、4、3。")]),t._v(" "),s("li",[t._v("新的数组中,以 2 为分割点,左边都是比 2 小的数,右边都是比 2 大的数。")]),t._v(" "),s("li",[t._v("因为 2 已经在数组中找到了合适的位置,所以不用再动。")]),t._v(" "),s("li",[t._v("2 左边的数组只有一个元素 1,所以显然不用再排序,位置也被确定。(注:这种情况时,left 指针和 right 指针显然是重合的。因此在代码中,我们可以通过设置判定条件 left 必须小于 right,如果不满足,则不用排序了)。")]),t._v(" "),s("li",[t._v("而对于 2 右边的数组 5、4、3,设置 left 指向 5,right 指向 3,开始继续重复图中的一、二、三、四步骤,对新的数组进行排序。")])]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("division")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 以最左边的数(left)为基准")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" base "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("left "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 从序列右端开始,向左遍历,直到找到小于base的数")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("left "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" right "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" base"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n right"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("--")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 找到了比base小的元素,将这个元素放到最左边的位置")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 从序列左端开始,向右遍历,直到找到大于base的数")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("left "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" right "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" base"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n left"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 找到了比base大的元素,将这个元素放到最右边的位置")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 最后将base放到left位置。此时,left位置的左侧数值应该都比left小;")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 而left位置的右侧数值应该都比left大。")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" base"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("quickSort")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 左下标一定小于右下标,否则就越界了")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("left "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 对数组进行分割,取出下次分割的基准标号")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" base "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("division")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"base = %d:\\t"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("base"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printPart")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("quickSort")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" base "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 对“基准标号“右侧的一组数值进行递归的切割,以至于将这些数值完整的排序")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("quickSort")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" base "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"算法分析-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法分析-2"}},[t._v("#")]),t._v(" 算法分析")]),t._v(" "),s("p",[t._v("快速排序算法的性能")]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("参数")]),t._v(" "),s("th",[t._v("结果")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("排序类别")]),t._v(" "),s("td",[t._v("交换排序")])]),t._v(" "),s("tr",[s("td",[t._v("排序方法")]),t._v(" "),s("td",[t._v("快速排序")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度平均情况")]),t._v(" "),s("td",[t._v("O(Nlog2N)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最坏情况")]),t._v(" "),s("td",[t._v("O(N2)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最好情况")]),t._v(" "),s("td",[t._v("O(Nlog2N)")])]),t._v(" "),s("tr",[s("td",[t._v("空间复杂度")]),t._v(" "),s("td",[t._v("O(Nlog2N)")])]),t._v(" "),s("tr",[s("td",[t._v("稳定性")]),t._v(" "),s("td",[t._v("不稳定")])]),t._v(" "),s("tr",[s("td",[t._v("复杂性")]),t._v(" "),s("td",[t._v("较复杂")])])])]),t._v(" "),s("h4",{attrs:{id:"时间复杂度-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度-2"}},[t._v("#")]),t._v(" 时间复杂度")]),t._v(" "),s("p",[t._v("当数据有序时,以第一个关键字为基准分为两个子序列,前一个子序列为空,此时执行效率最差。")]),t._v(" "),s("p",[t._v("而当数据随机分布时,以第一个关键字为基准分为两个子序列,两个子序列的元素个数接近相等,此时执行效率最好。")]),t._v(" "),s("p",[t._v("所以,数据越随机分布时,快速排序性能越好;数据越接近有序,快速排序性能越差。")]),t._v(" "),s("h4",{attrs:{id:"空间复杂度"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#空间复杂度"}},[t._v("#")]),t._v(" 空间复杂度")]),t._v(" "),s("p",[t._v("快速排序在每次分割的过程中,需要 1 个空间存储基准值。而快速排序的大概需要 Nlog2N 次的分割处理,所以占用空间也是 Nlog2N 个。")]),t._v(" "),s("h4",{attrs:{id:"算法稳定性-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法稳定性-2"}},[t._v("#")]),t._v(" 算法稳定性")]),t._v(" "),s("p",[t._v("在快速排序中,相等元素可能会因为分区而交换顺序,所以它是不稳定的算法。")]),t._v(" "),s("h3",{attrs:{id:"示例代码-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#示例代码-2"}},[t._v("#")]),t._v(" 示例代码")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的 Github 测试例"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。")]),t._v(" "),s("h2",{attrs:{id:"插入排序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#插入排序"}},[t._v("#")]),t._v(" 插入排序")]),t._v(" "),s("h3",{attrs:{id:"要点-3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#要点-3"}},[t._v("#")]),t._v(" 要点")]),t._v(" "),s("blockquote",[s("p",[t._v("直接插入排序是一种最简单的"),s("strong",[t._v("插入排序")]),t._v("。")]),t._v(" "),s("p",[s("strong",[t._v("插入排序")]),t._v(":每一趟将一个待排序的记录,按照其关键字的大小插入到有序队列的合适位置里,知道全部插入完成。")])]),t._v(" "),s("h3",{attrs:{id:"算法思想-3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法思想-3"}},[t._v("#")]),t._v(" 算法思想")]),t._v(" "),s("p",[t._v("在讲解直接插入排序之前,先让我们脑补一下我们打牌的过程。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/insert-sort.png",alt:"img"}})]),t._v(" "),s("ul",[s("li",[t._v("先拿一张 5 在手里,")]),t._v(" "),s("li",[t._v("再摸到一张 4,比 5 小,插到 5 前面,")]),t._v(" "),s("li",[t._v("摸到一张 6,嗯,比 5 大,插到 5 后面,")]),t._v(" "),s("li",[t._v("摸到一张 8,比 6 大,插到 6 后面,")]),t._v(" "),s("li",[t._v("。。。")]),t._v(" "),s("li",[t._v("最后一看,我靠,凑到的居然是同花顺,这下牛逼大了。")])]),t._v(" "),s("p",[t._v("以上的过程,其实就是典型的"),s("strong",[t._v("直接插入排序,每次将一个新数据插入到有序队列中的合适位置里")]),t._v("。")]),t._v(" "),s("p",[t._v("很简单吧,接下来,我们要将这个算法转化为编程语言。")]),t._v(" "),s("p",[t._v("假设有一组无序序列 R0, R1, ... , RN-1。")]),t._v(" "),s("ul",[s("li",[t._v("我们先将这个序列中下标为 0 的元素视为元素个数为 1 的有序序列。")]),t._v(" "),s("li",[t._v("然后,我们要依次把 R1, R2, ... , RN-1 插入到这个有序序列中。所以,我们需要一个"),s("strong",[t._v("外部循环")]),t._v(",从下标 1 扫描到 N-1 。")]),t._v(" "),s("li",[t._v("接下来描述插入过程。假设这是要将 Ri 插入到前面有序的序列中。由前面所述,我们可知,插入 Ri 时,前 i-1 个数肯定已经是有序了。")])]),t._v(" "),s("p",[t._v("所以我们需要将 Ri 和 R0 ~ Ri-1 进行比较,确定要插入的合适位置。这就需要一个"),s("strong",[t._v("内部循环")]),t._v(",我们一般是从后往前比较,即从下标 i-1 开始向 0 进行扫描。")]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("insertSort")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 打印第一个元素")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"i = %d:\\t"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printPart")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 第1个数肯定是有序的,从第2个数开始遍历,依次插入有序序列")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 取出第i个数,和前i-1个数比较后,插入合适位置")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 因为前i-1个数都是从小到大的有序序列,所以只要当前比较的数(list[j])比temp大,就把这个数后移一位")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("--")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" temp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"i = %d:\\t"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printPart")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"算法分析-3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法分析-3"}},[t._v("#")]),t._v(" 算法分析")]),t._v(" "),s("p",[s("strong",[t._v("直接插入排序的算法性能")])]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("参数")]),t._v(" "),s("th",[t._v("结果")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("排序类别")]),t._v(" "),s("td",[t._v("插入排序")])]),t._v(" "),s("tr",[s("td",[t._v("排序方法")]),t._v(" "),s("td",[t._v("直接插入排序")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度平均情况")]),t._v(" "),s("td",[t._v("O(N2)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最坏情况")]),t._v(" "),s("td",[t._v("O(N2)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最好情况")]),t._v(" "),s("td",[t._v("O(N)")])]),t._v(" "),s("tr",[s("td",[t._v("空间复杂度")]),t._v(" "),s("td",[t._v("O(1)")])]),t._v(" "),s("tr",[s("td",[t._v("稳定性")]),t._v(" "),s("td",[t._v("稳定")])]),t._v(" "),s("tr",[s("td",[t._v("复杂性")]),t._v(" "),s("td",[t._v("简单")])])])]),t._v(" "),s("h4",{attrs:{id:"时间复杂度-3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度-3"}},[t._v("#")]),t._v(" 时间复杂度")]),t._v(" "),s("p",[t._v("当数据"),s("strong",[t._v("正序")]),t._v("时,执行效率"),s("strong",[t._v("最好")]),t._v(",每次插入都不用移动前面的元素,时间复杂度为 "),s("strong",[t._v("O(N)")]),t._v("。")]),t._v(" "),s("p",[t._v("当数据"),s("strong",[t._v("反序")]),t._v("时,执行效率"),s("strong",[t._v("最差")]),t._v(",每次插入都要前面的元素后移,时间复杂度为 "),s("strong",[t._v("O(N2)")]),t._v("。")]),t._v(" "),s("p",[t._v("所以,"),s("strong",[t._v("数据越接近正序,直接插入排序的算法性能越好")]),t._v("。")]),t._v(" "),s("h4",{attrs:{id:"空间复杂度-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#空间复杂度-2"}},[t._v("#")]),t._v(" 空间复杂度")]),t._v(" "),s("p",[t._v("由直接插入排序算法可知,我们在排序过程中,需要一个临时变量存储要插入的值,所以空间复杂度为 "),s("strong",[t._v("1")]),t._v(" 。")]),t._v(" "),s("h4",{attrs:{id:"算法稳定性-3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法稳定性-3"}},[t._v("#")]),t._v(" 算法稳定性")]),t._v(" "),s("p",[t._v("直接插入排序的过程中,不需要改变相等数值元素的位置,所以它是"),s("strong",[t._v("稳定的")]),t._v("算法。")]),t._v(" "),s("h3",{attrs:{id:"示例代码-3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#示例代码-3"}},[t._v("#")]),t._v(" 示例代码")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的 Github 测试例"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。")]),t._v(" "),s("h2",{attrs:{id:"希尔排序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#希尔排序"}},[t._v("#")]),t._v(" 希尔排序")]),t._v(" "),s("h3",{attrs:{id:"要点-4"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#要点-4"}},[t._v("#")]),t._v(" 要点")]),t._v(" "),s("blockquote",[s("p",[t._v("希尔(Shell)排序又称为"),s("strong",[t._v("缩小增量排序")]),t._v(",它是一种"),s("strong",[t._v("插入排序")]),t._v("。它"),s("strong",[t._v("是直接插入排序算法的一种威力加强版")]),t._v("。")])]),t._v(" "),s("p",[t._v("该方法因 DL.Shell 于 1959 年提出而得名。")]),t._v(" "),s("h3",{attrs:{id:"算法思想-4"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法思想-4"}},[t._v("#")]),t._v(" 算法思想")]),t._v(" "),s("p",[t._v("希尔排序的"),s("strong",[t._v("基本思想")]),t._v("是:")]),t._v(" "),s("p",[t._v("把记录按"),s("strong",[t._v("步长 gap")]),t._v(" 分组,对每组记录采用"),s("strong",[t._v("直接插入排序")]),t._v("方法进行排序。\n随着"),s("strong",[t._v("步长逐渐减小")]),t._v(",所分成的组包含的记录越来越多,当步长的值减小到 "),s("strong",[t._v("1")]),t._v(" 时,整个数据合成为一组,构成一组有序记录,则完成排序。")]),t._v(" "),s("p",[t._v("我们来通过演示图,更深入的理解一下这个过程。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/shell-sort.png",alt:"img"}})]),t._v(" "),s("p",[t._v("在上面这幅图中:")]),t._v(" "),s("p",[t._v("初始时,有一个大小为 10 的无序序列。")]),t._v(" "),s("ul",[s("li",[t._v("在"),s("strong",[t._v("第一趟排序中")]),t._v(",我们不妨设 gap1 = N / 2 = 5,即相隔距离为 5 的元素组成一组,可以分为 5 组。\n"),s("ul",[s("li",[t._v("接下来,按照直接插入排序的方法对每个组进行排序。")])])]),t._v(" "),s("li",[t._v("在** 第二趟排序中**,我们把上次的 gap 缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组。\n"),s("ul",[s("li",[t._v("按照直接插入排序的方法对每个组进行排序。")])])]),t._v(" "),s("li",[t._v("在"),s("strong",[t._v("第三趟排序中")]),t._v(",再次把 gap 缩小一半,即 gap3 = gap2 / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组。\n"),s("ul",[s("li",[t._v("按照直接插入排序的方法对每个组进行排序。此时,"),s("strong",[t._v("排序已经结束")]),t._v("。")])])])]),t._v(" "),s("p",[t._v("需要注意一下的是,图中有两个相等数值的元素 "),s("strong",[t._v("5")]),t._v(" 和 "),s("strong",[t._v("5")]),t._v(" 。我们可以清楚的看到,在排序过程中,"),s("strong",[t._v("两个元素位置交换了")]),t._v("。")]),t._v(" "),s("p",[t._v("所以,希尔排序是不稳定的算法。")]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("shellSort")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 把距离为 gap 的元素编为一个组,扫描所有组")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 对距离为 gap 的元素组进行排序")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" temp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"gap = %d:\\t"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printAll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 减小增量")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"算法分析-4"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法分析-4"}},[t._v("#")]),t._v(" 算法分析")]),t._v(" "),s("p",[s("strong",[t._v("希尔排序的算法性能")])]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("参数")]),t._v(" "),s("th",[t._v("结果")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("排序类别")]),t._v(" "),s("td",[t._v("插入排序")])]),t._v(" "),s("tr",[s("td",[t._v("排序方法")]),t._v(" "),s("td",[t._v("希尔排序")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度平均情况")]),t._v(" "),s("td",[t._v("O(Nlog2N)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最坏情况")]),t._v(" "),s("td",[t._v("O(N1.5)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最好情况")]),t._v(" "),s("td")]),t._v(" "),s("tr",[s("td",[t._v("空间复杂度")]),t._v(" "),s("td",[t._v("O(1)")])]),t._v(" "),s("tr",[s("td",[t._v("稳定性")]),t._v(" "),s("td",[t._v("不稳定")])]),t._v(" "),s("tr",[s("td",[t._v("复杂性")]),t._v(" "),s("td",[t._v("较复杂")])])])]),t._v(" "),s("h4",{attrs:{id:"时间复杂度-4"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度-4"}},[t._v("#")]),t._v(" 时间复杂度")]),t._v(" "),s("p",[t._v("步长的选择是希尔排序的重要部分。只要最终步长为 1 任何步长序列都可以工作。")]),t._v(" "),s("p",[t._v("算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为 1 进行排序。当步长为 1 时,算法变为插入排序,这就保证了数据一定会被排序。")]),t._v(" "),s("p",[t._v("Donald Shell 最初建议步长选择为 N/2 并且对步长取半直到步长达到 1。虽然这样取可以比 O(N2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长 5 进行了排序然后再以步长 3 进行排序,那么该数列不仅是以步长 3 有序,而且是以步长 5 有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。")]),t._v(" "),s("p",[t._v("已知的最好步长序列是由 Sedgewick 提出的(1, 5, 19, 41, 109,...),该序列的项来自这两个算式。")]),t._v(" "),s("p",[t._v("这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长序列的希尔排序比插入排序和堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。")]),t._v(" "),s("h4",{attrs:{id:"算法稳定性-4"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法稳定性-4"}},[t._v("#")]),t._v(" 算法稳定性")]),t._v(" "),s("p",[t._v("由上文的"),s("strong",[t._v("希尔排序算法演示图")]),t._v("即可知,希尔排序中相等数据可能会交换位置,所以希尔排序是"),s("strong",[t._v("不稳定")]),t._v("的算法。")]),t._v(" "),s("h4",{attrs:{id:"直接插入排序和希尔排序的比较"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#直接插入排序和希尔排序的比较"}},[t._v("#")]),t._v(" 直接插入排序和希尔排序的比较")]),t._v(" "),s("ul",[s("li",[t._v("直接插入排序是"),s("strong",[t._v("稳定的")]),t._v(";而希尔排序是"),s("strong",[t._v("不稳定")]),t._v("的。")]),t._v(" "),s("li",[t._v("直接插入排序更适合于原始记录基本"),s("strong",[t._v("有序")]),t._v("的集合。")]),t._v(" "),s("li",[t._v("希尔排序的比较次数和移动次数都要比直接插入排序少,当 N 越大时,效果越明显。")]),t._v(" "),s("li",[t._v("在希尔排序中,增量序列 gap 的取法必须满足:**最后一个步长必须是 1 。 **")]),t._v(" "),s("li",[t._v("直接插入排序也"),s("strong",[t._v("适用于链式存储结构")]),t._v(";希尔排序"),s("strong",[t._v("不适用于链式结构")]),t._v("。")])]),t._v(" "),s("h3",{attrs:{id:"示例代码-4"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#示例代码-4"}},[t._v("#")]),t._v(" 示例代码")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的 Github 测试例"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。")]),t._v(" "),s("h2",{attrs:{id:"简单选择排序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#简单选择排序"}},[t._v("#")]),t._v(" 简单选择排序")]),t._v(" "),s("h3",{attrs:{id:"要点-5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#要点-5"}},[t._v("#")]),t._v(" 要点")]),t._v(" "),s("blockquote",[s("p",[t._v("简单选择排序是一种"),s("strong",[t._v("选择排序")]),t._v("。")]),t._v(" "),s("p",[s("strong",[t._v("选择排序")]),t._v(":每趟从待排序的记录中选出关键字最小的记录,顺序放在已排序的记录序列末尾,直到全部排序结束为止。")])]),t._v(" "),s("h3",{attrs:{id:"算法思想-5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法思想-5"}},[t._v("#")]),t._v(" 算法思想")]),t._v(" "),s("ol",[s("li",[t._v("从待排序序列中,找到关键字最小的元素;")]),t._v(" "),s("li",[t._v("如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换;")]),t._v(" "),s("li",[t._v("从余下的 N - 1 个元素中,找出关键字最小的元素,重复 1、2 步,直到排序结束。")])]),t._v(" "),s("p",[t._v("如图所示,每趟排序中,将当前**第 i 小的元素放在位置 i **上。")]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/selection-sort.png",alt:"img"}})]),t._v(" "),s("h3",{attrs:{id:"算法分析-5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法分析-5"}},[t._v("#")]),t._v(" 算法分析")]),t._v(" "),s("p",[s("strong",[t._v("简单选择排序算法的性能")])]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("参数")]),t._v(" "),s("th",[t._v("结果")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("排序类别")]),t._v(" "),s("td",[t._v("选择排序")])]),t._v(" "),s("tr",[s("td",[t._v("排序方法")]),t._v(" "),s("td",[t._v("简单选择排序")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度平均情况")]),t._v(" "),s("td",[t._v("O(N2)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最坏情况")]),t._v(" "),s("td",[t._v("O(N2)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最好情况")]),t._v(" "),s("td",[t._v("O(N2)")])]),t._v(" "),s("tr",[s("td",[t._v("空间复杂度")]),t._v(" "),s("td",[t._v("O(1)")])]),t._v(" "),s("tr",[s("td",[t._v("稳定性")]),t._v(" "),s("td",[t._v("不稳定")])]),t._v(" "),s("tr",[s("td",[t._v("复杂性")]),t._v(" "),s("td",[t._v("简单")])])])]),t._v(" "),s("h4",{attrs:{id:"时间复杂度-5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度-5"}},[t._v("#")]),t._v(" 时间复杂度")]),t._v(" "),s("p",[t._v("简单选择排序的比较次数与序列的初始排序无关。 假设待排序的序列有 "),s("strong",[t._v("N")]),t._v(" 个元素,则**比较次数总是 N (N - 1) / 2 **。")]),t._v(" "),s("p",[t._v("而移动次数与序列的初始排序有关。当序列正序时,移动次数最少,为 "),s("strong",[t._v("0")]),t._v(".")]),t._v(" "),s("p",[t._v("当序列反序时,移动次数最多,为 "),s("strong",[t._v("3N (N - 1) / 2")]),t._v("。")]),t._v(" "),s("p",[t._v("所以,综合以上,简单排序的时间复杂度为 "),s("strong",[t._v("O(N2)")]),t._v("。")]),t._v(" "),s("h4",{attrs:{id:"空间复杂度-3"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#空间复杂度-3"}},[t._v("#")]),t._v(" 空间复杂度")]),t._v(" "),s("p",[t._v("简单选择排序需要占用一个临时空间,在交换数值时使用。")]),t._v(" "),s("h3",{attrs:{id:"示例代码-5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#示例代码-5"}},[t._v("#")]),t._v(" 示例代码")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的 Github 测试例"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。")]),t._v(" "),s("h2",{attrs:{id:"堆排序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#堆排序"}},[t._v("#")]),t._v(" 堆排序")]),t._v(" "),s("h3",{attrs:{id:"要点-6"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#要点-6"}},[t._v("#")]),t._v(" 要点")]),t._v(" "),s("p",[t._v("在介绍堆排序之前,首先需要说明一下,堆是个什么玩意儿。")]),t._v(" "),s("p",[s("strong",[t._v("堆")]),t._v("是一棵"),s("strong",[t._v("顺序存储")]),t._v("的"),s("strong",[t._v("完全二叉树")]),t._v("。")]),t._v(" "),s("p",[t._v("其中每个结点的关键字都"),s("strong",[t._v("不大于")]),t._v("其孩子结点的关键字,这样的堆称为"),s("strong",[t._v("小根堆")]),t._v("。\n其中每个结点的关键字都"),s("strong",[t._v("不小于")]),t._v("其孩子结点的关键字,这样的堆称为"),s("strong",[t._v("大根堆")]),t._v("。\n举例来说,对于 n 个元素的序列 {R0, R1, ... , Rn} 当且仅当满足下列关系之一时,称之为堆:")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("Ri <= R2i+1 且 Ri <= R2i+2 (小根堆)")])]),t._v(" "),s("li",[s("strong",[t._v("Ri >= R2i+1 且 Ri >= R2i+2 (大根堆)")])])]),t._v(" "),s("p",[t._v("其中 i=1,2,…,n/2 向下取整;")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/heap-sort.png",alt:"img"}})]),t._v(" "),s("p",[t._v("如上图所示,序列 R{3, 8,15, 31, 25} 是一个典型的小根堆。")]),t._v(" "),s("p",[t._v("堆中有两个父结点,元素 3 和元素 8。")]),t._v(" "),s("p",[t._v("元素 3 在数组中以 R[0] 表示,它的左孩子结点是 R[1],右孩子结点是 R[2]。")]),t._v(" "),s("p",[t._v("元素 8 在数组中以 R[1] 表示,它的左孩子结点是 R[3],右孩子结点是 R[4],它的父结点是 R[0]。可以看出,它们"),s("strong",[t._v("满足以下规律")]),t._v(":")]),t._v(" "),s("p",[t._v("设当前元素在数组中以 "),s("strong",[t._v("R[i]")]),t._v(" 表示,那么,")]),t._v(" "),s("ul",[s("li",[t._v("它的"),s("strong",[t._v("左孩子结点")]),t._v("是:"),s("strong",[t._v("R[2*i+1]")]),t._v(";")]),t._v(" "),s("li",[t._v("它的"),s("strong",[t._v("右孩子结点")]),t._v("是:"),s("strong",[t._v("R[2*i+2]")]),t._v(";")]),t._v(" "),s("li",[t._v("它的"),s("strong",[t._v("父结点")]),t._v("是:"),s("strong",[t._v("R[(i-1)/2]")]),t._v(";")]),t._v(" "),s("li",[t._v("R[i] <= R[2*i+1] 且 R[i] <= R[2i+2]。")])]),t._v(" "),s("h3",{attrs:{id:"算法思想-6"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法思想-6"}},[t._v("#")]),t._v(" 算法思想")]),t._v(" "),s("ul",[s("li",[t._v("首先,按堆的定义将数组 R[0..n]调整为堆(这个过程称为创建初始堆),交换 R[0]和 R[n];")]),t._v(" "),s("li",[t._v("然后,将 R[0..n-1]调整为堆,交换 R[0]和 R[n-1];")]),t._v(" "),s("li",[t._v("如此反复,直到交换了 R[0]和 R[1]为止。")])]),t._v(" "),s("p",[t._v("以上思想可归纳为两个操作:")]),t._v(" "),s("ol",[s("li",[t._v("根据初始数组去"),s("strong",[t._v("构造初始堆")]),t._v("(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。")]),t._v(" "),s("li",[t._v("每次"),s("strong",[t._v("交换第一个和最后一个元素,输出最后一个元素")]),t._v("(最大值),然后把剩下元素"),s("strong",[t._v("重新调整")]),t._v("为大根堆。")])]),t._v(" "),s("p",[t._v("当输出完最后一个元素后,这个数组已经是按照从小到大的顺序排列了。")]),t._v(" "),s("p",[t._v("先通过详细的实例图来看一下,如何构建初始堆。")]),t._v(" "),s("p",[t._v("设有一个无序序列 { 1, 3,4, 5, 2, 6, 9, 7, 8, 0 }。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/heap-sort-02.png",alt:"img"}})]),t._v(" "),s("p",[t._v("构造了初始堆后,我们来看一下完整的堆排序处理:")]),t._v(" "),s("p",[t._v("还是针对前面提到的无序序列 { 1,3, 4, 5, 2, 6, 9, 7, 8, 0 } 来加以说明。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/heap-sort-03.png",alt:"img"}})]),t._v(" "),s("p",[t._v("相信,通过以上两幅图,应该能很直观的演示堆排序的操作处理。")]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HeapAdjust")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" parent"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("parent"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// temp保存当前父节点")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" child "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" parent "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 先获得左孩子")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("child "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("child "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("child"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("child "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n child"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 如果父结点的值已经大于孩子结点的值,则直接结束")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("child"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("break")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 把孩子结点的值赋给父结点")]),t._v("\n array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("parent"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("child"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 选取孩子结点的左孩子结点,继续向下筛选")]),t._v("\n parent "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" child"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n child "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" child "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("parent"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" temp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("heapSort")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 循环建立初始堆")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("--")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HeapAdjust")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 进行n-1次循环,完成排序")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("--")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 最后一个元素和第一元素进行交换")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" temp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" temp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 筛选 R[0] 结点,得到i-1个结点的堆")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HeapAdjust")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"第 %d 趟: \\t"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printPart")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"算法分析-6"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法分析-6"}},[t._v("#")]),t._v(" 算法分析")]),t._v(" "),s("p",[s("strong",[t._v("堆排序算法的总体情况")])]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("参数")]),t._v(" "),s("th",[t._v("结果")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("排序类别")]),t._v(" "),s("td",[t._v("选择排序")])]),t._v(" "),s("tr",[s("td",[t._v("排序方法")]),t._v(" "),s("td",[t._v("堆排序")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度平均情况")]),t._v(" "),s("td",[t._v("O(nlog2n)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最坏情况")]),t._v(" "),s("td",[t._v("O(nlog2n)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最好情况")]),t._v(" "),s("td",[t._v("O(nlog2n)")])]),t._v(" "),s("tr",[s("td",[t._v("空间复杂度")]),t._v(" "),s("td",[t._v("O(1)")])]),t._v(" "),s("tr",[s("td",[t._v("稳定性")]),t._v(" "),s("td",[t._v("不稳定")])]),t._v(" "),s("tr",[s("td",[t._v("复杂性")]),t._v(" "),s("td",[t._v("较复杂")])])])]),t._v(" "),s("h4",{attrs:{id:"时间复杂度-6"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度-6"}},[t._v("#")]),t._v(" 时间复杂度")]),t._v(" "),s("p",[t._v("堆的存储表示是"),s("strong",[t._v("顺序的")]),t._v("。因为堆所对应的二叉树为完全二叉树,而完全二叉树通常采用顺序存储方式。")]),t._v(" "),s("p",[t._v("当想得到一个序列中第 "),s("strong",[t._v("k")]),t._v(" 个最小的元素之前的部分排序序列,最好采用堆排序。")]),t._v(" "),s("p",[t._v("因为堆排序的时间复杂度是 "),s("strong",[t._v("O(n+klog2n)")]),t._v(",若 "),s("strong",[t._v("k ≤ n/log2n")]),t._v(",则可得到的时间复杂度为 "),s("strong",[t._v("O(n)")]),t._v("。")]),t._v(" "),s("h4",{attrs:{id:"算法稳定性-5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法稳定性-5"}},[t._v("#")]),t._v(" 算法稳定性")]),t._v(" "),s("p",[t._v("堆排序是一种"),s("strong",[t._v("不稳定")]),t._v("的排序方法。")]),t._v(" "),s("p",[t._v("因为在堆的调整过程中,关键字进行比较和交换所走的是该结点到叶子结点的一条路径,")]),t._v(" "),s("p",[t._v("因此对于相同的关键字就可能出现排在后面的关键字被交换到前面来的情况。")]),t._v(" "),s("h3",{attrs:{id:"示例代码-6"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#示例代码-6"}},[t._v("#")]),t._v(" 示例代码")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的 Github 测试例"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。")]),t._v(" "),s("h2",{attrs:{id:"归并排序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#归并排序"}},[t._v("#")]),t._v(" 归并排序")]),t._v(" "),s("h3",{attrs:{id:"要点-7"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#要点-7"}},[t._v("#")]),t._v(" 要点")]),t._v(" "),s("blockquote",[s("p",[t._v("归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用**分治法(Divide and Conquer)**的一个非常典型的应用。")]),t._v(" "),s("p",[t._v("将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为"),s("strong",[t._v("二路归并")]),t._v("。")])]),t._v(" "),s("h3",{attrs:{id:"算法思想-7"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法思想-7"}},[t._v("#")]),t._v(" 算法思想")]),t._v(" "),s("p",[t._v("将待排序序列 R[0...n-1] 看成是 n 个长度为 1 的有序序列,将相邻的有序表成对归并,得到 n/2 个长度为 2 的有序表;将这些有序序列再次归并,得到 n/4 个长度为 4 的有序序列;如此反复进行下去,最后得到一个长度为 n 的有序序列。")]),t._v(" "),s("p",[t._v("综上可知:")]),t._v(" "),s("p",[t._v("归并排序其实要做两件事:")]),t._v(" "),s("ul",[s("li",[t._v("“分解”——将序列每次"),s("strong",[t._v("折半划分")]),t._v("。")]),t._v(" "),s("li",[t._v("“合并”——将划分后的序列段"),s("strong",[t._v("两两合并后排序")]),t._v("。")])]),t._v(" "),s("p",[t._v("我们先来考虑第二步,"),s("strong",[t._v("如何合并")]),t._v("?")]),t._v(" "),s("p",[t._v("在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。")]),t._v(" "),s("p",[t._v("这两个有序序列段分别为 R[low, mid] 和 R[mid+1, high]。")]),t._v(" "),s("p",[t._v("先将他们合并到一个局部的"),s("strong",[t._v("暂存数组")]),t._v("R2 中,带合并完成后再将 R2 复制回 R 中。")]),t._v(" "),s("p",[t._v("为了方便描述,我们称 R[low, mid] 第一段,R[mid+1, high] 为第二段。")]),t._v(" "),s("p",[t._v("每次从两个段中取出一个记录进行关键字的比较,将较小者放入 R2 中。最后将各段中余下的部分直接复制到 R2 中。")]),t._v(" "),s("p",[t._v("经过这样的过程,R2 已经是一个有序的序列,再将其复制回 R 中,一次合并排序就完成了。")]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Merge")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" low"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" mid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" high"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" low"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// i是第一段序列的下标")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// j是第二段序列的下标")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" k "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// k是临时存放合并序列的下标")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" array2 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("high "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// array2是临时合并序列")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 扫描第一段和第二段序列,直到有一个扫描结束")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" high"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("k"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n k"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("k"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n j"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n k"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 若第一段序列还没扫描完,将其全部复制到合并序列")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" mid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("k"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n k"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 若第二段序列还没扫描完,将其全部复制到合并序列")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" high"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("k"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n j"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n k"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 将合并序列复制到原始序列中")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("k "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" low"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" high"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" k"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("k"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("掌握了合并的方法,接下来,让我们来了解"),s("strong",[t._v("如何分解")]),t._v("。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/merge-sort.png",alt:"img"}})]),t._v(" "),s("p",[t._v("在某趟归并中,设各子表的长度为 "),s("strong",[t._v("gap")]),t._v(",则归并前 R[0...n-1] 中共有 "),s("strong",[t._v("n/gap")]),t._v(" 个有序的子表:"),s("code",[t._v("R[0...gap-1]")]),t._v(", "),s("code",[t._v("R[gap...2*gap-1]")]),t._v(", ... , "),s("code",[t._v("R[(n/gap)*gap ... n-1]")]),t._v("。")]),t._v(" "),s("p",[t._v("调用 Merge "),s("strong",[t._v("将相邻的子表归并")]),t._v("时,必须对表的特殊情况进行特殊处理。")]),t._v(" "),s("p",[t._v("若子表个数为奇数,则最后一个子表无须和其他子表归并(即本趟处理轮空):若子表个数为偶数,则要注意到最后一对子表中后一个子表区间的上限为 n-1。")]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MergePass")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 归并gap长度的两个相邻子表")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Merge")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 余下两个子表,后者长度小于gap")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Merge")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sort")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("MergePass")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"gap = "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('":\\t"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printAll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"算法分析-7"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法分析-7"}},[t._v("#")]),t._v(" 算法分析")]),t._v(" "),s("p",[s("strong",[t._v("归并排序算法的性能")])]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("参数")]),t._v(" "),s("th",[t._v("结果")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("排序类别")]),t._v(" "),s("td",[t._v("归并排序")])]),t._v(" "),s("tr",[s("td",[t._v("排序方法")]),t._v(" "),s("td",[t._v("归并排序")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度平均情况")]),t._v(" "),s("td",[t._v("O(nlog2n)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最坏情况")]),t._v(" "),s("td",[t._v("O(nlog2n)")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最好情况")]),t._v(" "),s("td",[t._v("O(nlog2n)")])]),t._v(" "),s("tr",[s("td",[t._v("空间复杂度")]),t._v(" "),s("td",[t._v("O(n)")])]),t._v(" "),s("tr",[s("td",[t._v("稳定性")]),t._v(" "),s("td",[t._v("稳定")])]),t._v(" "),s("tr",[s("td",[t._v("复杂性")]),t._v(" "),s("td",[t._v("较复杂")])])])]),t._v(" "),s("h4",{attrs:{id:"时间复杂度-7"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度-7"}},[t._v("#")]),t._v(" 时间复杂度")]),t._v(" "),s("p",[t._v("归并排序的形式就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的可以得出它的时间复杂度是 "),s("strong",[t._v("O(n*log2n)")]),t._v("。")]),t._v(" "),s("h4",{attrs:{id:"空间复杂度-4"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#空间复杂度-4"}},[t._v("#")]),t._v(" 空间复杂度")]),t._v(" "),s("p",[t._v("由前面的算法说明可知,算法处理过程中,需要一个大小为 "),s("strong",[t._v("n")]),t._v(" 的临时存储空间用以保存合并序列。")]),t._v(" "),s("h4",{attrs:{id:"算法稳定性-6"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法稳定性-6"}},[t._v("#")]),t._v(" 算法稳定性")]),t._v(" "),s("p",[t._v("在归并排序中,相等的元素的顺序不会改变,所以它是"),s("strong",[t._v("稳定的")]),t._v("算法。")]),t._v(" "),s("h4",{attrs:{id:"归并排序和堆排序、快速排序的比较"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#归并排序和堆排序、快速排序的比较"}},[t._v("#")]),t._v(" 归并排序和堆排序、快速排序的比较")]),t._v(" "),s("p",[t._v("若从空间复杂度来考虑:首选堆排序,其次是快速排序,最后是归并排序。")]),t._v(" "),s("p",[t._v("若从稳定性来考虑,应选取归并排序,因为堆排序和快速排序都是不稳定的。")]),t._v(" "),s("p",[t._v("若从平均情况下的排序速度考虑,应该选择快速排序。")]),t._v(" "),s("h3",{attrs:{id:"示例代码-7"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#示例代码-7"}},[t._v("#")]),t._v(" 示例代码")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的 Github 测试例"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。")]),t._v(" "),s("h2",{attrs:{id:"基数排序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#基数排序"}},[t._v("#")]),t._v(" 基数排序")]),t._v(" "),s("h3",{attrs:{id:"要点-8"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#要点-8"}},[t._v("#")]),t._v(" 要点")]),t._v(" "),s("p",[t._v("基数排序与本系列前面讲解的七种排序方法都不同,它"),s("strong",[t._v("不需要比较关键字的大小")]),t._v("。")]),t._v(" "),s("p",[t._v("它是根据关键字中各位的值,通过对排序的 N 个元素进行若干趟“分配”与“收集”来实现排序的。")]),t._v(" "),s("p",[t._v("不妨通过一个具体的实例来展示一下,基数排序是如何进行的。")]),t._v(" "),s("p",[t._v("设有一个初始序列为: R {50, 123, 543, 187, 49, 30,0, 2, 11, 100}。")]),t._v(" "),s("p",[t._v("我们知道,任何一个阿拉伯数,它的各个位数上的基数都是以 0~9 来表示的。")]),t._v(" "),s("p",[t._v("所以我们不妨把 0~9 视为 10 个桶。")]),t._v(" "),s("p",[t._v("我们先根据序列的个位数的数字来进行分类,将其分到指定的桶中。例如:R[0] = 50,个位数上是 0,将这个数存入编号为 0 的桶中。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/radix-sort.png",alt:"img"}})]),t._v(" "),s("p",[t._v("分类后,我们在从各个桶中,将这些数按照从编号 0 到编号 9 的顺序依次将所有数取出来。")]),t._v(" "),s("p",[t._v("这时,得到的序列就是个位数上呈递增趋势的序列。")]),t._v(" "),s("p",[t._v("按照个位数排序: {50, 30, 0, 100, 11, 2, 123,543, 187, 49}。")]),t._v(" "),s("p",[t._v("接下来,可以对十位数、百位数也按照这种方法进行排序,最后就能得到排序完成的序列。")]),t._v(" "),s("h3",{attrs:{id:"算法分析-8"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法分析-8"}},[t._v("#")]),t._v(" 算法分析")]),t._v(" "),s("p",[s("strong",[t._v("基数排序的性能")])]),t._v(" "),s("table",[s("thead",[s("tr",[s("th",[t._v("参数")]),t._v(" "),s("th",[t._v("结果")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("排序类别")]),t._v(" "),s("td",[t._v("基数排序")])]),t._v(" "),s("tr",[s("td",[t._v("排序方法")]),t._v(" "),s("td",[t._v("基数排序")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度平均情况")]),t._v(" "),s("td",[t._v("O(d(n+r))")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最坏情况")]),t._v(" "),s("td",[t._v("O(d(n+r))")])]),t._v(" "),s("tr",[s("td",[t._v("时间复杂度最好情况")]),t._v(" "),s("td",[t._v("O(d(n+r))")])]),t._v(" "),s("tr",[s("td",[t._v("空间复杂度")]),t._v(" "),s("td",[t._v("O(n+r)")])]),t._v(" "),s("tr",[s("td",[t._v("稳定性")]),t._v(" "),s("td",[t._v("稳定")])]),t._v(" "),s("tr",[s("td",[t._v("复杂性")]),t._v(" "),s("td",[t._v("较复杂")])])])]),t._v(" "),s("h4",{attrs:{id:"时间复杂度-8"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度-8"}},[t._v("#")]),t._v(" 时间复杂度")]),t._v(" "),s("p",[t._v("通过上文可知,假设在基数排序中,r 为基数,d 为位数。则基数排序的时间复杂度为 "),s("strong",[t._v("O(d(n+r))")]),t._v("。")]),t._v(" "),s("p",[t._v("我们可以看出,基数排序的效率和初始序列是否有序没有关联。")]),t._v(" "),s("h4",{attrs:{id:"空间复杂度-5"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#空间复杂度-5"}},[t._v("#")]),t._v(" 空间复杂度")]),t._v(" "),s("p",[t._v("在基数排序过程中,对于任何位数上的基数进行“装桶”操作时,都需要 "),s("strong",[t._v("n+r")]),t._v(" 个临时空间。")]),t._v(" "),s("h4",{attrs:{id:"算法稳定性-7"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法稳定性-7"}},[t._v("#")]),t._v(" 算法稳定性")]),t._v(" "),s("p",[t._v("在基数排序过程中,每次都是将当前位数上相同数值的元素统一“装桶”,并不需要交换位置。所以基数排序是"),s("strong",[t._v("稳定")]),t._v("的算法。")]),t._v(" "),s("h3",{attrs:{id:"示例代码-8"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#示例代码-8"}},[t._v("#")]),t._v(" 示例代码")]),t._v(" "),s("p",[s("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("我的 Github 测试例"),s("OutboundLink")],1)]),t._v(" "),s("p",[t._v("样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。")])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/11.2fec7336.js b/assets/js/11.2fec7336.js new file mode 100644 index 0000000..0f4528e --- /dev/null +++ b/assets/js/11.2fec7336.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{374:function(t,r,_){"use strict";_.r(r);var a=_(15),v=Object(a.a)({},(function(){var t=this,r=t._self._c;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"树和二叉树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#树和二叉树"}},[t._v("#")]),t._v(" 树和二叉树")]),t._v(" "),r("h2",{attrs:{id:"树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#树"}},[t._v("#")]),t._v(" 树")]),t._v(" "),r("h3",{attrs:{id:"什么是树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#什么是树"}},[t._v("#")]),t._v(" 什么是树")]),t._v(" "),r("p",[t._v("在计算机科学中,"),r("strong",[t._v("树")]),t._v("(英语:tree)是一种"),r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E8%B3%87%E6%96%99%E5%9E%8B%E5%88%A5",target:"_blank",rel:"noopener noreferrer"}},[t._v("抽象数据类型"),r("OutboundLink")],1),t._v("(ADT)或是实现这种抽象数据类型的"),r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构"),r("OutboundLink")],1),t._v(",用来模拟具"),r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E6%A8%B9%E7%8B%80%E7%B5%90%E6%A7%8B",target:"_blank",rel:"noopener noreferrer"}},[t._v("有树状结构"),r("OutboundLink")],1),t._v("性质的数据集合。它是由 n(n>0)个有限节点组成一个具有层次关系的"),r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E9%9B%86%E5%90%88",target:"_blank",rel:"noopener noreferrer"}},[t._v("集合"),r("OutboundLink")],1),t._v("。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。")]),t._v(" "),r("p",[t._v("它具有以下的特点:")]),t._v(" "),r("ul",[r("li",[t._v("每个节点都只有有限个子节点或无子节点。")]),t._v(" "),r("li",[t._v("树有且仅有一个根节点。")]),t._v(" "),r("li",[t._v("根节点没有父节点;非根节点有且仅有一个父节点。")]),t._v(" "),r("li",[t._v("每个非根节点可以分为多个不相交的子树。")]),t._v(" "),r("li",[t._v("树里面没有环路。")])]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220403163620.png",alt:""}})]),t._v(" "),r("h3",{attrs:{id:"树的术语"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#树的术语"}},[t._v("#")]),t._v(" 树的术语")]),t._v(" "),r("ul",[r("li",[r("strong",[t._v("节点的度")]),t._v(":一个节点含有的子树的个数称为该节点的度;")]),t._v(" "),r("li",[r("strong",[t._v("树的度")]),t._v(":一棵树中,最大的节点度称为树的度;")]),t._v(" "),r("li",[r("strong",[t._v("叶子节点")]),t._v("或"),r("strong",[t._v("终端节点")]),t._v(":度为零的节点;")]),t._v(" "),r("li",[r("strong",[t._v("非终端节点")]),t._v("或"),r("strong",[t._v("分支节点")]),t._v(":度不为零的节点;")]),t._v(" "),r("li",[r("strong",[t._v("父节点")]),t._v(":若一个节点含有子节点,则这个节点称为其子节点的父节点;")]),t._v(" "),r("li",[r("strong",[t._v("子节点")]),t._v(":一个节点含有的子树的根节点称为该节点的子节点;")]),t._v(" "),r("li",[r("strong",[t._v("兄弟节点")]),t._v(":具有相同父节点的节点互称为兄弟节点;")]),t._v(" "),r("li",[r("strong",[t._v("堂兄弟节点")]),t._v(":父节点在同一层的节点互为堂兄弟;")]),t._v(" "),r("li",[r("strong",[t._v("节点的祖先")]),t._v(":从根到该节点所经分支上的所有节点;")]),t._v(" "),r("li",[r("strong",[t._v("子孙")]),t._v(":以某节点为根的子树中任一节点都称为该节点的子孙。")]),t._v(" "),r("li",[r("strong",[t._v("森林")]),t._v(":由 m(m>=0)棵互不相交的树的集合称为森林;")])]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220403164732.png",alt:""}})]),t._v(" "),r("ul",[r("li",[r("strong",[t._v("节点的高度")]),t._v(":节点到叶子节点的最长路径。高度是从下往上度量。")]),t._v(" "),r("li",[r("strong",[t._v("节点的深度")]),t._v(":根节点到该节点的最长路径。深度是从上往下度量。")]),t._v(" "),r("li",[r("strong",[t._v("节点的层次")]),t._v(":节点的深度 + 1。")]),t._v(" "),r("li",[r("strong",[t._v("树的高度")]),t._v(":根节点的高度。")])]),t._v(" "),r("h3",{attrs:{id:"树的性质"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#树的性质"}},[t._v("#")]),t._v(" 树的性质")]),t._v(" "),r("ul",[r("li",[t._v("树中的节点数等于所有节点的度数加 1。")]),t._v(" "),r("li",[t._v("度为 m 的树中第 "),r("code",[t._v("i")]),t._v(" 层上至多有 $$m^{i-1}$$ 个节点($$i ≥ 1$$)。")]),t._v(" "),r("li",[t._v("高度为 h 的 m 次树至多有 $$(m^h-1)/(m-1)$$ 个节点。")]),t._v(" "),r("li",[t._v("具有 n 个节点的 m 次树的最小高度为 $$\\log_m{(n(m-1)+1)}$$ 。")])]),t._v(" "),r("h3",{attrs:{id:"树的种类"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#树的种类"}},[t._v("#")]),t._v(" 树的种类")]),t._v(" "),r("p",[r("strong",[t._v("无序树")]),t._v(":树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为"),r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E8%87%AA%E7%94%B1%E6%A0%91",target:"_blank",rel:"noopener noreferrer"}},[t._v("自由树"),r("OutboundLink")],1),t._v(";")]),t._v(" "),r("p",[r("strong",[t._v("有序树")]),t._v(":树中任意节点的子节点之间有顺序关系,这种树称为有序树;")]),t._v(" "),r("ul",[r("li",[t._v("二叉树:每个节点最多含有两个子树的树称为二叉树;\n"),r("ul",[r("li",[r("strong",[t._v("完全二叉树")]),t._v(":对于一颗二叉树,假设其深度为 d(d>1)。除了第 d 层外,其它各层的节点数目均已达最大值,且第 d 层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;")])])]),t._v(" "),r("li",[r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E6%BB%A1%E4%BA%8C%E5%8F%89%E6%A0%91",target:"_blank",rel:"noopener noreferrer"}},[t._v("满二叉树"),r("OutboundLink")],1),t._v(":所有叶节点都在最底层的完全二叉树;")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91",target:"_blank",rel:"noopener noreferrer"}},[t._v("平衡二叉树"),r("OutboundLink")],1),t._v("("),r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/AVL%E6%A0%91",target:"_blank",rel:"noopener noreferrer"}},[t._v("AVL 树"),r("OutboundLink")],1),t._v("):当且仅当任何节点的两棵子树的高度差不大于 1 的二叉树;")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E6%8E%92%E5%BA%8F%E4%BA%8C%E5%85%83%E6%A8%B9",target:"_blank",rel:"noopener noreferrer"}},[t._v("排序二叉树"),r("OutboundLink")],1),t._v("("),r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%8F%89%E6%9F%A5%E6%89%BE%E6%A0%91",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉查找树"),r("OutboundLink")],1),t._v("(英语:Binary Search Tree)):也称二叉搜索树、有序二叉树;")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E9%9C%8D%E5%A4%AB%E6%9B%BC%E6%A0%91",target:"_blank",rel:"noopener noreferrer"}},[t._v("霍夫曼树"),r("OutboundLink")],1),t._v(":"),r("a",{attrs:{href:"https://zh.wikipedia.org/w/index.php?title=%E5%B8%A6%E6%9D%83%E8%B7%AF%E5%BE%84&action=edit&redlink=1",target:"_blank",rel:"noopener noreferrer"}},[t._v("带权路径"),r("OutboundLink")],1),t._v("最短的二叉树称为哈夫曼树或最优二叉树;")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://zh.wikipedia.org/wiki/B%E6%A0%91",target:"_blank",rel:"noopener noreferrer"}},[t._v("B 树"),r("OutboundLink")],1),t._v(":一种对读写操作进行优化的自平衡的二叉查找树,能够保持数据有序,拥有多于两个子树。")])]),t._v(" "),r("h2",{attrs:{id:"二叉树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉树"}},[t._v("#")]),t._v(" 二叉树")]),t._v(" "),r("p",[t._v("二叉树中的每个节点最多有两个子节点,分别是"),r("strong",[t._v("左子节点")]),t._v("和"),r("strong",[t._v("右子节点")]),t._v("。")]),t._v(" "),r("h3",{attrs:{id:"二叉树的性质"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉树的性质"}},[t._v("#")]),t._v(" 二叉树的性质")]),t._v(" "),r("ol",[r("li",[t._v("二叉树第 i 层上的结点数目最多为 "),r("strong",[t._v("2"),r("sup",[t._v("i-1")])]),t._v(" (i≥1)。")]),t._v(" "),r("li",[t._v("深度为 k 的二叉树至多有 "),r("strong",[t._v("2"),r("sup",[t._v("k")]),t._v("-1")]),t._v(" 个结点(k≥1)。")]),t._v(" "),r("li",[t._v("包含 n 个结点的二叉树的高度至少为 "),r("strong",[t._v("log"),r("sub",[t._v("2")]),t._v("(n+1)")]),t._v("。")]),t._v(" "),r("li",[t._v("在任意一棵二叉树中,若终端结点的个数为 n0,度为 2 的结点数为 n2,则 n0=n2+1。")])]),t._v(" "),r("h3",{attrs:{id:"满二叉树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#满二叉树"}},[t._v("#")]),t._v(" 满二叉树")]),t._v(" "),r("p",[t._v("除了叶子节点之外,每个节点都有左右两个子节点,这种二叉树就叫作"),r("strong",[t._v("满二叉树")]),t._v("。")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220403183927.png",alt:""}})]),t._v(" "),r("h3",{attrs:{id:"完全二叉树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#完全二叉树"}},[t._v("#")]),t._v(" 完全二叉树")]),t._v(" "),r("p",[t._v("叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大,这种二叉树叫作"),r("strong",[t._v("完全二叉树")]),t._v("。")]),t._v(" "),r("p",[t._v("特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220403183640.png",alt:""}})]),t._v(" "),r("p",[t._v("存储一棵二叉树,有两种方法,一种是基于指针或者引用的二叉链式存储法,一种是基于数组的顺序存储法。")]),t._v(" "),r("p",[r("strong",[t._v("二叉链式存储法")])]),t._v(" "),r("p",[t._v("每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针。")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220403212249.png",alt:""}})]),t._v(" "),r("p",[r("strong",[t._v("顺序存储法")])]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220403214627.png",alt:""}})]),t._v(" "),r("p",[t._v("如果节点 X 存储在数组中下标为 i 的位置,下标为 2 _ i 的位置存储的就是左子节点,下标为 2 _ i + 1 的位置存储的就是右子节点。反过来,下标为 i/2 的位置存储就是它的父节点。通过这种方式,我们只要知道根节点存储的位置(一般情况下,为了方便计算子节点,根节点会存储在下标为 1 的位置),这样就可以通过下标计算,把整棵树都串起来。")]),t._v(" "),r("p",[t._v("如果是非完全二叉树,其实会浪费比较多的数组存储空间。所以,如果某棵二叉树是一棵完全二叉树,那用数组存储无疑是最节省内存的一种方式。因为数组的存储方式并不需要像链式存储法那样,要存储额外的左右子节点的指针。这也是 为什么完全二叉树要求最后一层的子节点都靠左的原因。")]),t._v(" "),r("h3",{attrs:{id:"二叉树的遍历"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉树的遍历"}},[t._v("#")]),t._v(" 二叉树的遍历")]),t._v(" "),r("p",[t._v("二叉树的遍历有三种方式:")]),t._v(" "),r("ul",[r("li",[r("strong",[t._v("前序遍历")]),t._v(":对于树中的任意节点来说,先打印这个节点,然后再打印它的左子树,最后打印它的右子树。")]),t._v(" "),r("li",[r("strong",[t._v("中序遍历")]),t._v(":对于树中的任意节点来说,先打印它的左子树,然后再打印它本身,最后打印它的右子树。")]),t._v(" "),r("li",[r("strong",[t._v("后序遍历")]),t._v("是指,对于树中的任意节点来说,先打印它的左子树,然后再打印它的右子树,最后打印这个节点本身。")])]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220404201713.png",alt:""}})]),t._v(" "),r("h2",{attrs:{id:"二叉查找树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉查找树"}},[t._v("#")]),t._v(" 二叉查找树")]),t._v(" "),r("p",[t._v("二叉查找树是二叉树中最常用的一种类型,也叫二叉搜索树。顾名思义,二叉查找树是为了实现快速查找而生的。不过,它不仅仅支持快速查找一个数据,还支持快速插入、删除一个数据。")]),t._v(" "),r("p",[r("strong",[t._v("二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。")])]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220405172359.png",alt:""}})]),t._v(" "),r("h3",{attrs:{id:"二叉查找树的查找"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉查找树的查找"}},[t._v("#")]),t._v(" 二叉查找树的查找")]),t._v(" "),r("p",[t._v("首先,我们看如何在二叉查找树中查找一个节点。我们先取根节点,如果它等于我们要查找的数据,那就返回。如果要查找的数据比根节点的值小,那就在左子树中递归查找;如果要查找的数据比根节点的值大,那就在右子树中递归查找。")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220405172537.png",alt:""}})]),t._v(" "),r("h3",{attrs:{id:"二叉查找树的插入"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉查找树的插入"}},[t._v("#")]),t._v(" 二叉查找树的插入")]),t._v(" "),r("p",[t._v("如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;如果不为空,就再递归遍历右子树,查找插入位置。同理,如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再递归遍历左子树,查找插入位置。")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220405172549.png",alt:""}})]),t._v(" "),r("h3",{attrs:{id:"二叉查找树的删除"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉查找树的删除"}},[t._v("#")]),t._v(" 二叉查找树的删除")]),t._v(" "),r("p",[t._v("第一种情况是,如果要删除的节点没有子节点,我们只需要直接将父节点中,指向要删除节点的指针置为 null。")]),t._v(" "),r("p",[t._v("第二种情况是,如果要删除的节点只有一个子节点(只有左子节点或者右子节点),我们只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220405200219.png",alt:""}})]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220405200234.png",alt:""}})]),t._v(" "),r("p",[t._v("第三种情况是,如果要删除的节点有两个子节点,这就比较复杂了。我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上。然后再删除掉这个最小节点,因为最小节点肯定没有左子节点(如果有左子结点,那就不是最小节点了),所以,我们可以应用上面两条规则来删除这个最小节点。")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220405200456.png",alt:""}})]),t._v(" "),r("h3",{attrs:{id:"二叉查找树的时间复杂度"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉查找树的时间复杂度"}},[t._v("#")]),t._v(" 二叉查找树的时间复杂度")]),t._v(" "),r("p",[t._v("不管操作是插入、删除还是查找,"),r("strong",[t._v("时间复杂度其实都跟树的高度成正比,也就是 O(log n)")]),t._v("。")]),t._v(" "),r("p",[t._v("二叉查找树的形态各式各样。比如这个图中,对于同一组数据,我们构造了三种二叉查找树。它们的查找、插入、删除操作的执行效率都是不一样的。图中第一种二叉查找树,根节点的左右子树极度不平衡,已经退化成了链表,所以查找的时间复杂度就变成了 O(n)。")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220405234630.png",alt:""}})]),t._v(" "),r("h3",{attrs:{id:"为什么需要二叉查找树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#为什么需要二叉查找树"}},[t._v("#")]),t._v(" 为什么需要二叉查找树")]),t._v(" "),r("p",[t._v("第一,哈希表中的数据是无序存储的,如果要输出有序的数据,需要先进行排序。而对于二叉查找树来说,我们只需要中序遍历,就可以在 O(n) 的时间复杂度内,输出有序的数据序列。")]),t._v(" "),r("p",[t._v("第二,哈希表扩容耗时很多,而且当遇到散列冲突时,性能不稳定,尽管二叉查找树的性能不稳定,但是在工程中,我们最常用的平衡二叉查找树的性能非常稳定,时间复杂度稳定在 O(logn)。")]),t._v(" "),r("p",[t._v("第三,笼统地来说,尽管哈希表的查找等操作的时间复杂度是常量级的,但因为哈希冲突的存在,这个常量不一定比 logn 小,所以实际的查找速度可能不一定比 O(logn) 快。加上哈希函数的耗时,也不一定就比平衡二叉查找树的效率高。")]),t._v(" "),r("p",[t._v("第四,哈希表的构造比二叉查找树要复杂,需要考虑的东西很多。比如散列函数的设计、冲突解决办法、扩容、缩容等。平衡二叉查找树只需要考虑平衡性这一个问题,而且这个问题的解决方案比较成熟、固定。")]),t._v(" "),r("p",[t._v("最后,为了避免过多的散列冲突,哈希表装载因子不能太大,特别是基于开放寻址法解决冲突的哈希表,不然会浪费一定的存储空间。")]),t._v(" "),r("h2",{attrs:{id:"参考资料"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法之美"),r("OutboundLink")],1)])])])}),[],!1,null,null,null);r.default=v.exports}}]); \ No newline at end of file diff --git a/assets/js/12.b55fdf6e.js b/assets/js/12.b55fdf6e.js new file mode 100644 index 0000000..0413a2f --- /dev/null +++ b/assets/js/12.b55fdf6e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{376:function(t,a,v){"use strict";v.r(a);var _=v(15),r=Object(_.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"堆"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#堆"}},[t._v("#")]),t._v(" 堆")]),t._v(" "),a("h2",{attrs:{id:"什么是堆"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#什么是堆"}},[t._v("#")]),t._v(" 什么是堆?")]),t._v(" "),a("p",[t._v("堆(Heap)是一个可以被看成近似完全二叉树的数组。")]),t._v(" "),a("ul",[a("li",[a("strong",[t._v("堆是一个完全二叉树")]),t._v("。完全二叉树要求,除了最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列。")]),t._v(" "),a("li",[a("strong",[t._v("堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值")]),t._v("。")])]),t._v(" "),a("p",[t._v("堆可以分为大顶堆和小顶堆。")]),t._v(" "),a("ul",[a("li",[a("p",[t._v("对于每个节点的值都大于等于子树中每个节点值的堆,叫作“"),a("strong",[t._v("大顶堆")]),t._v("”。")])]),t._v(" "),a("li",[a("p",[t._v("对于每个节点的值都小于等于子树中每个节点值的堆,叫作“"),a("strong",[t._v("小顶堆")]),t._v("”。")])])]),t._v(" "),a("h2",{attrs:{id:"如何实现堆"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#如何实现堆"}},[t._v("#")]),t._v(" 如何实现堆")]),t._v(" "),a("p",[t._v("完全二叉树比较适合用数组来存储。用数组来存储完全二叉树是非常节省存储空间的。因为我们不需要存储左右子节点的指针,单纯地通过数组的下标,就可以找到一个节点的左右子节点和父节点。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220311112542.jpg",alt:"img"}})]),t._v(" "),a("p",[t._v("堆常见的操作:")]),t._v(" "),a("ul",[a("li",[t._v("HEAPIFY 建堆:把一个乱序的数组变成堆结构的数组,时间复杂度为 $$O(n)$$。")]),t._v(" "),a("li",[t._v("HEAPPUSH:把一个数值放进已经是堆结构的数组中,并保持堆结构,时间复杂度为 $$O(log N)$$")]),t._v(" "),a("li",[t._v("HEAPPOP:从最大堆中取出最大值或从最小堆中取出最小值,并将剩余的数组保持堆结构,时间复杂度为 $$O(log N)$$。")]),t._v(" "),a("li",[t._v("HEAPSORT:借由 HEAPFY 建堆和 HEAPPOP 堆数组进行排序,时间复杂度为$$ O(N log N)$$,空间复杂度为 $$O(1)$$。")])]),t._v(" "),a("h2",{attrs:{id:"堆的应用场景"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#堆的应用场景"}},[t._v("#")]),t._v(" 堆的应用场景")]),t._v(" "),a("h3",{attrs:{id:"求-top-n"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#求-top-n"}},[t._v("#")]),t._v(" 求 TOP N")]),t._v(" "),a("p",[t._v("堆结构的一个常见应用是建立优先队列(Priority Queue)。")]),t._v(" "),a("p",[t._v("求 Top K 的问题抽象成两类。一类是针对静态数据集合;另一类是针对动态数据集合")]),t._v(" "),a("h3",{attrs:{id:"优先级队列"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#优先级队列"}},[t._v("#")]),t._v(" 优先级队列")]),t._v(" "),a("p",[t._v("在优先级队列中,数据的出队顺序不是先进先出,而是按照优先级来,优先级最高的,最先出队。")]),t._v(" "),a("p",[t._v("堆和优先级队列非常相似:往优先级队列中插入一个元素,就相当于往堆中插入一个元素;从优先级队列中取出优先级最高的元素,就相当于取出堆顶元素。")]),t._v(" "),a("blockquote",[a("p",[t._v("参考:Java 的 "),a("code",[t._v("PriorityQueue")]),t._v(" 类")])]),t._v(" "),a("h3",{attrs:{id:"求中位数"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#求中位数"}},[t._v("#")]),t._v(" 求中位数")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/13.5f9a5cef.js b/assets/js/13.5f9a5cef.js new file mode 100644 index 0000000..dce7a0b --- /dev/null +++ b/assets/js/13.5f9a5cef.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{377:function(t,_,v){"use strict";v.r(_);var r=v(15),e=Object(r.a)({},(function(){var t=this,_=t._self._c;return _("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[_("h1",{attrs:{id:"b-树"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#b-树"}},[t._v("#")]),t._v(" B+树")]),t._v(" "),_("h2",{attrs:{id:"什么是-b-树"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#什么是-b-树"}},[t._v("#")]),t._v(" 什么是 B+树")]),t._v(" "),_("p",[t._v("B+树是在二叉查找树的基础上进行了改造:树中的节点并不存储数据本身,而是只是作为索引。每个叶子节点串在一条链表上,链表中的数据是从小到大有序的。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220311092926.jpg",alt:"img"}})]),t._v(" "),_("p",[t._v("改造之后,如果我们要求某个区间的数据。我们只需要拿区间的起始值,在树中进行查找,当查找到某个叶子节点之后,我们再顺着链表往后遍历,直到链表中的结点数据值大于区间的终止值为止。所有遍历到的数据,就是符合区间值的所有数据。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220311092929.jpg",alt:"img"}})]),t._v(" "),_("p",[t._v("但是,我们要为几千万、上亿的数据构建索引,如果将索引存储在内存中,尽管内存访问的速度非常快,查询的效率非常高,但是,占用的内存会非常多。")]),t._v(" "),_("p",[t._v("比如,我们给一亿个数据构建二叉查找树索引,那索引中会包含大约 1 亿个节点,每个节点假设占用 16 个字节,那就需要大约 1GB 的内存空间。给一张表建立索引,我们需要 1GB 的内存空间。如果我们要给 10 张表建立索引,那对内存的需求是无法满足的。如何解决这个索引占用太多内存的问题呢?")]),t._v(" "),_("p",[t._v("我们可以借助时间换空间的思路,把索引存储在硬盘中,而非内存中。我们都知道,硬盘是一个非常慢速的存储设备。通常内存的访问速度是纳秒级别的,而磁盘访问的速度是毫秒级别的。读取同样大小的数据,从磁盘中读取花费的时间,是从内存中读取所花费时间的上万倍,甚至几十万倍。")]),t._v(" "),_("p",[t._v("这种将索引存储在硬盘中的方案,尽管减少了内存消耗,但是在数据查找的过程中,需要读取磁盘中的索引,因此数据查询效率就相应降低很多。")]),t._v(" "),_("p",[t._v("二叉查找树,经过改造之后,支持区间查找的功能就实现了。不过,为了节省内存,如果把树存储在硬盘中,那么每个节点的读取(或者访问),都对应一次磁盘 IO 操作。树的高度就等于每次查询数据时磁盘 IO 操作的次数。")]),t._v(" "),_("p",[t._v("我们前面讲到,比起内存读写操作,磁盘 IO 操作非常耗时,所以我们优化的重点就是尽量减少磁盘 IO 操作,也就是,尽量降低树的高度。那如何降低树的高度呢?")]),t._v(" "),_("p",[t._v("我们来看下,如果我们把索引构建成 m 叉树,高度是不是比二叉树要小呢?如图所示,给 16 个数据构建二叉树索引,树的高度是 4,查找一个数据,就需要 4 个磁盘 IO 操作(如果根节点存储在内存中,其他结点存储在磁盘中),如果对 16 个数据构建五叉树索引,那高度只有 2,查找一个数据,对应只需要 2 次磁盘操作。如果 m 叉树中的 m 是 100,那对一亿个数据构建索引,树的高度也只是 3,最多只要 3 次磁盘 IO 就能获取到数据。磁盘 IO 变少了,查找数据的效率也就提高了。")]),t._v(" "),_("h2",{attrs:{id:"为什么需要-b-树"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#为什么需要-b-树"}},[t._v("#")]),t._v(" 为什么需要 B+树")]),t._v(" "),_("p",[t._v("关系型数据库中常用 B+ 树作为索引,这是为什么呢?")]),t._v(" "),_("p",[t._v("思考以下经典应用场景")]),t._v(" "),_("ul",[_("li",[t._v("根据某个值查找数据,比如 "),_("code",[t._v("select * from user where id=1234")]),t._v("。")]),t._v(" "),_("li",[t._v("根据区间值来查找某些数据,比如 "),_("code",[t._v("select * from user where id > 1234 and id < 2345")]),t._v("。")])]),t._v(" "),_("p",[t._v("为了提高查询效率,需要使用索引。而对于索引的性能要求,主要考察"),_("strong",[t._v("执行效率和存储空间")]),t._v("。如果让你选择一种数据结构去存储索引,你会如何考虑?")]),t._v(" "),_("p",[t._v("以一些常见数据结构为例:")]),t._v(" "),_("ul",[_("li",[_("strong",[t._v("哈希表")]),t._v(":哈希表的查询性能很好,时间复杂度是 "),_("code",[t._v("O(1)")]),t._v("。但是,哈希表不能支持按照区间快速查找数据。所以,哈希表不能满足我们的需求。")]),t._v(" "),_("li",[_("strong",[t._v("平衡二叉查找树")]),t._v(":尽管平衡二叉查找树查询的性能也很高,时间复杂度是 "),_("code",[t._v("O(logn)")]),t._v("。而且,对树进行中序遍历,我们还可以得到一个从小到大有序的数据序列,但这仍然不足以支持按照区间快速查找数据。")]),t._v(" "),_("li",[_("strong",[t._v("跳表")]),t._v(":跳表是在链表之上加上多层索引构成的。它支持快速地插入、查找、删除数据,对应的时间复杂度是 "),_("code",[t._v("O(logn)")]),t._v("。并且,跳表也支持按照区间快速地查找数据。我们只需要定位到区间起点值对应在链表中的结点,然后从这个结点开始,顺序遍历链表,直到区间终点对应的结点为止,这期间遍历得到的数据就是满足区间值的数据。")])]),t._v(" "),_("p",[t._v("实际上,数据库索引所用到的数据结构跟跳表非常相似,叫作 B+ 树。不过,它是通过二叉查找树演化过来的,而非跳表。B+树的应用场景")]),t._v(" "),_("h2",{attrs:{id:"参考资料"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),_("ul",[_("li",[_("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法之美"),_("OutboundLink")],1)])])])}),[],!1,null,null,null);_.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/14.068c6d73.js b/assets/js/14.068c6d73.js new file mode 100644 index 0000000..1d4a858 --- /dev/null +++ b/assets/js/14.068c6d73.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{378:function(t,a,r){"use strict";r.r(a);var s=r(15),_=Object(s.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"lsm-树"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#lsm-树"}},[t._v("#")]),t._v(" LSM 树")]),t._v(" "),a("h2",{attrs:{id:"什么是-lsm-树"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#什么是-lsm-树"}},[t._v("#")]),t._v(" 什么是 LSM 树")]),t._v(" "),a("p",[t._v("LSM 树具有以下 3 个特点:")]),t._v(" "),a("ol",[a("li",[t._v("将索引分为内存和磁盘两部分,并在内存达到阈值时启动树合并(Merge Trees);")]),t._v(" "),a("li",[t._v("用批量写入代替随机写入,并且用预写日志 WAL 技术(Write AheadLog,预写日志技术)保证内存数据,在系统崩溃后可以被恢复;")]),t._v(" "),a("li",[t._v("数据采取类似日志追加写的方式写入(Log Structured)磁盘,以顺序写的方式提高写\n入效率。")])]),t._v(" "),a("p",[t._v("LSM 树的这些特点,使得它相对于 B+ 树,在写入性能上有大幅提升。所以,许多 NoSQL 系统都使用 LSM 树作为检索引擎,而且还对 LSM 树进行了优化以提升检索性能。")]),t._v(" "),a("p",[t._v("LSM 树就是根据这个思路设计了这样一个机制:当数据写入时,延迟写磁盘,将数据先存放在内存中的树里,进行常规的存储和查询。当内存中的树持续变大达到阈值时,再批量地以块为单位写入磁盘的树中。因此,LSM 树至少需要由两棵树组成,一棵是存储在内存中较小的 C0 树,另一棵是存储在磁盘中较大的 C1 树。")]),t._v(" "),a("h3",{attrs:{id:"如何将内存数据与磁盘数据合并"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#如何将内存数据与磁盘数据合并"}},[t._v("#")]),t._v(" 如何将内存数据与磁盘数据合并")]),t._v(" "),a("p",[t._v("可以参考两个有序链表归并排序的过程,将 C0 树和 C1 树的所有叶子节点中存储的数据,看作是两个有序链表,那滚动合并问题就变成了我们熟悉的两个有序链表的归并问题。不过由于涉及磁盘操作,那为了提高写入效率和检索效率,我们还需要针对磁盘的特性,在一些归并细节上进行优化。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220316105440.png",alt:"img"}})]),t._v(" "),a("p",[t._v("由于磁盘具有顺序读写效率高的特性,因此,为了提高 C1 树中节点的读写性能,除了根节点以外的节点都要尽可能地存放到连续的块中,让它们能作为一个整体单位来读写。这种包含多个节点的块就叫作多页块(Multi-Pages Block)。")]),t._v(" "),a("p",[t._v("第一步,以多页块为单位,将 C1 树的当前叶子节点从前往后读入内存。读入内存的多页块,叫作清空块(Emptying Block),意思是处理完以后会被清空。")]),t._v(" "),a("p",[t._v("第二步,将 C0 树的叶子节点和清空块中的数据进行归并排序,把归并的结果写入内存的一个新块中,叫作填充块(Filling Block)。")]),t._v(" "),a("p",[t._v("第三步,如果填充块写满了,我们就要将填充块作为新的叶节点集合顺序写入磁盘。这个时候,如果 C0 树的叶子节点和清空块都没有遍历完,我们就继续遍历归并,将数据写入新的填充块。如果清空块遍历完了,我们就去 C1 树中顺序读取新的多页块,加载到清空块中。")]),t._v(" "),a("p",[t._v("第四步,重复第三步,直到遍历完 C0 树和 C1 树的所有叶子节点,并将所有的归并结果写入到磁盘。这个时候,我们就可以同时删除 C0 树和 C1 树中被处理过的叶子节点。这样就完成了滚动归并的过程。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220316110736.png",alt:"img"}})]),t._v(" "),a("h3",{attrs:{id:"lsm-树是如何检索"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#lsm-树是如何检索"}},[t._v("#")]),t._v(" LSM 树是如何检索")]),t._v(" "),a("p",[t._v("因为同时存在 C0 和 C1 树,所以要查询一个 key 时,我们会先到 C0 树中查询。如果查询到了则直接返回;如过没有查询到,则查询 C1 树。")]),t._v(" "),a("p",[t._v("需要注意一种特殊情况:删除操作。假设某数据在 C0 树中被删除了,但是在 C1 树中仍存在。这此时查询时,可以在 C1 树中查到这个 key,这其实是过期数据了,如何应对这种情况呢?对于被删除的数据,可以将这些数据的 key 插入到 C0 树中,并标记一个删除标志。如果查到了一个带着删除标志的 key,就直接返回查询失败。")]),t._v(" "),a("h2",{attrs:{id:"为什么需要-lsm-树"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#为什么需要-lsm-树"}},[t._v("#")]),t._v(" 为什么需要 LSM 树")]),t._v(" "),a("p",[t._v("在关系型数据库中,通常使用 B+ 树作为索引。B+ 树的数据都存储在叶子节点中,而叶子节点一般都存储在磁盘中。因此,每次插入的新数据都需要随机写入磁盘,而随机写入的性能非常慢。如果是一个日志系统,每秒钟要写入上千条甚至上万条数据,这样的磁盘操作代价会使得系统性能急剧下降,甚至无法使用。")]),t._v(" "),a("p",[t._v("操作系统对磁盘的读写是以块为单位的,我们能否以块为单位写入,而不是每次插入一个数据都要随机写入磁盘呢?这样是不是就可以大幅度减少写入操作了呢?解决方案就是:"),a("strong",[t._v("LSM 树")]),t._v("(Log Structured Merge Trees)。")]),t._v(" "),a("h2",{attrs:{id:"wal-技术"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#wal-技术"}},[t._v("#")]),t._v(" WAL 技术")]),t._v(" "),a("p",[t._v("LSM 树至少需要由两棵树组成,一棵是存储在内存中较小的 C0 树,另一棵是存储在磁盘中较大的 C1 树。")]),t._v(" "),a("p",[t._v("如果机器断电或系统崩溃了,那内存中还未写入磁盘的数据岂不就永远丢失了?这种情况我们该如何解决呢?")]),t._v(" "),a("p",[t._v("为了保证内存中的数据在系统崩溃后能恢复,可以使用 WAL 技术(Write Ahead Log,预写日志技术)将数据第一时间高效写入磁盘进行备份。")]),t._v(" "),a("p",[t._v("WAL 技术保存和恢复数据的具体步骤如下:")]),t._v(" "),a("ol",[a("li",[t._v("内存中的程序在处理数据时,会先将对数据的修改作为一条记录,顺序写入磁盘的 log 文件作为备份。由于磁盘文件的顺序追加写入效率很高,因此许多应用场景都可以接受这种备份处理。")]),t._v(" "),a("li",[t._v("在数据写入 log 文件后,备份就成功了。接下来,该数据就可以长期驻留在内存中了。")]),t._v(" "),a("li",[t._v("系统会周期性地检查内存中的数据是否都被处理完了(比如,被删除或者写入磁盘),并且生成对应的检查点(Check Point)记录在磁盘中。然后,我们就可以随时删除被处理完的数据了。这样一来,log 文件就不会无限增长了。")]),t._v(" "),a("li",[t._v("系统崩溃重启,我们只需要从磁盘中读取检查点,就能知道最后一次成功处理的数据在 log 文件中的位置。接下来,我们就可以把这个位置之后未被处理的数据,从 log 文件中读出,然后重新加载到内存中。")])]),t._v(" "),a("p",[a("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220316104837.png",alt:"img"}})]),t._v(" "),a("h2",{attrs:{id:"参考资料"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),a("ul",[a("li",[a("a",{attrs:{href:"https://time.geekbang.org/column/intro/100048401",target:"_blank",rel:"noopener noreferrer"}},[t._v("检索技术核心 20 讲"),a("OutboundLink")],1)])])])}),[],!1,null,null,null);a.default=_.exports}}]); \ No newline at end of file diff --git a/assets/js/15.70be4a8f.js b/assets/js/15.70be4a8f.js new file mode 100644 index 0000000..65800d0 --- /dev/null +++ b/assets/js/15.70be4a8f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{380:function(t,r,a){"use strict";a.r(r);var s=a(15),e=Object(s.a)({},(function(){var t=this,r=t._self._c;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"字典树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#字典树"}},[t._v("#")]),t._v(" 字典树")]),t._v(" "),r("h2",{attrs:{id:"什么是字典树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#什么是字典树"}},[t._v("#")]),t._v(" 什么是字典树")]),t._v(" "),r("p",[t._v("Trie 树(又叫「前缀树」或「字典树」)是一种用于快速查询「某个字符串/字符前缀」是否存在的数据结构。")]),t._v(" "),r("ul",[r("li",[t._v("根节点(Root)不包含字符,除根节点外的每一个节点都仅包含一个字符;")]),t._v(" "),r("li",[t._v("从根节点到某一节点路径上所经过的字符连接起来,即为该节点对应的字符串;")]),t._v(" "),r("li",[t._v("任意节点的所有子节点所包含的字符都不相同;")])]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181057.jpg",alt:"img"}})]),t._v(" "),r("h3",{attrs:{id:"字典树的构造"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#字典树的构造"}},[t._v("#")]),t._v(" 字典树的构造")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181243.jpg",alt:"img"}})]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181425.jpg",alt:"img"}})]),t._v(" "),r("p",[t._v("构建 Trie 树的过程,需要扫描所有的字符串,时间复杂度是 O(n)(n 表示所有字符串的长度和)。")]),t._v(" "),r("p",[r("strong",[t._v("字典树非常耗费内存")]),t._v("。")]),t._v(" "),r("p",[t._v("用数组来存储一个节点的子节点的指针。如果字符串中包含从 a 到 z 这 26 个字符,那每个节点都要存储一个长度为 26 的数组,并且每个数组存储一个 8 字节指针(或者是 4 字节,这个大小跟 CPU、操作系统、编译器等有关)。而且,即便一个节点只有很少的子节点,远小于 26 个,比如 3、4 个,我们也要维护一个长度为 26 的数组。")]),t._v(" "),r("p",[t._v("用数组来存储一个节点的子节点的指针。如果字符串中包含从 a 到 z 这 26 个字符,那每个节点都要存储一个长度为 26 的数组,并且每个数组存储一个 8 字节指针(或者是 4 字节,这个大小跟 CPU、操作系统、编译器等有关)。而且,即便一个节点只有很少的子节点,远小于 26 个,比如 3、4 个,我们也要维护一个长度为 26 的数组。")]),t._v(" "),r("p",[t._v("用数组来存储一个节点的子节点的指针。如果字符串中包含从 a 到 z 这 26 个字符,那每个节点都要存储一个长度为 26 的数组,并且每个数组存储一个 8 字节指针(或者是 4 字节,这个大小跟 CPU、操作系统、编译器等有关)。而且,即便一个节点只有很少的子节点,远小于 26 个,比如 3、4 个,我们也要维护一个长度为 26 的数组。")]),t._v(" "),r("h3",{attrs:{id:"字典树的查找"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#字典树的查找"}},[t._v("#")]),t._v(" 字典树的查找")]),t._v(" "),r("ol",[r("li",[t._v("每次从根结点开始搜索;")]),t._v(" "),r("li",[t._v("获取关键词的第一个字符,根据该字符选择对应的子节点,转到该子节点继续检索;")]),t._v(" "),r("li",[t._v("在相应的子节点上,获取关键词的第二个字符,进一步选择对应的子节点进行检索;")]),t._v(" "),r("li",[t._v("以此类推,进行迭代过程;")]),t._v(" "),r("li",[t._v("在某个节点处,关键词的所有字母已被取出,则读取附在该节点上的信息,查找完成。")])]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181305.jpg",alt:"img"}})]),t._v(" "),r("p",[t._v("每次查询时,如果要查询的字符串长度是 k,那我们只需要比对大约 k 个节点,就能完成查询操作。跟原本那组字符串的长度和个数没有任何关系。所以说,构建好 Trie 树后,在其中查找字符串的时间复杂度是 O(k),k 表示要查找的字符串的长度。")]),t._v(" "),r("h2",{attrs:{id:"字典树的应用场景"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#字典树的应用场景"}},[t._v("#")]),t._v(" 字典树的应用场景")]),t._v(" "),r("p",[t._v("在一组字符串中查找字符串,Trie 树实际上表现得并不好。它对要处理的字符串有及其严苛的要求。")]),t._v(" "),r("p",[t._v("第一,字符串中包含的字符集不能太大。我们前面讲到,如果字符集太大,那存储空间可能就会浪费很多。即便可以优化,但也要付出牺牲查询、插入效率的代价。")]),t._v(" "),r("p",[t._v("第二,要求字符串的前缀重合比较多,不然空间消耗会变大很多。")]),t._v(" "),r("p",[t._v("第三,如果要用 Trie 树解决问题,那我们就要自己从零开始实现一个 Trie 树,还要保证没有 bug,这个在工程上是将简单问题复杂化,除非必须,一般不建议这样做。")]),t._v(" "),r("p",[t._v("第四,我们知道,通过指针串起来的数据块是不连续的,而 Trie 树中用到了指针,所以,对缓存并不友好,性能上会打个折扣。")]),t._v(" "),r("p",[t._v("在一组字符串中查找字符串,Trie 树实际上表现得并不好。它对要处理的字符串有及其严苛的要求。")]),t._v(" "),r("p",[t._v("在一组字符串中查找字符串,Trie 树实际上表现得并不好。它对要处理的字符串有及其严苛的要求。")]),t._v(" "),r("p",[t._v("(1)自动补全")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20200305095300.png",alt:"img"}})]),t._v(" "),r("p",[t._v("(2)拼写检查")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20200305101637.png",alt:"img"}})]),t._v(" "),r("p",[t._v("(3)IP 路由 (最长前缀匹配)")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20200305102959.gif",alt:"img"}})]),t._v(" "),r("p",[t._v("图 3. 使用 Trie 树的最长前缀匹配算法,Internet 协议(IP)路由中利用转发表选择路径。")]),t._v(" "),r("p",[t._v("(4)T9 (九宫格) 打字预测")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20200305103047.jpg",alt:"img"}})]),t._v(" "),r("p",[t._v("(5)单词游戏")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20200305103052.png",alt:"img"}})]),t._v(" "),r("p",[t._v("Trie 树可通过剪枝搜索空间来高效解决 Boggle 单词游戏")]),t._v(" "),r("h2",{attrs:{id:"参考资料"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法之美"),r("OutboundLink")],1)]),t._v(" "),r("li",[t._v("https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shi-xian-trie-qian-zhui-shu-by-leetcode/")])])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/16.8087d451.js b/assets/js/16.8087d451.js new file mode 100644 index 0000000..eab2ab7 --- /dev/null +++ b/assets/js/16.8087d451.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{379:function(_,v,a){"use strict";a.r(v);var t=a(15),s=Object(t.a)({},(function(){var _=this,v=_._self._c;return v("ContentSlotsDistributor",{attrs:{"slot-key":_.$parent.slotKey}},[v("h1",{attrs:{id:"红黑树"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#红黑树"}},[_._v("#")]),_._v(" 红黑树")]),_._v(" "),v("h2",{attrs:{id:"平衡二叉树"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#平衡二叉树"}},[_._v("#")]),_._v(" 平衡二叉树")]),_._v(" "),v("p",[_._v("平衡二叉树的严格定义是这样的:二叉树中任意一个节点的左右子树的高度相差不能大于 1。")]),_._v(" "),v("p",[_._v("完全二叉树、满二叉树其实都是平衡二叉树,但是非完全二叉树也有可能是平衡二叉树。")]),_._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310202113.jpg",alt:"img"}})]),_._v(" "),v("p",[v("strong",[_._v("平衡二叉查找树中“平衡”的意思,其实就是让整棵树左右看起来比较“对称”、比较“平衡”,不要出现左子树很高、右子树很矮的情况。这样就能让整棵树的高度相对来说低一些,相应的插入、删除、查找等操作的效率高一些")]),_._v("。")]),_._v(" "),v("h2",{attrs:{id:"什么是红黑树"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#什么是红黑树"}},[_._v("#")]),_._v(" 什么是红黑树")]),_._v(" "),v("p",[_._v("红黑树的英文是“Red-Black Tree”,简称 R-B Tree。它是一种不严格的平衡二叉查找树。")]),_._v(" "),v("p",[_._v("红黑树中的节点,一类被标记为黑色,一类被标记为红色。除此之外,一棵红黑树还需要满足这样几个要求:")]),_._v(" "),v("ul",[v("li",[_._v("根节点是黑色的;")]),_._v(" "),v("li",[_._v("每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储数据;")]),_._v(" "),v("li",[_._v("任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的;")]),_._v(" "),v("li",[_._v("每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点;")])]),_._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310202612.jpg",alt:"img"}})]),_._v(" "),v("h3",{attrs:{id:"为什么说红黑树是-近似平衡-的"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#为什么说红黑树是-近似平衡-的"}},[_._v("#")]),_._v(" 为什么说红黑树是“近似平衡”的?")]),_._v(" "),v("p",[_._v("平衡二叉查找树的初衷,是为了解决二叉查找树因为动态更新导致的性能退化问题。")]),_._v(" "),v("p",[_._v("所以,"),v("strong",[_._v("“平衡”的意思可以等价为性能不退化。“近似平衡”就等价为性能不会退化的太严重")]),_._v("。")]),_._v(" "),v("p",[v("strong",[_._v("如果我们将红色节点从红黑树中去掉,那单纯包含黑色节点的红黑树的高度是多少呢")]),_._v("?")]),_._v(" "),v("p",[_._v("红色节点删除之后,有些节点就没有父节点了,它们会直接拿这些节点的祖父节点(父节点的父节点)作为父节点。所以,之前的二叉树就变成了四叉树。")]),_._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310202902.jpg",alt:"img"}})]),_._v(" "),v("p",[_._v("前面红黑树的定义里有这么一条:从任意节点到可达的叶子节点的每个路径包含相同数目的黑色节点。我们从四叉树中取出某些节点,放到叶节点位置,四叉树就变成了完全二叉树。所以,仅包含黑色节点的四叉树的高度,比包含相同节点个数的完全二叉树的高度还要小。")]),_._v(" "),v("p",[v("strong",[_._v("现在把红色节点加回去,高度会变成多少呢")]),_._v("?")]),_._v(" "),v("p",[_._v("在红黑树中,红色节点不能相邻,也就是说,有一个红色节点就要至少有一个黑色节点,将它跟其他红色节点隔开。红黑树中包含最多黑色节点的路径不会超过 log2n,所以加入红色节点之后,最长路径不会超过 2log2n,也就是说,红黑树的高度近似 2log2n。")]),_._v(" "),v("p",[_._v("所以,红黑树的高度只比高度平衡的 AVL 树的高度(log2n)仅仅大了一倍,在性能上,下降得并不多。这样推导出来的结果不够精确,实际上红黑树的性能更好。")]),_._v(" "),v("h2",{attrs:{id:"为什么需要红黑树"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#为什么需要红黑树"}},[_._v("#")]),_._v(" 为什么需要红黑树")]),_._v(" "),v("p",[_._v("AVL 树是一种高度平衡的二叉树,所以查找的效率非常高,但是,有利就有弊,AVL 树为了维持这种高度的平衡,就要付出更多的代价。每次插入、删除都要做调整,就比较复杂、耗时。所以,对于有频繁的插入、删除操作的数据集合,使用 AVL 树的代价就有点高了。")]),_._v(" "),v("p",[_._v("红黑树只是做到了近似平衡,并不是严格的平衡,所以在维护平衡的成本上,要比 AVL 树要低。")]),_._v(" "),v("p",[_._v("所以,红黑树的插入、删除、查找各种操作性能都比较稳定。对于工程应用来说,要面对各种异常情况,为了支撑这种工业级的应用,我们更倾向于这种性能稳定的平衡二叉查找树。")]),_._v(" "),v("h2",{attrs:{id:"红黑树平衡调整"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#红黑树平衡调整"}},[_._v("#")]),_._v(" 红黑树平衡调整")]),_._v(" "),v("h3",{attrs:{id:"插入操作的平衡调整"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#插入操作的平衡调整"}},[_._v("#")]),_._v(" 插入操作的平衡调整")]),_._v(" "),v("p",[v("strong",[_._v("红黑树规定,插入的节点必须是红色的。而且,二叉查找树中新插入的节点都是放在叶子节点上")]),_._v("。")]),_._v(" "),v("ul",[v("li",[_._v("如果插入节点的父节点是黑色的,那我们什么都不用做,它仍然满足红黑树的定义。")]),_._v(" "),v("li",[_._v("如果插入的节点是根节点,那我们直接改变它的颜色,把它变成黑色就可以了。")])]),_._v(" "),v("p",[_._v("除此之外,其他情况都会违背红黑树的定义,于是我们就需要进行调整,调整的过程包含两种基础的操作:"),v("strong",[_._v("左右旋转")]),_._v("和"),v("strong",[_._v("改变颜色")]),_._v("。")]),_._v(" "),v("p",[_._v("红黑树的平衡调整过程是一个迭代的过程。我们把正在处理的节点叫作"),v("strong",[_._v("关注节点")]),_._v("。关注节点会随着不停地迭代处理,而不断发生变化。最开始的关注节点就是新插入的节点。")]),_._v(" "),v("p",[_._v("新节点插入之后,如果红黑树的平衡被打破,那一般会有下面三种情况。我们只需要根据每种情况的特点,不停地调整,就可以让红黑树继续符合定义,也就是继续保持平衡。")]),_._v(" "),v("p",[v("strong",[_._v("CASE 1:如果关注节点是 a,它的叔叔节点 d 是红色")]),_._v(",我们就依次执行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("将关注节点 a 的父节点 b、叔叔节点 d 的颜色都设置成黑色;")]),_._v(" "),v("li",[_._v("将关注节点 a 的祖父节点 c 的颜色设置成红色;")]),_._v(" "),v("li",[_._v("关注节点变成 a 的祖父节点 c;")]),_._v(" "),v("li",[_._v("跳到 CASE 2 或者 CASE 3。")])]),_._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310203600.jpg",alt:"img"}})]),_._v(" "),v("p",[v("strong",[_._v("CASE 2:如果关注节点是 a,它的叔叔节点 d 是黑色,关注节点 a 是其父节点 b 的右子节点")]),_._v(",我们就依次执行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("关注节点变成节点 a 的父节点 b;")]),_._v(" "),v("li",[_._v("围绕新的关注节点 b 左旋;")]),_._v(" "),v("li",[_._v("跳到 CASE 3。")])]),_._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310203623.jpg",alt:"img"}})]),_._v(" "),v("p",[v("strong",[_._v("CASE 3:如果关注节点是 a,它的叔叔节点 d 是黑色,关注节点 a 是其父节点 b 的左子节点")]),_._v(",我们就依次执行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("围绕关注节点 a 的祖父节点 c 右旋;")]),_._v(" "),v("li",[_._v("将关注节点 a 的父节点 b、兄弟节点 c 的颜色互换。")]),_._v(" "),v("li",[_._v("调整结束。")])]),_._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310203645.jpg",alt:"img"}})]),_._v(" "),v("h3",{attrs:{id:"删除操作的平衡调整"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#删除操作的平衡调整"}},[_._v("#")]),_._v(" 删除操作的平衡调整")]),_._v(" "),v("h4",{attrs:{id:"针对删除节点初步调整"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#针对删除节点初步调整"}},[_._v("#")]),_._v(" 针对删除节点初步调整")]),_._v(" "),v("p",[v("strong",[_._v("CASE 1:如果要删除的节点是 a,它只有一个子节点 b")]),_._v(",那我们就依次进行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("删除节点 a,并且把节点 b 替换到节点 a 的位置,这一部分操作跟普通的二叉查找树的删除操作一样;")]),_._v(" "),v("li",[_._v("节点 a 只能是黑色,节点 b 也只能是红色,其他情况均不符合红黑树的定义。这种情况下,我们把节点 b 改为黑色;")]),_._v(" "),v("li",[_._v("调整结束,不需要进行二次调整。")])]),_._v(" "),v("p",[v("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310204215.jpg",alt:"img"}})]),_._v(" "),v("p",[v("strong",[_._v("CASE 2:如果要删除的节点 a 有两个非空子节点,并且它的后继节点就是节点 a 的右子节点 c")]),_._v("。我们就依次进行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("如果节点 a 的后继节点就是右子节点 c,那右子节点 c 肯定没有左子树。我们把节点 a 删除,并且将节点 c 替换到节点 a 的位置。这一部分操作跟普通的二叉查找树的删除操作无异;")]),_._v(" "),v("li",[_._v("然后把节点 c 的颜色设置为跟节点 a 相同的颜色;")]),_._v(" "),v("li",[_._v("如果节点 c 是黑色,为了不违反红黑树的最后一条定义,我们给节点 c 的右子节点 d 多加一个黑色,这个时候节点 d 就成了“红 - 黑”或者“黑 - 黑”;")]),_._v(" "),v("li",[_._v("这个时候,关注节点变成了节点 d,第二步的调整操作就会针对关注节点来做。")])]),_._v(" "),v("p",[v("strong",[_._v("CASE 3:如果要删除的是节点 a,它有两个非空子节点,并且节点 a 的后继节点不是右子节点")]),_._v(",我们就依次进行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("找到后继节点 d,并将它删除,删除后继节点 d 的过程参照 CASE 1;")]),_._v(" "),v("li",[_._v("将节点 a 替换成后继节点 d;")]),_._v(" "),v("li",[_._v("把节点 d 的颜色设置为跟节点 a 相同的颜色;")]),_._v(" "),v("li",[_._v("如果节点 d 是黑色,为了不违反红黑树的最后一条定义,我们给节点 d 的右子节点 c 多加一个黑色,这个时候节点 c 就成了“红 - 黑”或者“黑 - 黑”;")]),_._v(" "),v("li",[_._v("这个时候,关注节点变成了节点 c,第二步的调整操作就会针对关注节点来做。")])]),_._v(" "),v("h4",{attrs:{id:"针对关注节点进行二次调整"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#针对关注节点进行二次调整"}},[_._v("#")]),_._v(" 针对关注节点进行二次调整")]),_._v(" "),v("p",[v("strong",[_._v("CASE 1:如果关注节点是 a,它的兄弟节点 c 是红色的")]),_._v(",我们就依次进行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("围绕关注节点 a 的父节点 b 左旋;")]),_._v(" "),v("li",[_._v("关注节点 a 的父节点 b 和祖父节点 c 交换颜色;")]),_._v(" "),v("li",[_._v("关注节点不变;")]),_._v(" "),v("li",[_._v("继续从四种情况中选择适合的规则来调整。")])]),_._v(" "),v("p",[v("strong",[_._v("CASE 2:如果关注节点是 a,它的兄弟节点 c 是黑色的,并且节点 c 的左右子节点 d、e 都是黑色的")]),_._v(",我们就依次进行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("将关注节点 a 的兄弟节点 c 的颜色变成红色;")]),_._v(" "),v("li",[_._v("从关注节点 a 中去掉一个黑色,这个时候节点 a 就是单纯的红色或者黑色;")]),_._v(" "),v("li",[_._v("给关注节点 a 的父节点 b 添加一个黑色,这个时候节点 b 就变成了“红 - 黑”或者“黑 - 黑”;")]),_._v(" "),v("li",[_._v("关注节点从 a 变成其父节点 b;")]),_._v(" "),v("li",[_._v("继续从四种情况中选择符合的规则来调整。")])]),_._v(" "),v("p",[v("strong",[_._v("CASE 3:如果关注节点是 a,它的兄弟节点 c 是黑色,c 的左子节点 d 是红色,c 的右子节点 e 是黑色")]),_._v(",我们就依次进行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("围绕关注节点 a 的兄弟节点 c 右旋;")]),_._v(" "),v("li",[_._v("节点 c 和节点 d 交换颜色;")]),_._v(" "),v("li",[_._v("关注节点不变;")]),_._v(" "),v("li",[_._v("跳转到 CASE 4,继续调整。")])]),_._v(" "),v("p",[v("strong",[_._v("CASE 4:如果关注节点 a 的兄弟节点 c 是黑色的,并且 c 的右子节点是红色的")]),_._v(",我们就依次进行下面的操作:")]),_._v(" "),v("ul",[v("li",[_._v("围绕关注节点 a 的父节点 b 左旋;")]),_._v(" "),v("li",[_._v("将关注节点 a 的兄弟节点 c 的颜色,跟关注节点 a 的父节点 b 设置成相同的颜色;")]),_._v(" "),v("li",[_._v("将关注节点 a 的父节点 b 的颜色设置为黑色;")]),_._v(" "),v("li",[_._v("从关注节点 a 中去掉一个黑色,节点 a 就变成了单纯的红色或者黑色;")]),_._v(" "),v("li",[_._v("将关注节点 a 的叔叔节点 e 设置为黑色;")]),_._v(" "),v("li",[_._v("调整结束。")])]),_._v(" "),v("h2",{attrs:{id:"参考资料"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[_._v("#")]),_._v(" 参考资料")]),_._v(" "),v("ul",[v("li",[v("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[_._v("数据结构与算法之美"),v("OutboundLink")],1)])])])}),[],!1,null,null,null);v.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/17.b0677b09.js b/assets/js/17.b0677b09.js new file mode 100644 index 0000000..4348d64 --- /dev/null +++ b/assets/js/17.b0677b09.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{381:function(v,_,t){"use strict";t.r(_);var a=t(15),r=Object(a.a)({},(function(){var v=this,_=v._self._c;return _("ContentSlotsDistributor",{attrs:{"slot-key":v.$parent.slotKey}},[_("h1",{attrs:{id:"哈希表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#哈希表"}},[v._v("#")]),v._v(" 哈希表")]),v._v(" "),_("blockquote",[_("p",[_("strong",[v._v("哈希表")]),v._v(" 是一种使用 "),_("strong",[v._v("哈希函数")]),v._v(" 组织数据,以支持快速插入和搜索的数据结构。")]),v._v(" "),_("p",[v._v("有两种不同类型的哈希表:"),_("strong",[v._v("哈希集合")]),v._v(" 和 "),_("strong",[v._v("哈希映射")]),v._v("。")]),v._v(" "),_("ul",[_("li",[_("strong",[v._v("哈希集合")]),v._v(" 是集合数据结构的实现之一,用于存储非重复值。")]),v._v(" "),_("li",[_("strong",[v._v("哈希映射")]),v._v(" 是映射 数据结构的实现之一,用于存储(key, value)键值对。")])])]),v._v(" "),_("h2",{attrs:{id:"什么是哈希表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#什么是哈希表"}},[v._v("#")]),v._v(" 什么是哈希表")]),v._v(" "),_("p",[v._v("哈希表的英文叫“Hash Table”,我们平时也叫它“散列表”或者“Hash 表”。")]),v._v(" "),_("p",[_("strong",[v._v("哈希表")]),v._v(" 是一种使用 "),_("strong",[v._v("哈希函数")]),v._v(" 组织数据,以支持快速插入和搜索的数据结构。")]),v._v(" "),_("p",[v._v("有两种不同类型的哈希表:"),_("strong",[v._v("哈希集合")]),v._v(" 和 "),_("strong",[v._v("哈希映射")]),v._v("。")]),v._v(" "),_("ul",[_("li",[_("strong",[v._v("哈希集合")]),v._v(" 是集合数据结构的实现之一,用于存储非重复值。")]),v._v(" "),_("li",[_("strong",[v._v("哈希映射")]),v._v(" 是映射 数据结构的实现之一,用于存储(key, value)键值对。")])]),v._v(" "),_("p",[_("strong",[v._v("哈希表用的是数组支持按照下标随机访问数据的特性,所以哈希表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有哈希表")]),v._v("。")]),v._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320201844.png",alt:"img"}})]),v._v(" "),_("p",[v._v("哈希表通过散列函数把元素的键值映射为下标,然后将数据存储在数组中对应下标的位置。按照键值查询元素时,用同样的散列函数,将键值转化数组下标,从对应的数组下标的位置取数据。")]),v._v(" "),_("p",[v._v("有两种不同类型的哈希表:哈希集合和哈希映射。")]),v._v(" "),_("ul",[_("li",[_("code",[v._v("哈希集合")]),v._v("是"),_("code",[v._v("集合")]),v._v("数据结构的实现之一,用于存储"),_("code",[v._v("非重复值")]),v._v("。")]),v._v(" "),_("li",[_("code",[v._v("哈希映射")]),v._v("是"),_("code",[v._v("映射")]),v._v(" 数据结构的实现之一,用于存储"),_("code",[v._v("(key, value)")]),v._v("键值对。")])]),v._v(" "),_("p",[v._v("在"),_("code",[v._v("标准模板库")]),v._v("的帮助下,哈希表是"),_("code",[v._v("易于使用的")]),v._v("。大多数常见语言(如 Java,C ++ 和 Python)都支持哈希集合和哈希映射。")]),v._v(" "),_("h2",{attrs:{id:"散列函数"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#散列函数"}},[v._v("#")]),v._v(" 散列函数")]),v._v(" "),_("p",[v._v("散列函数,顾名思义,它是一个函数。我们可以把它定义成 "),_("strong",[v._v("hash(key)")]),v._v(",其中 key 表示元素的键值,hash(key) 的值表示经过散列函数计算得到的散列值。")]),v._v(" "),_("p",[v._v("哈希表的关键思想是使用哈希函数将键映射到存储桶。更确切地说,")]),v._v(" "),_("ol",[_("li",[v._v("当我们插入一个新的键时,哈希函数将决定该键应该分配到哪个桶中,并将该键存储在相应的桶中;")]),v._v(" "),_("li",[v._v("当我们想要搜索一个键时,哈希表将使用相同的哈希函数来查找对应的桶,并只在特定的桶中进行搜索。")])]),v._v(" "),_("p",[v._v("散列函数将取决于 "),_("code",[v._v("键值的范围")]),v._v(" 和 "),_("code",[v._v("桶的数量")]),v._v(" 。")]),v._v(" "),_("p",[_("strong",[v._v("散列函数设计的基本要求")]),v._v(":")]),v._v(" "),_("ol",[_("li",[v._v("散列函数计算得到的散列值是一个非负整数;")]),v._v(" "),_("li",[v._v("如果 key1 = key2,那 hash(key1) == hash(key2);")]),v._v(" "),_("li",[v._v("如果 key1 ≠ key2,那 hash(key1) ≠ hash(key2)。")])]),v._v(" "),_("h3",{attrs:{id:"散列冲突"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#散列冲突"}},[v._v("#")]),v._v(" 散列冲突")]),v._v(" "),_("p",[v._v("即便像业界著名的"),_("a",{attrs:{href:"https://zh.wikipedia.org/wiki/MD5",target:"_blank",rel:"noopener noreferrer"}},[v._v("MD5"),_("OutboundLink")],1),v._v("、"),_("a",{attrs:{href:"https://zh.wikipedia.org/wiki/SHA%E5%AE%B6%E6%97%8F",target:"_blank",rel:"noopener noreferrer"}},[v._v("SHA"),_("OutboundLink")],1),v._v("、"),_("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E5%BE%AA%E7%92%B0%E5%86%97%E9%A4%98%E6%A0%A1%E9%A9%97",target:"_blank",rel:"noopener noreferrer"}},[v._v("CRC"),_("OutboundLink")],1),v._v("等哈希算法,也无法完全避免这种"),_("strong",[v._v("散列冲突")]),v._v("。")]),v._v(" "),_("p",[v._v("该如何解决散列冲突问题呢?我们常用的散列冲突解决方法有两类,开放寻址法(open addressing)和链表法(chaining)。")]),v._v(" "),_("h3",{attrs:{id:"装载因子"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#装载因子"}},[v._v("#")]),v._v(" 装载因子")]),v._v(" "),_("p",[v._v("当哈希表中空闲位置不多的时候,散列冲突的概率就会大大提高。为了尽可能保证哈希表的操作效率,一般情况下,我们会尽可能保证哈希表中有一定比例的空闲槽位。我们用"),_("strong",[v._v("装载因子")]),v._v("(load factor)来表示空位的多少。")]),v._v(" "),_("p",[v._v("装载因子的计算公式是:")]),v._v(" "),_("div",{staticClass:"language- extra-class"},[_("pre",{pre:!0,attrs:{class:"language-text"}},[_("code",[v._v("哈希表的装载因子 = 填入表中的元素个数 / 哈希表的长度\n")])])]),_("p",[_("strong",[v._v("装载因子越大,说明空闲位置越少,冲突越多")]),v._v(",哈希表的性能会下降。不仅插入数据的过程要多次寻址或者拉很长的链,查找的过程也会因此变得很慢。")]),v._v(" "),_("p",[v._v("当装载因子过大时,就需要对哈希表扩容。新申请一个更大的哈希表,将数据搬移到这个新哈希表中。针对数组的扩容,数据搬移操作比较简单。但是,针对哈希表的扩容,数据搬移操作要复杂很多。因为哈希表的大小变了,数据的存储位置也变了,所以我们需要通过散列函数重新计算每个数据的存储位置。")]),v._v(" "),_("p",[v._v("插入一个数据,最好情况下,不需要扩容,最好时间复杂度是 O(1)。最坏情况下,哈希表装载因子过高,启动扩容,我们需要重新申请内存空间,重新计算哈希位置,并且搬移数据,所以时间复杂度是 O(n)。用摊还分析法,均摊情况下,时间复杂度接近最好情况,就是 O(1)。")]),v._v(" "),_("p",[v._v("装载因子阈值需要选择得当。如果太大,会导致冲突过多;如果太小,会导致内存浪费严重。")]),v._v(" "),_("h3",{attrs:{id:"开放寻址法"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#开放寻址法"}},[v._v("#")]),v._v(" 开放寻址法")]),v._v(" "),_("p",[v._v("开放寻址法的核心思想是,如果出现了散列冲突,我们就重新探测一个空闲位置,将其插入。")]),v._v(" "),_("p",[_("strong",[v._v("当数据量比较小、装载因子小的时候,适合采用开放寻址法。这也是 Java 中的 "),_("code",[v._v("ThreadLocalMap")]),v._v(" 使用开放寻址法解决散列冲突的原因")]),v._v("。")]),v._v(" "),_("p",[_("strong",[v._v("线性探测")]),v._v("(Linear Probing):当我们往哈希表中插入数据时,如果某个数据经过散列函数散列之后,存储位置已经被占用了,我们就从当前位置开始,依次往后查找,看是否有空闲位置,直到找到为止。")]),v._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220323200359.png",alt:""}})]),v._v(" "),_("p",[v._v("对于使用线性探测法解决冲突的哈希表,删除操作稍微有些特别。我们不能单纯地把要删除的元素设置为空。这是为什么呢?在查找的时候,一旦我们通过线性探测方法,找到一个空闲位置,我们就可以认定哈希表中不存在这个数据。但是,如果这个空闲位置是我们后来删除的,就会导致原来的查找算法失效。本来存在的数据,会被认定为不存在。这个问题如何解决呢?")]),v._v(" "),_("p",[v._v("我们可以将删除的元素,特殊标记为 deleted。当线性探测查找的时候,遇到标记为 deleted 的空间,并不是停下来,而是继续往下探测。")]),v._v(" "),_("p",[v._v("线性探测法其实存在很大问题。当哈希表中插入的数据越来越多时,散列冲突发生的可能性就会越来越大,空闲位置会越来越少,线性探测的时间就会越来越久。极端情况下,我们可能需要探测整个哈希表,所以最坏情况下的时间复杂度为 O(n)。同理,在删除和查找时,也有可能会线性探测整张哈希表,才能找到要查找或者删除的数据。")]),v._v(" "),_("h3",{attrs:{id:"链表法"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#链表法"}},[v._v("#")]),v._v(" 链表法")]),v._v(" "),_("p",[v._v("在哈希表中,每个“桶(bucket)”或者“槽(slot)”会对应一条链表,所有散列值相同的元素我们都放到相同槽位对应的链表中。")]),v._v(" "),_("p",[v._v("链表法比起开放寻址法,对大装载因子的容忍度更高。开放寻址法只能适用装载因子小于 1 的情况。接近 1 时,就可能会有大量的散列冲突,导致大量的探测、再散列等,性能会下降很多。但是对于链表法来说,只要散列函数的值随机均匀,即便装载因子变成 10,也就是链表的长度变长了而已,虽然查找效率有所下降,但是比起顺序查找还是快很多。")]),v._v(" "),_("p",[_("strong",[v._v("基于链表的散列冲突处理方法比较适合存储大对象、大数据量的哈希表,而且,比起开放寻址法,它更加灵活,支持更多的优化策略,比如用红黑树代替链表")]),v._v("。")]),v._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220323200419.png",alt:""}})]),v._v(" "),_("p",[v._v("当插入的时候,我们只需要通过散列函数计算出对应的散列槽位,将其插入到对应链表中即可,所以插入的时间复杂度是 O(1)。当查找、删除一个元素时,我们同样通过散列函数计算出对应的槽,然后遍历链表查找或者删除。那查找或删除操作的时间复杂度是多少呢?")]),v._v(" "),_("p",[v._v("实际上,这两个操作的时间复杂度跟链表的长度 k 成正比,也就是 O(k)。对于散列比较均匀的散列函数来说,理论上讲,k=n/m,其中 n 表示散列中数据的个数,m 表示哈希表中“槽”的个数。")]),v._v(" "),_("h3",{attrs:{id:"开放寻址法-vs-链表法"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#开放寻址法-vs-链表法"}},[v._v("#")]),v._v(" 开放寻址法 vs. 链表法")]),v._v(" "),_("p",[_("strong",[v._v("开放寻址法适用于数据量比较小、装载因子小的场景")]),v._v("。")]),v._v(" "),_("p",[_("strong",[v._v("链表法适用于存储大对象、大数据量的哈希表")]),v._v("。"),_("strong",[v._v("比起开放寻址法,它更加灵活,支持更多的优化策略,比如用红黑树代替链表")]),v._v("。")]),v._v(" "),_("h2",{attrs:{id:"哈希表的应用场景"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#哈希表的应用场景"}},[v._v("#")]),v._v(" 哈希表的应用场景")]),v._v(" "),_("p",[v._v("哈希算法的应用非常非常多,最常见的七个,分别是:")]),v._v(" "),_("ul",[_("li",[_("strong",[v._v("安全加密")]),v._v(":如:MD5、SHA")]),v._v(" "),_("li",[_("strong",[v._v("唯一标识")]),v._v(":UUID")]),v._v(" "),_("li",[v._v("数据校验:数字签名")]),v._v(" "),_("li",[_("strong",[v._v("散列函数")]),v._v(":")]),v._v(" "),_("li",[_("strong",[v._v("负载均衡")]),v._v(":会话粘滞(session sticky)负载均衡算法。"),_("strong",[v._v("可以通过哈希算法,对客户端 IP 地址或者会话 ID 计算哈希值,将取得的哈希值与服务器列表的大小进行取模运算,最终得到的值就是应该被路由到的服务器编号。")]),v._v(" 这样,我们就可以把同一个 IP 过来的所有请求,都路由到同一个后端服务器上。")]),v._v(" "),_("li",[v._v("数据分片")]),v._v(" "),_("li",[v._v("分布式存储:一致性哈希算法、虚拟哈希槽")])]),v._v(" "),_("h3",{attrs:{id:"典型应用场景"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#典型应用场景"}},[v._v("#")]),v._v(" 典型应用场景")]),v._v(" "),_("p",[v._v("Java 的 HashMap 工具类,其")]),v._v(" "),_("ul",[_("li",[v._v("HashMap 默认的初始大小是 16")]),v._v(" "),_("li",[v._v("最大装载因子默认是 0.75,当 HashMap 中元素个数超过 0.75*capacity(capacity 表示哈希表的容量)的时候,就会启动扩容,每次扩容都会扩容为原来的两倍大小。")]),v._v(" "),_("li",[v._v("HashMap 底层采用链表法来解决冲突。即使负载因子和散列函数设计得再合理,也免不了会出现链表过长的情况,一旦出现链表过长,则会严重影响 HashMap 的性能。在 JDK1.8 版本中,对 HashMap 做了进一步优化:引入了红黑树。当链表长度太长(默认超过 8)时,链表就转换为红黑树。我们可以利用红黑树快速增删改查的特点,提高 HashMap 的性能。当红黑树结点个数少于 8 个的时候,又会将红黑树转化为链表。因为在数据量较小的情况下,红黑树要维护平衡,比起链表来,性能上的优势并不明显。")])]),v._v(" "),_("h2",{attrs:{id:"练习"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#练习"}},[v._v("#")]),v._v(" 练习")]),v._v(" "),_("p",[v._v("Leetcode 练习题:")]),v._v(" "),_("ul",[_("li",[_("a",{attrs:{href:"https://leetcode-cn.com/problems/design-hashset/",target:"_blank",rel:"noopener noreferrer"}},[v._v("705. 设计哈希集合"),_("OutboundLink")],1)]),v._v(" "),_("li",[_("a",{attrs:{href:"https://leetcode-cn.com/problems/design-hashmap/",target:"_blank",rel:"noopener noreferrer"}},[v._v("706. 设计哈希映射"),_("OutboundLink")],1)])]),v._v(" "),_("h2",{attrs:{id:"思考"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#思考"}},[v._v("#")]),v._v(" 思考")]),v._v(" "),_("ol",[_("li",[v._v("假设我们有 10 万条 URL 访问日志,如何按照访问次数给 URL 排序?")]),v._v(" "),_("li",[v._v("有两个字符串数组,每个数组大约有 10 万条字符串,如何快速找出两个数组中相同的字符串?")])]),v._v(" "),_("h2",{attrs:{id:"参考资料"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[v._v("#")]),v._v(" 参考资料")]),v._v(" "),_("ul",[_("li",[_("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[v._v("数据结构与算法之美"),_("OutboundLink")],1)])])])}),[],!1,null,null,null);_.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/18.a1cc2021.js b/assets/js/18.a1cc2021.js new file mode 100644 index 0000000..0ff8ff5 --- /dev/null +++ b/assets/js/18.a1cc2021.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[18],{382:function(t,_,v){"use strict";v.r(_);var a=v(15),s=Object(a.a)({},(function(){var t=this,_=t._self._c;return _("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[_("h1",{attrs:{id:"跳表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#跳表"}},[t._v("#")]),t._v(" 跳表")]),t._v(" "),_("h2",{attrs:{id:"什么是跳表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#什么是跳表"}},[t._v("#")]),t._v(" 什么是跳表")]),t._v(" "),_("p",[t._v("对于一个有序数组,可以使用高效的二分查找法,其时间复杂度为 "),_("code",[t._v("O(log n)")]),t._v("。")]),t._v(" "),_("p",[t._v("但是,即使是有序的链表,也只能使用低效的顺序查找,其时间复杂度为 "),_("code",[t._v("O(n)")]),t._v("。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220323113532.png",alt:"img"}})]),t._v(" "),_("p",[t._v("如何提高链表的查找效率呢?")]),t._v(" "),_("p",[t._v("我们可以对链表加一层索引。具体来说,可以每两个结点提取一个结点到上一级,我们把抽出来的那一级叫作"),_("strong",[t._v("索引")]),t._v("或"),_("strong",[t._v("索引层")]),t._v("。索引节点中通过一个 down 指针,指向下一级结点。通过这样的改造,就可以支持类似二分查找的算法。我们把改造之后的数据结构叫作"),_("strong",[t._v("跳表")]),t._v("(Skip list)。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220323155309.png",alt:"img"}})]),t._v(" "),_("p",[t._v("随着数据的不断增长,一级索引层也变得越来越长。此时,我们可以为一级索引再增加一层索引层:二级索引层。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220323155346.png",alt:"img"}})]),t._v(" "),_("p",[t._v("随着数据的膨胀,当二级索引层也变得很长时,我们可以继续为其添加新的索引层。"),_("strong",[t._v("这种链表加多级索引的结构,就是跳表")]),t._v("。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220323114408.png",alt:"img"}})]),t._v(" "),_("h3",{attrs:{id:"跳表的时间复杂度"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#跳表的时间复杂度"}},[t._v("#")]),t._v(" 跳表的时间复杂度")]),t._v(" "),_("p",[t._v("在一个具有多级索引的跳表中,第一级索引的结点个数大约就是 "),_("code",[t._v("n/2")]),t._v(",第二级索引的结点个数大约就是 "),_("code",[t._v("n/4")]),t._v(",第三级索引的结点个数大约就是 "),_("code",[t._v("n/8")]),t._v(",依次类推,也就是说,第 "),_("code",[t._v("k")]),t._v(" 级索引的结点个数是第 "),_("code",[t._v("k-1")]),t._v(" 级索引的结点个数的 "),_("code",[t._v("1/2")]),t._v(",那第 k 级索引结点的个数就是 "),_("code",[t._v("n/(2k)")]),t._v("。所以"),_("strong",[t._v("跳表查询数据的时间复杂度就是 "),_("code",[t._v("O(logn)")])]),t._v("。")]),t._v(" "),_("h3",{attrs:{id:"跳表的空间复杂度"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#跳表的空间复杂度"}},[t._v("#")]),t._v(" 跳表的空间复杂度")]),t._v(" "),_("p",[t._v("比起单纯的单链表,跳表需要存储多级索引,肯定要消耗更多的存储空间。")]),t._v(" "),_("p",[t._v("假设原始链表大小为 n,那第一级索引大约有 n/2 个结点,第二级索引大约有 n/4 个结点,以此类推,每上升一级就减少一半,直到剩下 2 个结点。如果我们把每层索引的结点数写出来,就是一个等比数列。")]),t._v(" "),_("div",{staticClass:"language- extra-class"},[_("pre",{pre:!0,attrs:{class:"language-text"}},[_("code",[t._v("索引节点数 = n/2 + n/4 + n/8 … + 8 + 4 + 2 = n-2\n")])])]),_("p",[t._v("所以,跳表的空间复杂度是 "),_("code",[t._v("O(n)")]),t._v("。")]),t._v(" "),_("p",[t._v("跳表的存储空间其实还有压缩空间。比如,我们增加索引节点的范围,由『每两个节点抽一个上级索引节点』改为『每五个节点抽一个上级索引节点』,可以显著节省存储空间。")]),t._v(" "),_("p",[t._v("实际上,在软件开发中,我们不必太在意索引占用的额外空间。在讲数据结构和算法时,我们习惯性地把要处理的数据看成整数,但是在实际的软件开发中,原始链表中存储的有可能是很大的对象,而索引结点只需要存储关键值和几个指针,并不需要存储对象,所以当对象比索引结点大很多时,那索引占用的额外空间就可以忽略了。")]),t._v(" "),_("h2",{attrs:{id:"跳表的操作"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#跳表的操作"}},[t._v("#")]),t._v(" 跳表的操作")]),t._v(" "),_("p",[t._v("跳表是一种各方面性能都比较优秀的"),_("strong",[t._v("动态数据结构")]),t._v(",可以支持快速的插入、删除、查找操作,写起来也不复杂,甚至可以替代"),_("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91",target:"_blank",rel:"noopener noreferrer"}},[t._v("红黑树"),_("OutboundLink")],1),t._v("(Red-black tree)。")]),t._v(" "),_("h3",{attrs:{id:"高效的动态插入和删除"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#高效的动态插入和删除"}},[t._v("#")]),t._v(" 高效的动态插入和删除")]),t._v(" "),_("p",[t._v("跳表不仅支持查找操作,还支持动态的插入、删除操作,而且插入、删除操作的时间复杂度也是 "),_("code",[t._v("O(logn)")]),t._v("。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220323155933.png",alt:"img"}})]),t._v(" "),_("ul",[_("li",[_("strong",[t._v("插入操作")]),t._v(":对于纯粹的单链表,需要遍历每个结点,来找到插入的位置。但是,对于跳表来说,我们讲过查找某个结点的的时间复杂度是 "),_("code",[t._v("O(log n)")]),t._v(",所以这里查找某个数据应该插入的位置,方法也是类似的,时间复杂度也是 "),_("code",[t._v("O(log n)")]),t._v("。")]),t._v(" "),_("li",[_("strong",[t._v("删除操作")]),t._v(":如果这个结点在索引中也有出现,我们除了要删除原始链表中的结点,还要删除索引中的。因为单链表中的删除操作需要拿到要删除结点的前驱结点,然后通过指针操作完成删除。所以在查找要删除的结点的时候,一定要获取前驱结点。当然,如果我们用的是双向链表,就不需要考虑这个问题了。")])]),t._v(" "),_("h3",{attrs:{id:"跳表索引动态更新"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#跳表索引动态更新"}},[t._v("#")]),t._v(" 跳表索引动态更新")]),t._v(" "),_("p",[t._v("当我们不停地往跳表中插入数据时,如果我们不更新索引,就有可能出现某 2 个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220323161942.png",alt:"img"}})]),t._v(" "),_("p",[t._v("如红黑树、AVL 树这样的平衡二叉树,是通过左右旋的方式保持左右子树的大小平衡,而跳表是通过随机函数来维护前面提到的“平衡性”。")]),t._v(" "),_("p",[t._v("当我们往跳表中插入数据的时候,我们可以选择同时将这个数据插入到部分索引层中。如何选择加入哪些索引层呢?可以通过一个随机函数,来决定将这个结点插入到哪几级索引中,比如随机函数生成了值 K,那我们就将这个结点添加到第一级到第 K 级这 K 级索引中。")]),t._v(" "),_("h2",{attrs:{id:"为什么需要跳表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#为什么需要跳表"}},[t._v("#")]),t._v(" 为什么需要跳表")]),t._v(" "),_("p",[t._v("跳表是一种动态数据结构,支持快速的插入、删除、查找操作,时间复杂度都是 "),_("code",[t._v("O(logn)")]),t._v("。")]),t._v(" "),_("p",[t._v("跳表的空间复杂度是 "),_("code",[t._v("O(n)")]),t._v("。不过,跳表的实现非常灵活,可以通过改变索引构建策略,有效平衡执行效率和内存消耗。虽然跳表的代码实现并不简单,但是作为一种动态数据结构,比起红黑树来说,实现要简单多了。所以很多时候,我们为了代码的简单、易读,比起红黑树,我们更倾向用跳表。")]),t._v(" "),_("h2",{attrs:{id:"跳表的应用场景"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#跳表的应用场景"}},[t._v("#")]),t._v(" 跳表的应用场景")]),t._v(" "),_("p",[t._v("经典实现:Redis 的 Sorted Set、JDK 的 "),_("code",[t._v("ConcurrentSkipListMap")]),t._v(" 和 "),_("code",[t._v("ConcurrentSkipListSet")]),t._v(" 都是基于跳表实现。")]),t._v(" "),_("p",[t._v("为什么 Redis 要用跳表来实现有序集合,而不是红黑树?")]),t._v(" "),_("p",[t._v("Redis 中的有序集合支持的核心操作主要有下面这几个:")]),t._v(" "),_("ul",[_("li",[t._v("插入一个数据;")]),t._v(" "),_("li",[t._v("删除一个数据;")]),t._v(" "),_("li",[t._v("查找一个数据;")]),t._v(" "),_("li",[t._v("按照区间查找数据(比如查找值在 [100, 356] 之间的数据);")]),t._v(" "),_("li",[t._v("迭代输出有序序列。")])]),t._v(" "),_("p",[t._v("其中,插入、删除、查找以及迭代输出有序序列这几个操作,红黑树也可以完成,时间复杂度跟跳表是一样的。但是,按照区间来查找数据这个操作,红黑树的效率没有跳表高。")]),t._v(" "),_("h2",{attrs:{id:"参考资料"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),_("ul",[_("li",[_("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法之美"),_("OutboundLink")],1)])])])}),[],!1,null,null,null);_.default=s.exports}}]); \ No newline at end of file diff --git a/assets/js/19.f394aaac.js b/assets/js/19.f394aaac.js new file mode 100644 index 0000000..d2c0894 --- /dev/null +++ b/assets/js/19.f394aaac.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{383:function(e,t,v){"use strict";v.r(t);var r=v(15),_=Object(r.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"图"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#图"}},[e._v("#")]),e._v(" 图")]),e._v(" "),t("p",[e._v("在计算机科学中,一个图就是一些"),t("em",[e._v("顶点")]),e._v("的集合,这些顶点通过一系列"),t("em",[e._v("边")]),e._v("结对(连接)。顶点用圆圈表示,边就是这些圆圈之间的连线。顶点之间通过边连接。")]),e._v(" "),t("p",[t("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/cs/data-structure/graph/graph.png",alt:"img"}})]),e._v(" "),t("h2",{attrs:{id:"什么是图"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#什么是图"}},[e._v("#")]),e._v(" 什么是图")]),e._v(" "),t("ul",[t("li",[t("strong",[e._v("阶(Order)")]),e._v(" - 图 G 中点集 V 的大小称作图 G 的阶。")]),e._v(" "),t("li",[t("strong",[e._v("子图(Sub-Graph)")]),e._v(" - 当图 G'=(V',E')其中 V‘包含于 V,E’包含于 E,则 G'称作图 G=(V,E)的子图。每个图都是本身的子图。")]),e._v(" "),t("li",[e._v("生成子图(Spanning Sub-Graph) - 指满足条件 V(G') = V(G)的 G 的子图 G'。")]),e._v(" "),t("li",[e._v("导出子图(Induced Subgraph) - 以图 G 的顶点集 V 的"),t("a",{attrs:{href:"https://baike.baidu.com/item/%E9%9D%9E%E7%A9%BA%E5%AD%90%E9%9B%86/10180460",target:"_blank",rel:"noopener noreferrer"}},[e._v("非空子集"),t("OutboundLink")],1),e._v("V1 为顶点集,以两端点均在 V1 中的全体边为边集的 G 的子图,称为 V1 导出的导出子图;以图 G 的边集 E 的非空子集 E1 为边集,以 E1 中边关联的顶点的全体为顶点集的 G 的子图,称为 E1 导出的导出子图。")]),e._v(" "),t("li",[t("strong",[e._v("有向图")]),e._v(" - 如果给图的每条边规定一个方向,那么得到的图称为有向图。")]),e._v(" "),t("li",[t("strong",[e._v("无向图")]),e._v(" - 边没有方向的图称为无向图。")]),e._v(" "),t("li",[t("strong",[e._v("度(Degree)")]),e._v(" - 一个顶点的度是指与该顶点相关联的边的条数,顶点 v 的度记作 d(v)。")]),e._v(" "),t("li",[t("strong",[e._v("入度(In-degree)"),t("strong",[e._v("和")]),e._v("出度(Out-degree)")]),e._v(" - 对于有向图来说,一个顶点的度可细分为入度和出度。一个顶点的入度是指与其关联的各边之中,以其为终点的边数;出度则是相对的概念,指以该顶点为起点的边数。")]),e._v(" "),t("li",[t("strong",[e._v("自环(Loop)")]),e._v(" - 若一条边的两个顶点为同一顶点,则此边称作自环。")]),e._v(" "),t("li",[e._v("路径(Path) - 从 u 到 v 的一条路径是指一个序列 v0,e1,v1,e2,v2,...ek,vk,其中 ei 的顶点为 vi 及 vi - 1,k 称作路径的长度。如果它的起止顶点相同,该路径是“闭”的,反之,则称为“开”的。一条路径称为一简单路径(simple path),如果路径中除起始与终止"),t("a",{attrs:{href:"https://baike.baidu.com/item/%E9%A1%B6%E7%82%B9",target:"_blank",rel:"noopener noreferrer"}},[e._v("顶点"),t("OutboundLink")],1),e._v("可以重合外,所有顶点两两不等。")]),e._v(" "),t("li",[t("strong",[e._v("行迹(Trace)")]),e._v(" - 如果路径 P(u,v)中的边各不相同,则该路径称为 u 到 v 的一条行迹。闭的行迹称作回路(Circuit)。")]),e._v(" "),t("li",[t("strong",[e._v("轨迹(Track)")]),e._v(" - 如果路径 P(u,v)中的顶点各不相同,则该路径称为 u 到 v 的一条轨迹。闭的轨迹称作圈(Cycle)。")]),e._v(" "),t("li",[t("strong",[e._v("桥(Bridge)")]),e._v(" - 若去掉一条边,便会使得整个图不连通,该边称为"),t("a",{attrs:{href:"https://baike.baidu.com/item/%E6%A1%A5",target:"_blank",rel:"noopener noreferrer"}},[e._v("桥"),t("OutboundLink")],1),e._v("。")])]),e._v(" "),t("p",[e._v("如果图的边没有方向性,则被成为无向图。")]),e._v(" "),t("p",[t("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220314093554.jpg",alt:"img"}})]),e._v(" "),t("h2",{attrs:{id:"图的基本操作"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#图的基本操作"}},[e._v("#")]),e._v(" 图的基本操作")]),e._v(" "),t("ul",[t("li",[e._v("创建一个图结构 - CreateGraph(G)")]),e._v(" "),t("li",[e._v("检索给定顶点 - LocateVex(G,elem)")]),e._v(" "),t("li",[e._v("获取图中某个顶点 - GetVex(G,v)")]),e._v(" "),t("li",[e._v("为图中顶点赋值 - PutVex(G,v,value)")]),e._v(" "),t("li",[e._v("返回第一个邻接点 - FirstAdjVex(G,v)")]),e._v(" "),t("li",[e._v("返回下一个邻接点 - NextAdjVex(G,v,w)")]),e._v(" "),t("li",[e._v("插入一个顶点 - InsertVex(G,v)")]),e._v(" "),t("li",[e._v("删除一个顶点 - DeleteVex(G,v)")]),e._v(" "),t("li",[e._v("插入一条边 - InsertEdge(G,v,w)")]),e._v(" "),t("li",[e._v("删除一条边 - DeleteEdge(G,v,w)")]),e._v(" "),t("li",[e._v("遍历图 - Traverse(G,v)")])]),e._v(" "),t("h2",{attrs:{id:"参考资料"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[e._v("#")]),e._v(" 参考资料")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[e._v("数据结构与算法之美"),t("OutboundLink")],1)])])])}),[],!1,null,null,null);t.default=_.exports}}]); \ No newline at end of file diff --git a/assets/js/2.91ce5277.js b/assets/js/2.91ce5277.js new file mode 100644 index 0000000..ab49e5b --- /dev/null +++ b/assets/js/2.91ce5277.js @@ -0,0 +1,14 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{289:function(t,e,n){},290:function(t,e,n){},291:function(t,e,n){},292:function(t,e,n){},293:function(t,e,n){},294:function(t,e,n){},295:function(t,e,n){},296:function(t,e,n){},297:function(t,e,n){"use strict";var r=TypeError;t.exports=function(t,e){if(t + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */(function(){var i="Expected a function",o="__lodash_placeholder__",s=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],a="[object Arguments]",u="[object Array]",l="[object Boolean]",c="[object Date]",h="[object Error]",f="[object Function]",p="[object GeneratorFunction]",g="[object Map]",d="[object Number]",v="[object Object]",m="[object RegExp]",y="[object Set]",_="[object String]",b="[object Symbol]",w="[object WeakMap]",k="[object ArrayBuffer]",x="[object DataView]",P="[object Float32Array]",C="[object Float64Array]",T="[object Int8Array]",S="[object Int16Array]",L="[object Int32Array]",A="[object Uint8Array]",B="[object Uint16Array]",M="[object Uint32Array]",O=/\b__p \+= '';/g,E=/\b(__p \+=) '' \+/g,I=/(__e\(.*?\)|\b__t\)) \+\n'';/g,D=/&(?:amp|lt|gt|quot|#39);/g,$=/[&<>"']/g,j=RegExp(D.source),Y=RegExp($.source),X=/<%-([\s\S]+?)%>/g,N=/<%([\s\S]+?)%>/g,R=/<%=([\s\S]+?)%>/g,z=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,U=/^\w*$/,H=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,F=/[\\^$.*+?()[\]{}|]/g,W=RegExp(F.source),q=/^\s+/,G=/\s/,K=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,Q=/\{\n\/\* \[wrapped with (.+)\] \*/,J=/,? & /,Z=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,V=/[()=,{}\[\]\/\s]/,tt=/\\(\\)?/g,et=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,nt=/\w*$/,rt=/^[-+]0x[0-9a-f]+$/i,it=/^0b[01]+$/i,ot=/^\[object .+?Constructor\]$/,st=/^0o[0-7]+$/i,at=/^(?:0|[1-9]\d*)$/,ut=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,lt=/($^)/,ct=/['\n\r\u2028\u2029\\]/g,ht="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",ft="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",pt="[\\ud800-\\udfff]",gt="["+ft+"]",dt="["+ht+"]",vt="\\d+",mt="[\\u2700-\\u27bf]",yt="[a-z\\xdf-\\xf6\\xf8-\\xff]",_t="[^\\ud800-\\udfff"+ft+vt+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",bt="\\ud83c[\\udffb-\\udfff]",wt="[^\\ud800-\\udfff]",kt="(?:\\ud83c[\\udde6-\\uddff]){2}",xt="[\\ud800-\\udbff][\\udc00-\\udfff]",Pt="[A-Z\\xc0-\\xd6\\xd8-\\xde]",Ct="(?:"+yt+"|"+_t+")",Tt="(?:"+Pt+"|"+_t+")",St="(?:"+dt+"|"+bt+")"+"?",Lt="[\\ufe0e\\ufe0f]?"+St+("(?:\\u200d(?:"+[wt,kt,xt].join("|")+")[\\ufe0e\\ufe0f]?"+St+")*"),At="(?:"+[mt,kt,xt].join("|")+")"+Lt,Bt="(?:"+[wt+dt+"?",dt,kt,xt,pt].join("|")+")",Mt=RegExp("['’]","g"),Ot=RegExp(dt,"g"),Et=RegExp(bt+"(?="+bt+")|"+Bt+Lt,"g"),It=RegExp([Pt+"?"+yt+"+(?:['’](?:d|ll|m|re|s|t|ve))?(?="+[gt,Pt,"$"].join("|")+")",Tt+"+(?:['’](?:D|LL|M|RE|S|T|VE))?(?="+[gt,Pt+Ct,"$"].join("|")+")",Pt+"?"+Ct+"+(?:['’](?:d|ll|m|re|s|t|ve))?",Pt+"+(?:['’](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",vt,At].join("|"),"g"),Dt=RegExp("[\\u200d\\ud800-\\udfff"+ht+"\\ufe0e\\ufe0f]"),$t=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,jt=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Yt=-1,Xt={};Xt[P]=Xt[C]=Xt[T]=Xt[S]=Xt[L]=Xt[A]=Xt["[object Uint8ClampedArray]"]=Xt[B]=Xt[M]=!0,Xt[a]=Xt[u]=Xt[k]=Xt[l]=Xt[x]=Xt[c]=Xt[h]=Xt[f]=Xt[g]=Xt[d]=Xt[v]=Xt[m]=Xt[y]=Xt[_]=Xt[w]=!1;var Nt={};Nt[a]=Nt[u]=Nt[k]=Nt[x]=Nt[l]=Nt[c]=Nt[P]=Nt[C]=Nt[T]=Nt[S]=Nt[L]=Nt[g]=Nt[d]=Nt[v]=Nt[m]=Nt[y]=Nt[_]=Nt[b]=Nt[A]=Nt["[object Uint8ClampedArray]"]=Nt[B]=Nt[M]=!0,Nt[h]=Nt[f]=Nt[w]=!1;var Rt={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},zt=parseFloat,Ut=parseInt,Ht="object"==typeof global&&global&&global.Object===Object&&global,Ft="object"==typeof self&&self&&self.Object===Object&&self,Wt=Ht||Ft||Function("return this")(),qt=e&&!e.nodeType&&e,Gt=qt&&"object"==typeof t&&t&&!t.nodeType&&t,Kt=Gt&&Gt.exports===qt,Qt=Kt&&Ht.process,Jt=function(){try{var t=Gt&&Gt.require&&Gt.require("util").types;return t||Qt&&Qt.binding&&Qt.binding("util")}catch(t){}}(),Zt=Jt&&Jt.isArrayBuffer,Vt=Jt&&Jt.isDate,te=Jt&&Jt.isMap,ee=Jt&&Jt.isRegExp,ne=Jt&&Jt.isSet,re=Jt&&Jt.isTypedArray;function ie(t,e,n){switch(n.length){case 0:return t.call(e);case 1:return t.call(e,n[0]);case 2:return t.call(e,n[0],n[1]);case 3:return t.call(e,n[0],n[1],n[2])}return t.apply(e,n)}function oe(t,e,n,r){for(var i=-1,o=null==t?0:t.length;++i-1}function he(t,e,n){for(var r=-1,i=null==t?0:t.length;++r-1;);return n}function Ie(t,e){for(var n=t.length;n--&&be(e,t[n],0)>-1;);return n}function De(t,e){for(var n=t.length,r=0;n--;)t[n]===e&&++r;return r}var $e=Ce({"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss","Ā":"A","Ă":"A","Ą":"A","ā":"a","ă":"a","ą":"a","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","ć":"c","ĉ":"c","ċ":"c","č":"c","Ď":"D","Đ":"D","ď":"d","đ":"d","Ē":"E","Ĕ":"E","Ė":"E","Ę":"E","Ě":"E","ē":"e","ĕ":"e","ė":"e","ę":"e","ě":"e","Ĝ":"G","Ğ":"G","Ġ":"G","Ģ":"G","ĝ":"g","ğ":"g","ġ":"g","ģ":"g","Ĥ":"H","Ħ":"H","ĥ":"h","ħ":"h","Ĩ":"I","Ī":"I","Ĭ":"I","Į":"I","İ":"I","ĩ":"i","ī":"i","ĭ":"i","į":"i","ı":"i","Ĵ":"J","ĵ":"j","Ķ":"K","ķ":"k","ĸ":"k","Ĺ":"L","Ļ":"L","Ľ":"L","Ŀ":"L","Ł":"L","ĺ":"l","ļ":"l","ľ":"l","ŀ":"l","ł":"l","Ń":"N","Ņ":"N","Ň":"N","Ŋ":"N","ń":"n","ņ":"n","ň":"n","ŋ":"n","Ō":"O","Ŏ":"O","Ő":"O","ō":"o","ŏ":"o","ő":"o","Ŕ":"R","Ŗ":"R","Ř":"R","ŕ":"r","ŗ":"r","ř":"r","Ś":"S","Ŝ":"S","Ş":"S","Š":"S","ś":"s","ŝ":"s","ş":"s","š":"s","Ţ":"T","Ť":"T","Ŧ":"T","ţ":"t","ť":"t","ŧ":"t","Ũ":"U","Ū":"U","Ŭ":"U","Ů":"U","Ű":"U","Ų":"U","ũ":"u","ū":"u","ŭ":"u","ů":"u","ű":"u","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","Ż":"Z","Ž":"Z","ź":"z","ż":"z","ž":"z","IJ":"IJ","ij":"ij","Œ":"Oe","œ":"oe","ʼn":"'n","ſ":"s"}),je=Ce({"&":"&","<":"<",">":">",'"':""","'":"'"});function Ye(t){return"\\"+Rt[t]}function Xe(t){return Dt.test(t)}function Ne(t){var e=-1,n=Array(t.size);return t.forEach((function(t,r){n[++e]=[r,t]})),n}function Re(t,e){return function(n){return t(e(n))}}function ze(t,e){for(var n=-1,r=t.length,i=0,s=[];++n",""":'"',"'":"'"});var Ke=function t(e){var n,r=(e=null==e?Wt:Ke.defaults(Wt.Object(),e,Ke.pick(Wt,jt))).Array,G=e.Date,ht=e.Error,ft=e.Function,pt=e.Math,gt=e.Object,dt=e.RegExp,vt=e.String,mt=e.TypeError,yt=r.prototype,_t=ft.prototype,bt=gt.prototype,wt=e["__core-js_shared__"],kt=_t.toString,xt=bt.hasOwnProperty,Pt=0,Ct=(n=/[^.]+$/.exec(wt&&wt.keys&&wt.keys.IE_PROTO||""))?"Symbol(src)_1."+n:"",Tt=bt.toString,St=kt.call(gt),Lt=Wt._,At=dt("^"+kt.call(xt).replace(F,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bt=Kt?e.Buffer:void 0,Et=e.Symbol,Dt=e.Uint8Array,Rt=Bt?Bt.allocUnsafe:void 0,Ht=Re(gt.getPrototypeOf,gt),Ft=gt.create,qt=bt.propertyIsEnumerable,Gt=yt.splice,Qt=Et?Et.isConcatSpreadable:void 0,Jt=Et?Et.iterator:void 0,me=Et?Et.toStringTag:void 0,Ce=function(){try{var t=to(gt,"defineProperty");return t({},"",{}),t}catch(t){}}(),Qe=e.clearTimeout!==Wt.clearTimeout&&e.clearTimeout,Je=G&&G.now!==Wt.Date.now&&G.now,Ze=e.setTimeout!==Wt.setTimeout&&e.setTimeout,Ve=pt.ceil,tn=pt.floor,en=gt.getOwnPropertySymbols,nn=Bt?Bt.isBuffer:void 0,rn=e.isFinite,on=yt.join,sn=Re(gt.keys,gt),an=pt.max,un=pt.min,ln=G.now,cn=e.parseInt,hn=pt.random,fn=yt.reverse,pn=to(e,"DataView"),gn=to(e,"Map"),dn=to(e,"Promise"),vn=to(e,"Set"),mn=to(e,"WeakMap"),yn=to(gt,"create"),_n=mn&&new mn,bn={},wn=Lo(pn),kn=Lo(gn),xn=Lo(dn),Pn=Lo(vn),Cn=Lo(mn),Tn=Et?Et.prototype:void 0,Sn=Tn?Tn.valueOf:void 0,Ln=Tn?Tn.toString:void 0;function An(t){if(Fs(t)&&!Is(t)&&!(t instanceof En)){if(t instanceof On)return t;if(xt.call(t,"__wrapped__"))return Ao(t)}return new On(t)}var Bn=function(){function t(){}return function(e){if(!Hs(e))return{};if(Ft)return Ft(e);t.prototype=e;var n=new t;return t.prototype=void 0,n}}();function Mn(){}function On(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e,this.__index__=0,this.__values__=void 0}function En(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function In(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e=e?t:e)),t}function Jn(t,e,n,r,i,o){var s,u=1&e,h=2&e,w=4&e;if(n&&(s=i?n(t,r,i,o):n(t)),void 0!==s)return s;if(!Hs(t))return t;var O=Is(t);if(O){if(s=function(t){var e=t.length,n=new t.constructor(e);e&&"string"==typeof t[0]&&xt.call(t,"index")&&(n.index=t.index,n.input=t.input);return n}(t),!u)return yi(t,s)}else{var E=ro(t),I=E==f||E==p;if(Ys(t))return fi(t,u);if(E==v||E==a||I&&!i){if(s=h||I?{}:oo(t),!u)return h?function(t,e){return _i(t,no(t),e)}(t,function(t,e){return t&&_i(e,ka(e),t)}(s,t)):function(t,e){return _i(t,eo(t),e)}(t,qn(s,t))}else{if(!Nt[E])return i?t:{};s=function(t,e,n){var r=t.constructor;switch(e){case k:return pi(t);case l:case c:return new r(+t);case x:return function(t,e){var n=e?pi(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.byteLength)}(t,n);case P:case C:case T:case S:case L:case A:case"[object Uint8ClampedArray]":case B:case M:return gi(t,n);case g:return new r;case d:case _:return new r(t);case m:return function(t){var e=new t.constructor(t.source,nt.exec(t));return e.lastIndex=t.lastIndex,e}(t);case y:return new r;case b:return i=t,Sn?gt(Sn.call(i)):{}}var i}(t,E,u)}}o||(o=new Yn);var D=o.get(t);if(D)return D;o.set(t,s),Qs(t)?t.forEach((function(r){s.add(Jn(r,e,n,r,t,o))})):Ws(t)&&t.forEach((function(r,i){s.set(i,Jn(r,e,n,i,t,o))}));var $=O?void 0:(w?h?qi:Wi:h?ka:wa)(t);return se($||t,(function(r,i){$&&(r=t[i=r]),Hn(s,i,Jn(r,e,n,i,t,o))})),s}function Zn(t,e,n){var r=n.length;if(null==t)return!r;for(t=gt(t);r--;){var i=n[r],o=e[i],s=t[i];if(void 0===s&&!(i in t)||!o(s))return!1}return!0}function Vn(t,e,n){if("function"!=typeof t)throw new mt(i);return wo((function(){t.apply(void 0,n)}),e)}function tr(t,e,n,r){var i=-1,o=ce,s=!0,a=t.length,u=[],l=e.length;if(!a)return u;n&&(e=fe(e,Be(n))),r?(o=he,s=!1):e.length>=200&&(o=Oe,s=!1,e=new jn(e));t:for(;++i-1},Dn.prototype.set=function(t,e){var n=this.__data__,r=Fn(n,t);return r<0?(++this.size,n.push([t,e])):n[r][1]=e,this},$n.prototype.clear=function(){this.size=0,this.__data__={hash:new In,map:new(gn||Dn),string:new In}},$n.prototype.delete=function(t){var e=Zi(this,t).delete(t);return this.size-=e?1:0,e},$n.prototype.get=function(t){return Zi(this,t).get(t)},$n.prototype.has=function(t){return Zi(this,t).has(t)},$n.prototype.set=function(t,e){var n=Zi(this,t),r=n.size;return n.set(t,e),this.size+=n.size==r?0:1,this},jn.prototype.add=jn.prototype.push=function(t){return this.__data__.set(t,"__lodash_hash_undefined__"),this},jn.prototype.has=function(t){return this.__data__.has(t)},Yn.prototype.clear=function(){this.__data__=new Dn,this.size=0},Yn.prototype.delete=function(t){var e=this.__data__,n=e.delete(t);return this.size=e.size,n},Yn.prototype.get=function(t){return this.__data__.get(t)},Yn.prototype.has=function(t){return this.__data__.has(t)},Yn.prototype.set=function(t,e){var n=this.__data__;if(n instanceof Dn){var r=n.__data__;if(!gn||r.length<199)return r.push([t,e]),this.size=++n.size,this;n=this.__data__=new $n(r)}return n.set(t,e),this.size=n.size,this};var er=ki(lr),nr=ki(cr,!0);function rr(t,e){var n=!0;return er(t,(function(t,r,i){return n=!!e(t,r,i)})),n}function ir(t,e,n){for(var r=-1,i=t.length;++r0&&n(a)?e>1?sr(a,e-1,n,r,i):pe(i,a):r||(i[i.length]=a)}return i}var ar=xi(),ur=xi(!0);function lr(t,e){return t&&ar(t,e,wa)}function cr(t,e){return t&&ur(t,e,wa)}function hr(t,e){return le(e,(function(e){return Rs(t[e])}))}function fr(t,e){for(var n=0,r=(e=ui(e,t)).length;null!=t&&ne}function vr(t,e){return null!=t&&xt.call(t,e)}function mr(t,e){return null!=t&&e in gt(t)}function yr(t,e,n){for(var i=n?he:ce,o=t[0].length,s=t.length,a=s,u=r(s),l=1/0,c=[];a--;){var h=t[a];a&&e&&(h=fe(h,Be(e))),l=un(h.length,l),u[a]=!n&&(e||o>=120&&h.length>=120)?new jn(a&&h):void 0}h=t[0];var f=-1,p=u[0];t:for(;++f=a)return u;var l=n[r];return u*("desc"==l?-1:1)}}return t.index-e.index}(t,e,n)}))}function Ir(t,e,n){for(var r=-1,i=e.length,o={};++r-1;)a!==t&&Gt.call(a,u,1),Gt.call(t,u,1);return t}function $r(t,e){for(var n=t?e.length:0,r=n-1;n--;){var i=e[n];if(n==r||i!==o){var o=i;ao(i)?Gt.call(t,i,1):ti(t,i)}}return t}function jr(t,e){return t+tn(hn()*(e-t+1))}function Yr(t,e){var n="";if(!t||e<1||e>9007199254740991)return n;do{e%2&&(n+=t),(e=tn(e/2))&&(t+=t)}while(e);return n}function Xr(t,e){return ko(vo(t,e,qa),t+"")}function Nr(t){return Nn(Ba(t))}function Rr(t,e){var n=Ba(t);return Co(n,Qn(e,0,n.length))}function zr(t,e,n,r){if(!Hs(t))return t;for(var i=-1,o=(e=ui(e,t)).length,s=o-1,a=t;null!=a&&++io?0:o+e),(n=n>o?o:n)<0&&(n+=o),o=e>n?0:n-e>>>0,e>>>=0;for(var s=r(o);++i>>1,s=t[o];null!==s&&!Zs(s)&&(n?s<=e:s=200){var l=e?null:Yi(t);if(l)return Ue(l);s=!1,i=Oe,u=new jn}else u=e?[]:a;t:for(;++r=r?t:Wr(t,e,n)}var hi=Qe||function(t){return Wt.clearTimeout(t)};function fi(t,e){if(e)return t.slice();var n=t.length,r=Rt?Rt(n):new t.constructor(n);return t.copy(r),r}function pi(t){var e=new t.constructor(t.byteLength);return new Dt(e).set(new Dt(t)),e}function gi(t,e){var n=e?pi(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.length)}function di(t,e){if(t!==e){var n=void 0!==t,r=null===t,i=t==t,o=Zs(t),s=void 0!==e,a=null===e,u=e==e,l=Zs(e);if(!a&&!l&&!o&&t>e||o&&s&&u&&!a&&!l||r&&s&&u||!n&&u||!i)return 1;if(!r&&!o&&!l&&t1?n[i-1]:void 0,s=i>2?n[2]:void 0;for(o=t.length>3&&"function"==typeof o?(i--,o):void 0,s&&uo(n[0],n[1],s)&&(o=i<3?void 0:o,i=1),e=gt(e);++r-1?i[o?e[s]:s]:void 0}}function Li(t){return Fi((function(e){var n=e.length,r=n,o=On.prototype.thru;for(t&&e.reverse();r--;){var s=e[r];if("function"!=typeof s)throw new mt(i);if(o&&!a&&"wrapper"==Ki(s))var a=new On([],!0)}for(r=a?r:n;++r1&&_.reverse(),h&&la))return!1;var l=o.get(t),c=o.get(e);if(l&&c)return l==e&&c==t;var h=-1,f=!0,p=2&n?new jn:void 0;for(o.set(t,e),o.set(e,t);++h-1&&t%1==0&&t1?"& ":"")+e[r],e=e.join(n>2?", ":" "),t.replace(K,"{\n/* [wrapped with "+e+"] */\n")}(r,function(t,e){return se(s,(function(n){var r="_."+n[0];e&n[1]&&!ce(t,r)&&t.push(r)})),t.sort()}(function(t){var e=t.match(Q);return e?e[1].split(J):[]}(r),n)))}function Po(t){var e=0,n=0;return function(){var r=ln(),i=16-(r-n);if(n=r,i>0){if(++e>=800)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}function Co(t,e){var n=-1,r=t.length,i=r-1;for(e=void 0===e?r:e;++n1?t[e-1]:void 0;return n="function"==typeof n?(t.pop(),n):void 0,Ko(t,n)}));function ns(t){var e=An(t);return e.__chain__=!0,e}function rs(t,e){return e(t)}var is=Fi((function(t){var e=t.length,n=e?t[0]:0,r=this.__wrapped__,i=function(e){return Kn(e,t)};return!(e>1||this.__actions__.length)&&r instanceof En&&ao(n)?((r=r.slice(n,+n+(e?1:0))).__actions__.push({func:rs,args:[i],thisArg:void 0}),new On(r,this.__chain__).thru((function(t){return e&&!t.length&&t.push(void 0),t}))):this.thru(i)}));var os=bi((function(t,e,n){xt.call(t,n)?++t[n]:Gn(t,n,1)}));var ss=Si(Eo),as=Si(Io);function us(t,e){return(Is(t)?se:er)(t,Ji(e,3))}function ls(t,e){return(Is(t)?ae:nr)(t,Ji(e,3))}var cs=bi((function(t,e,n){xt.call(t,n)?t[n].push(e):Gn(t,n,[e])}));var hs=Xr((function(t,e,n){var i=-1,o="function"==typeof e,s=$s(t)?r(t.length):[];return er(t,(function(t){s[++i]=o?ie(e,t,n):_r(t,e,n)})),s})),fs=bi((function(t,e,n){Gn(t,n,e)}));function ps(t,e){return(Is(t)?fe:Lr)(t,Ji(e,3))}var gs=bi((function(t,e,n){t[n?0:1].push(e)}),(function(){return[[],[]]}));var ds=Xr((function(t,e){if(null==t)return[];var n=e.length;return n>1&&uo(t,e[0],e[1])?e=[]:n>2&&uo(e[0],e[1],e[2])&&(e=[e[0]]),Er(t,sr(e,1),[])})),vs=Je||function(){return Wt.Date.now()};function ms(t,e,n){return e=n?void 0:e,Ni(t,128,void 0,void 0,void 0,void 0,e=t&&null==e?t.length:e)}function ys(t,e){var n;if("function"!=typeof e)throw new mt(i);return t=ia(t),function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=void 0),n}}var _s=Xr((function(t,e,n){var r=1;if(n.length){var i=ze(n,Qi(_s));r|=32}return Ni(t,r,e,n,i)})),bs=Xr((function(t,e,n){var r=3;if(n.length){var i=ze(n,Qi(bs));r|=32}return Ni(e,r,t,n,i)}));function ws(t,e,n){var r,o,s,a,u,l,c=0,h=!1,f=!1,p=!0;if("function"!=typeof t)throw new mt(i);function g(e){var n=r,i=o;return r=o=void 0,c=e,a=t.apply(i,n)}function d(t){return c=t,u=wo(m,e),h?g(t):a}function v(t){var n=t-l;return void 0===l||n>=e||n<0||f&&t-c>=s}function m(){var t=vs();if(v(t))return y(t);u=wo(m,function(t){var n=e-(t-l);return f?un(n,s-(t-c)):n}(t))}function y(t){return u=void 0,p&&r?g(t):(r=o=void 0,a)}function _(){var t=vs(),n=v(t);if(r=arguments,o=this,l=t,n){if(void 0===u)return d(l);if(f)return hi(u),u=wo(m,e),g(l)}return void 0===u&&(u=wo(m,e)),a}return e=sa(e)||0,Hs(n)&&(h=!!n.leading,s=(f="maxWait"in n)?an(sa(n.maxWait)||0,e):s,p="trailing"in n?!!n.trailing:p),_.cancel=function(){void 0!==u&&hi(u),c=0,r=l=o=u=void 0},_.flush=function(){return void 0===u?a:y(vs())},_}var ks=Xr((function(t,e){return Vn(t,1,e)})),xs=Xr((function(t,e,n){return Vn(t,sa(e)||0,n)}));function Ps(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new mt(i);var n=function(){var r=arguments,i=e?e.apply(this,r):r[0],o=n.cache;if(o.has(i))return o.get(i);var s=t.apply(this,r);return n.cache=o.set(i,s)||o,s};return n.cache=new(Ps.Cache||$n),n}function Cs(t){if("function"!=typeof t)throw new mt(i);return function(){var e=arguments;switch(e.length){case 0:return!t.call(this);case 1:return!t.call(this,e[0]);case 2:return!t.call(this,e[0],e[1]);case 3:return!t.call(this,e[0],e[1],e[2])}return!t.apply(this,e)}}Ps.Cache=$n;var Ts=li((function(t,e){var n=(e=1==e.length&&Is(e[0])?fe(e[0],Be(Ji())):fe(sr(e,1),Be(Ji()))).length;return Xr((function(r){for(var i=-1,o=un(r.length,n);++i=e})),Es=br(function(){return arguments}())?br:function(t){return Fs(t)&&xt.call(t,"callee")&&!qt.call(t,"callee")},Is=r.isArray,Ds=Zt?Be(Zt):function(t){return Fs(t)&&gr(t)==k};function $s(t){return null!=t&&Us(t.length)&&!Rs(t)}function js(t){return Fs(t)&&$s(t)}var Ys=nn||su,Xs=Vt?Be(Vt):function(t){return Fs(t)&&gr(t)==c};function Ns(t){if(!Fs(t))return!1;var e=gr(t);return e==h||"[object DOMException]"==e||"string"==typeof t.message&&"string"==typeof t.name&&!Gs(t)}function Rs(t){if(!Hs(t))return!1;var e=gr(t);return e==f||e==p||"[object AsyncFunction]"==e||"[object Proxy]"==e}function zs(t){return"number"==typeof t&&t==ia(t)}function Us(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=9007199254740991}function Hs(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}function Fs(t){return null!=t&&"object"==typeof t}var Ws=te?Be(te):function(t){return Fs(t)&&ro(t)==g};function qs(t){return"number"==typeof t||Fs(t)&&gr(t)==d}function Gs(t){if(!Fs(t)||gr(t)!=v)return!1;var e=Ht(t);if(null===e)return!0;var n=xt.call(e,"constructor")&&e.constructor;return"function"==typeof n&&n instanceof n&&kt.call(n)==St}var Ks=ee?Be(ee):function(t){return Fs(t)&&gr(t)==m};var Qs=ne?Be(ne):function(t){return Fs(t)&&ro(t)==y};function Js(t){return"string"==typeof t||!Is(t)&&Fs(t)&&gr(t)==_}function Zs(t){return"symbol"==typeof t||Fs(t)&&gr(t)==b}var Vs=re?Be(re):function(t){return Fs(t)&&Us(t.length)&&!!Xt[gr(t)]};var ta=Di(Sr),ea=Di((function(t,e){return t<=e}));function na(t){if(!t)return[];if($s(t))return Js(t)?We(t):yi(t);if(Jt&&t[Jt])return function(t){for(var e,n=[];!(e=t.next()).done;)n.push(e.value);return n}(t[Jt]());var e=ro(t);return(e==g?Ne:e==y?Ue:Ba)(t)}function ra(t){return t?(t=sa(t))===1/0||t===-1/0?17976931348623157e292*(t<0?-1:1):t==t?t:0:0===t?t:0}function ia(t){var e=ra(t),n=e%1;return e==e?n?e-n:e:0}function oa(t){return t?Qn(ia(t),0,4294967295):0}function sa(t){if("number"==typeof t)return t;if(Zs(t))return NaN;if(Hs(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=Hs(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=Ae(t);var n=it.test(t);return n||st.test(t)?Ut(t.slice(2),n?2:8):rt.test(t)?NaN:+t}function aa(t){return _i(t,ka(t))}function ua(t){return null==t?"":Zr(t)}var la=wi((function(t,e){if(fo(e)||$s(e))_i(e,wa(e),t);else for(var n in e)xt.call(e,n)&&Hn(t,n,e[n])})),ca=wi((function(t,e){_i(e,ka(e),t)})),ha=wi((function(t,e,n,r){_i(e,ka(e),t,r)})),fa=wi((function(t,e,n,r){_i(e,wa(e),t,r)})),pa=Fi(Kn);var ga=Xr((function(t,e){t=gt(t);var n=-1,r=e.length,i=r>2?e[2]:void 0;for(i&&uo(e[0],e[1],i)&&(r=1);++n1),e})),_i(t,qi(t),n),r&&(n=Jn(n,7,Ui));for(var i=e.length;i--;)ti(n,e[i]);return n}));var Ta=Fi((function(t,e){return null==t?{}:function(t,e){return Ir(t,e,(function(e,n){return ma(t,n)}))}(t,e)}));function Sa(t,e){if(null==t)return{};var n=fe(qi(t),(function(t){return[t]}));return e=Ji(e),Ir(t,n,(function(t,n){return e(t,n[0])}))}var La=Xi(wa),Aa=Xi(ka);function Ba(t){return null==t?[]:Me(t,wa(t))}var Ma=Ci((function(t,e,n){return e=e.toLowerCase(),t+(n?Oa(e):e)}));function Oa(t){return Na(ua(t).toLowerCase())}function Ea(t){return(t=ua(t))&&t.replace(ut,$e).replace(Ot,"")}var Ia=Ci((function(t,e,n){return t+(n?"-":"")+e.toLowerCase()})),Da=Ci((function(t,e,n){return t+(n?" ":"")+e.toLowerCase()})),$a=Pi("toLowerCase");var ja=Ci((function(t,e,n){return t+(n?"_":"")+e.toLowerCase()}));var Ya=Ci((function(t,e,n){return t+(n?" ":"")+Na(e)}));var Xa=Ci((function(t,e,n){return t+(n?" ":"")+e.toUpperCase()})),Na=Pi("toUpperCase");function Ra(t,e,n){return t=ua(t),void 0===(e=n?void 0:e)?function(t){return $t.test(t)}(t)?function(t){return t.match(It)||[]}(t):function(t){return t.match(Z)||[]}(t):t.match(e)||[]}var za=Xr((function(t,e){try{return ie(t,void 0,e)}catch(t){return Ns(t)?t:new ht(t)}})),Ua=Fi((function(t,e){return se(e,(function(e){e=So(e),Gn(t,e,_s(t[e],t))})),t}));function Ha(t){return function(){return t}}var Fa=Li(),Wa=Li(!0);function qa(t){return t}function Ga(t){return Pr("function"==typeof t?t:Jn(t,1))}var Ka=Xr((function(t,e){return function(n){return _r(n,t,e)}})),Qa=Xr((function(t,e){return function(n){return _r(t,n,e)}}));function Ja(t,e,n){var r=wa(e),i=hr(e,r);null!=n||Hs(e)&&(i.length||!r.length)||(n=e,e=t,t=this,i=hr(e,wa(e)));var o=!(Hs(n)&&"chain"in n&&!n.chain),s=Rs(t);return se(i,(function(n){var r=e[n];t[n]=r,s&&(t.prototype[n]=function(){var e=this.__chain__;if(o||e){var n=t(this.__wrapped__),i=n.__actions__=yi(this.__actions__);return i.push({func:r,args:arguments,thisArg:t}),n.__chain__=e,n}return r.apply(t,pe([this.value()],arguments))})})),t}function Za(){}var Va=Oi(fe),tu=Oi(ue),eu=Oi(ve);function nu(t){return lo(t)?Pe(So(t)):function(t){return function(e){return fr(e,t)}}(t)}var ru=Ii(),iu=Ii(!0);function ou(){return[]}function su(){return!1}var au=Mi((function(t,e){return t+e}),0),uu=ji("ceil"),lu=Mi((function(t,e){return t/e}),1),cu=ji("floor");var hu,fu=Mi((function(t,e){return t*e}),1),pu=ji("round"),gu=Mi((function(t,e){return t-e}),0);return An.after=function(t,e){if("function"!=typeof e)throw new mt(i);return t=ia(t),function(){if(--t<1)return e.apply(this,arguments)}},An.ary=ms,An.assign=la,An.assignIn=ca,An.assignInWith=ha,An.assignWith=fa,An.at=pa,An.before=ys,An.bind=_s,An.bindAll=Ua,An.bindKey=bs,An.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return Is(t)?t:[t]},An.chain=ns,An.chunk=function(t,e,n){e=(n?uo(t,e,n):void 0===e)?1:an(ia(e),0);var i=null==t?0:t.length;if(!i||e<1)return[];for(var o=0,s=0,a=r(Ve(i/e));oi?0:i+n),(r=void 0===r||r>i?i:ia(r))<0&&(r+=i),r=n>r?0:oa(r);n>>0)?(t=ua(t))&&("string"==typeof e||null!=e&&!Ks(e))&&!(e=Zr(e))&&Xe(t)?ci(We(t),0,n):t.split(e,n):[]},An.spread=function(t,e){if("function"!=typeof t)throw new mt(i);return e=null==e?0:an(ia(e),0),Xr((function(n){var r=n[e],i=ci(n,0,e);return r&&pe(i,r),ie(t,this,i)}))},An.tail=function(t){var e=null==t?0:t.length;return e?Wr(t,1,e):[]},An.take=function(t,e,n){return t&&t.length?Wr(t,0,(e=n||void 0===e?1:ia(e))<0?0:e):[]},An.takeRight=function(t,e,n){var r=null==t?0:t.length;return r?Wr(t,(e=r-(e=n||void 0===e?1:ia(e)))<0?0:e,r):[]},An.takeRightWhile=function(t,e){return t&&t.length?ni(t,Ji(e,3),!1,!0):[]},An.takeWhile=function(t,e){return t&&t.length?ni(t,Ji(e,3)):[]},An.tap=function(t,e){return e(t),t},An.throttle=function(t,e,n){var r=!0,o=!0;if("function"!=typeof t)throw new mt(i);return Hs(n)&&(r="leading"in n?!!n.leading:r,o="trailing"in n?!!n.trailing:o),ws(t,e,{leading:r,maxWait:e,trailing:o})},An.thru=rs,An.toArray=na,An.toPairs=La,An.toPairsIn=Aa,An.toPath=function(t){return Is(t)?fe(t,So):Zs(t)?[t]:yi(To(ua(t)))},An.toPlainObject=aa,An.transform=function(t,e,n){var r=Is(t),i=r||Ys(t)||Vs(t);if(e=Ji(e,4),null==n){var o=t&&t.constructor;n=i?r?new o:[]:Hs(t)&&Rs(o)?Bn(Ht(t)):{}}return(i?se:lr)(t,(function(t,r,i){return e(n,t,r,i)})),n},An.unary=function(t){return ms(t,1)},An.union=Fo,An.unionBy=Wo,An.unionWith=qo,An.uniq=function(t){return t&&t.length?Vr(t):[]},An.uniqBy=function(t,e){return t&&t.length?Vr(t,Ji(e,2)):[]},An.uniqWith=function(t,e){return e="function"==typeof e?e:void 0,t&&t.length?Vr(t,void 0,e):[]},An.unset=function(t,e){return null==t||ti(t,e)},An.unzip=Go,An.unzipWith=Ko,An.update=function(t,e,n){return null==t?t:ei(t,e,ai(n))},An.updateWith=function(t,e,n,r){return r="function"==typeof r?r:void 0,null==t?t:ei(t,e,ai(n),r)},An.values=Ba,An.valuesIn=function(t){return null==t?[]:Me(t,ka(t))},An.without=Qo,An.words=Ra,An.wrap=function(t,e){return Ss(ai(e),t)},An.xor=Jo,An.xorBy=Zo,An.xorWith=Vo,An.zip=ts,An.zipObject=function(t,e){return oi(t||[],e||[],Hn)},An.zipObjectDeep=function(t,e){return oi(t||[],e||[],zr)},An.zipWith=es,An.entries=La,An.entriesIn=Aa,An.extend=ca,An.extendWith=ha,Ja(An,An),An.add=au,An.attempt=za,An.camelCase=Ma,An.capitalize=Oa,An.ceil=uu,An.clamp=function(t,e,n){return void 0===n&&(n=e,e=void 0),void 0!==n&&(n=(n=sa(n))==n?n:0),void 0!==e&&(e=(e=sa(e))==e?e:0),Qn(sa(t),e,n)},An.clone=function(t){return Jn(t,4)},An.cloneDeep=function(t){return Jn(t,5)},An.cloneDeepWith=function(t,e){return Jn(t,5,e="function"==typeof e?e:void 0)},An.cloneWith=function(t,e){return Jn(t,4,e="function"==typeof e?e:void 0)},An.conformsTo=function(t,e){return null==e||Zn(t,e,wa(e))},An.deburr=Ea,An.defaultTo=function(t,e){return null==t||t!=t?e:t},An.divide=lu,An.endsWith=function(t,e,n){t=ua(t),e=Zr(e);var r=t.length,i=n=void 0===n?r:Qn(ia(n),0,r);return(n-=e.length)>=0&&t.slice(n,i)==e},An.eq=Bs,An.escape=function(t){return(t=ua(t))&&Y.test(t)?t.replace($,je):t},An.escapeRegExp=function(t){return(t=ua(t))&&W.test(t)?t.replace(F,"\\$&"):t},An.every=function(t,e,n){var r=Is(t)?ue:rr;return n&&uo(t,e,n)&&(e=void 0),r(t,Ji(e,3))},An.find=ss,An.findIndex=Eo,An.findKey=function(t,e){return ye(t,Ji(e,3),lr)},An.findLast=as,An.findLastIndex=Io,An.findLastKey=function(t,e){return ye(t,Ji(e,3),cr)},An.floor=cu,An.forEach=us,An.forEachRight=ls,An.forIn=function(t,e){return null==t?t:ar(t,Ji(e,3),ka)},An.forInRight=function(t,e){return null==t?t:ur(t,Ji(e,3),ka)},An.forOwn=function(t,e){return t&&lr(t,Ji(e,3))},An.forOwnRight=function(t,e){return t&&cr(t,Ji(e,3))},An.get=va,An.gt=Ms,An.gte=Os,An.has=function(t,e){return null!=t&&io(t,e,vr)},An.hasIn=ma,An.head=$o,An.identity=qa,An.includes=function(t,e,n,r){t=$s(t)?t:Ba(t),n=n&&!r?ia(n):0;var i=t.length;return n<0&&(n=an(i+n,0)),Js(t)?n<=i&&t.indexOf(e,n)>-1:!!i&&be(t,e,n)>-1},An.indexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=null==n?0:ia(n);return i<0&&(i=an(r+i,0)),be(t,e,i)},An.inRange=function(t,e,n){return e=ra(e),void 0===n?(n=e,e=0):n=ra(n),function(t,e,n){return t>=un(e,n)&&t=-9007199254740991&&t<=9007199254740991},An.isSet=Qs,An.isString=Js,An.isSymbol=Zs,An.isTypedArray=Vs,An.isUndefined=function(t){return void 0===t},An.isWeakMap=function(t){return Fs(t)&&ro(t)==w},An.isWeakSet=function(t){return Fs(t)&&"[object WeakSet]"==gr(t)},An.join=function(t,e){return null==t?"":on.call(t,e)},An.kebabCase=Ia,An.last=No,An.lastIndexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=r;return void 0!==n&&(i=(i=ia(n))<0?an(r+i,0):un(i,r-1)),e==e?function(t,e,n){for(var r=n+1;r--;)if(t[r]===e)return r;return r}(t,e,i):_e(t,ke,i,!0)},An.lowerCase=Da,An.lowerFirst=$a,An.lt=ta,An.lte=ea,An.max=function(t){return t&&t.length?ir(t,qa,dr):void 0},An.maxBy=function(t,e){return t&&t.length?ir(t,Ji(e,2),dr):void 0},An.mean=function(t){return xe(t,qa)},An.meanBy=function(t,e){return xe(t,Ji(e,2))},An.min=function(t){return t&&t.length?ir(t,qa,Sr):void 0},An.minBy=function(t,e){return t&&t.length?ir(t,Ji(e,2),Sr):void 0},An.stubArray=ou,An.stubFalse=su,An.stubObject=function(){return{}},An.stubString=function(){return""},An.stubTrue=function(){return!0},An.multiply=fu,An.nth=function(t,e){return t&&t.length?Or(t,ia(e)):void 0},An.noConflict=function(){return Wt._===this&&(Wt._=Lt),this},An.noop=Za,An.now=vs,An.pad=function(t,e,n){t=ua(t);var r=(e=ia(e))?Fe(t):0;if(!e||r>=e)return t;var i=(e-r)/2;return Ei(tn(i),n)+t+Ei(Ve(i),n)},An.padEnd=function(t,e,n){t=ua(t);var r=(e=ia(e))?Fe(t):0;return e&&re){var r=t;t=e,e=r}if(n||t%1||e%1){var i=hn();return un(t+i*(e-t+zt("1e-"+((i+"").length-1))),e)}return jr(t,e)},An.reduce=function(t,e,n){var r=Is(t)?ge:Te,i=arguments.length<3;return r(t,Ji(e,4),n,i,er)},An.reduceRight=function(t,e,n){var r=Is(t)?de:Te,i=arguments.length<3;return r(t,Ji(e,4),n,i,nr)},An.repeat=function(t,e,n){return e=(n?uo(t,e,n):void 0===e)?1:ia(e),Yr(ua(t),e)},An.replace=function(){var t=arguments,e=ua(t[0]);return t.length<3?e:e.replace(t[1],t[2])},An.result=function(t,e,n){var r=-1,i=(e=ui(e,t)).length;for(i||(i=1,t=void 0);++r9007199254740991)return[];var n=4294967295,r=un(t,4294967295);t-=4294967295;for(var i=Le(r,e=Ji(e));++n=o)return t;var a=n-Fe(r);if(a<1)return r;var u=s?ci(s,0,a).join(""):t.slice(0,a);if(void 0===i)return u+r;if(s&&(a+=u.length-a),Ks(i)){if(t.slice(a).search(i)){var l,c=u;for(i.global||(i=dt(i.source,ua(nt.exec(i))+"g")),i.lastIndex=0;l=i.exec(c);)var h=l.index;u=u.slice(0,void 0===h?a:h)}}else if(t.indexOf(Zr(i),a)!=a){var f=u.lastIndexOf(i);f>-1&&(u=u.slice(0,f))}return u+r},An.unescape=function(t){return(t=ua(t))&&j.test(t)?t.replace(D,Ge):t},An.uniqueId=function(t){var e=++Pt;return ua(t)+e},An.upperCase=Xa,An.upperFirst=Na,An.each=us,An.eachRight=ls,An.first=$o,Ja(An,(hu={},lr(An,(function(t,e){xt.call(An.prototype,e)||(hu[e]=t)})),hu),{chain:!1}),An.VERSION="4.17.21",se(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(t){An[t].placeholder=An})),se(["drop","take"],(function(t,e){En.prototype[t]=function(n){n=void 0===n?1:an(ia(n),0);var r=this.__filtered__&&!e?new En(this):this.clone();return r.__filtered__?r.__takeCount__=un(n,r.__takeCount__):r.__views__.push({size:un(n,4294967295),type:t+(r.__dir__<0?"Right":"")}),r},En.prototype[t+"Right"]=function(e){return this.reverse()[t](e).reverse()}})),se(["filter","map","takeWhile"],(function(t,e){var n=e+1,r=1==n||3==n;En.prototype[t]=function(t){var e=this.clone();return e.__iteratees__.push({iteratee:Ji(t,3),type:n}),e.__filtered__=e.__filtered__||r,e}})),se(["head","last"],(function(t,e){var n="take"+(e?"Right":"");En.prototype[t]=function(){return this[n](1).value()[0]}})),se(["initial","tail"],(function(t,e){var n="drop"+(e?"":"Right");En.prototype[t]=function(){return this.__filtered__?new En(this):this[n](1)}})),En.prototype.compact=function(){return this.filter(qa)},En.prototype.find=function(t){return this.filter(t).head()},En.prototype.findLast=function(t){return this.reverse().find(t)},En.prototype.invokeMap=Xr((function(t,e){return"function"==typeof t?new En(this):this.map((function(n){return _r(n,t,e)}))})),En.prototype.reject=function(t){return this.filter(Cs(Ji(t)))},En.prototype.slice=function(t,e){t=ia(t);var n=this;return n.__filtered__&&(t>0||e<0)?new En(n):(t<0?n=n.takeRight(-t):t&&(n=n.drop(t)),void 0!==e&&(n=(e=ia(e))<0?n.dropRight(-e):n.take(e-t)),n)},En.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},En.prototype.toArray=function(){return this.take(4294967295)},lr(En.prototype,(function(t,e){var n=/^(?:filter|find|map|reject)|While$/.test(e),r=/^(?:head|last)$/.test(e),i=An[r?"take"+("last"==e?"Right":""):e],o=r||/^find/.test(e);i&&(An.prototype[e]=function(){var e=this.__wrapped__,s=r?[1]:arguments,a=e instanceof En,u=s[0],l=a||Is(e),c=function(t){var e=i.apply(An,pe([t],s));return r&&h?e[0]:e};l&&n&&"function"==typeof u&&1!=u.length&&(a=l=!1);var h=this.__chain__,f=!!this.__actions__.length,p=o&&!h,g=a&&!f;if(!o&&l){e=g?e:new En(this);var d=t.apply(e,s);return d.__actions__.push({func:rs,args:[c],thisArg:void 0}),new On(d,h)}return p&&g?t.apply(this,s):(d=this.thru(c),p?r?d.value()[0]:d.value():d)})})),se(["pop","push","shift","sort","splice","unshift"],(function(t){var e=yt[t],n=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",r=/^(?:pop|shift)$/.test(t);An.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var i=this.value();return e.apply(Is(i)?i:[],t)}return this[n]((function(n){return e.apply(Is(n)?n:[],t)}))}})),lr(En.prototype,(function(t,e){var n=An[e];if(n){var r=n.name+"";xt.call(bn,r)||(bn[r]=[]),bn[r].push({name:e,func:n})}})),bn[Ai(void 0,2).name]=[{name:"wrapper",func:void 0}],En.prototype.clone=function(){var t=new En(this.__wrapped__);return t.__actions__=yi(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=yi(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=yi(this.__views__),t},En.prototype.reverse=function(){if(this.__filtered__){var t=new En(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},En.prototype.value=function(){var t=this.__wrapped__.value(),e=this.__dir__,n=Is(t),r=e<0,i=n?t.length:0,o=function(t,e,n){var r=-1,i=n.length;for(;++r=this.__values__.length;return{done:t,value:t?void 0:this.__values__[this.__index__++]}},An.prototype.plant=function(t){for(var e,n=this;n instanceof Mn;){var r=Ao(n);r.__index__=0,r.__values__=void 0,e?i.__wrapped__=r:e=r;var i=r;n=n.__wrapped__}return i.__wrapped__=t,e},An.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof En){var e=t;return this.__actions__.length&&(e=new En(this)),(e=e.reverse()).__actions__.push({func:rs,args:[Ho],thisArg:void 0}),new On(e,this.__chain__)}return this.thru(Ho)},An.prototype.toJSON=An.prototype.valueOf=An.prototype.value=function(){return ri(this.__wrapped__,this.__actions__)},An.prototype.first=An.prototype.head,Jt&&(An.prototype[Jt]=function(){return this}),An}();Wt._=Ke,void 0===(r=function(){return Ke}.call(e,n,e,t))||(t.exports=r)}).call(this)}).call(this,n(75)(t))},299:function(t,e,n){},300:function(t,e,n){},301:function(t,e,n){},302:function(t,e,n){},303:function(t,e,n){},304:function(t,e,n){},305:function(t,e){t.exports=function(t){return null==t}},306:function(t,e,n){},307:function(t,e,n){},308:function(t,e,n){},309:function(t,e,n){},310:function(t,e,n){},311:function(t,e,n){},312:function(t,e,n){},313:function(t,e,n){},314:function(t,e,n){},315:function(t,e,n){},316:function(t,e,n){},317:function(t,e,n){},318:function(t,e,n){},319:function(t,e,n){},320:function(t,e,n){},321:function(t,e,n){},323:function(t,e,n){"use strict";n.r(e);n(4),n(72);var r=n(21),i={name:"SidebarGroup",props:["item","open","collapsable","depth"],components:{DropdownTransition:n(324).a},beforeCreate(){this.$options.components.SidebarLinks=n(323).default},methods:{isActive:r.f}},o=(n(359),n(15)),s=Object(o.a)(i,(function(){var t=this,e=t._self._c;return e("section",{staticClass:"sidebar-group",class:[{collapsable:t.collapsable,"is-sub-group":0!==t.depth},"depth-"+t.depth]},[t.item.path?e("router-link",{staticClass:"sidebar-heading clickable",class:{open:t.open,active:t.isActive(t.$route,t.item.path)},attrs:{to:t.item.path},nativeOn:{click:function(e){return t.$emit("toggle")}}},[e("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?e("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]):e("p",{staticClass:"sidebar-heading",class:{open:t.open},on:{click:function(e){return t.$emit("toggle")}}},[e("span",[t._v(t._s(t.item.title))]),t._v(" "),t.collapsable?e("span",{staticClass:"arrow",class:t.open?"down":"right"}):t._e()]),t._v(" "),e("DropdownTransition",[t.open||!t.collapsable?e("SidebarLinks",{staticClass:"sidebar-group-items",attrs:{items:t.item.children,"sidebar-depth":t.item.sidebarDepth,"initial-open-group-index":t.item.initialOpenGroupIndex,depth:t.depth+1}}):t._e()],1)],1)}),[],!1,null,null,null).exports;n(22);function a(t,e,n,r){return t("router-link",{props:{to:e,activeClass:"",exactActiveClass:""},class:{active:r,"sidebar-link":!0}},n)}function u(t,e,n,i,o,s=1){return!e||s>o?null:t("ul",{class:"sidebar-sub-headers"},e.map(e=>{const l=Object(r.f)(i,n+"#"+e.slug);return t("li",{class:"sidebar-sub-header level"+e.level},[a(t,n+"#"+e.slug,e.title,l),u(t,e.children,n,i,o,s+1)])}))}var l={functional:!0,props:["item","sidebarDepth"],render(t,{parent:{$page:e,$site:n,$route:i,$themeConfig:o,$themeLocaleConfig:s},props:{item:l,sidebarDepth:c}}){const h=Object(r.f)(i,l.path),f="auto"===l.type?h||l.children.some(t=>Object(r.f)(i,l.basePath+"#"+t.slug)):h,p="external"===l.type?function(t,e,n){return t("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},class:{"sidebar-link":!0}},[n,t("OutboundLink")])}(t,l.path,l.title||l.path):a(t,l.path,l.title||l.path,f),g=[e.frontmatter.sidebarDepth,c,s.sidebarDepth,o.sidebarDepth,1].find(t=>void 0!==t),d=s.displayAllHeaders||o.displayAllHeaders;if("auto"===l.type)return[p,u(t,l.children,l.basePath,i,g)];if((f||d)&&l.headers&&!r.e.test(l.path)){return[p,u(t,Object(r.d)(l.headers),l.path,i,g)]}return p}};n(360);function c(t,e){return"group"===e.type&&e.children.some(e=>"group"===e.type?c(t,e):"page"===e.type&&Object(r.f)(t,e.path))}var h={name:"SidebarLinks",components:{SidebarGroup:s,SidebarLink:Object(o.a)(l,void 0,void 0,!1,null,null,null).exports},props:["items","depth","sidebarDepth","initialOpenGroupIndex"],data(){return{openGroupIndex:this.initialOpenGroupIndex||0}},created(){this.refreshIndex()},watch:{$route(){this.refreshIndex()}},methods:{refreshIndex(){const t=function(t,e){for(let n=0;n-1&&(this.openGroupIndex=t)},toggleGroup(t){this.openGroupIndex=t===this.openGroupIndex?-1:t},isActive(t){return Object(r.f)(this.$route,t.regularPath)}}},f=Object(o.a)(h,(function(){var t=this,e=t._self._c;return t.items.length?e("ul",{staticClass:"sidebar-links"},t._l(t.items,(function(n,r){return e("li",{key:r},["group"===n.type?e("SidebarGroup",{attrs:{item:n,open:r===t.openGroupIndex,collapsable:n.collapsable||n.collapsible,depth:t.depth},on:{toggle:function(e){return t.toggleGroup(r)}}}):e("SidebarLink",{attrs:{sidebarDepth:t.sidebarDepth,item:n}})],1)})),0):t._e()}),[],!1,null,null,null);e.default=f.exports},324:function(t,e,n){"use strict";var r={name:"DropdownTransition",methods:{setHeight(t){t.style.height=t.scrollHeight+"px"},unsetHeight(t){t.style.height=""}}},i=(n(345),n(15)),o=Object(i.a)(r,(function(){return(0,this._self._c)("transition",{attrs:{name:"dropdown"},on:{enter:this.setHeight,"after-enter":this.unsetHeight,"before-leave":this.setHeight}},[this._t("default")],2)}),[],!1,null,null,null);e.a=o.exports},326:function(t,e,n){"use strict";n(289)},327:function(t,e,n){"use strict";n(290)},328:function(t,e,n){"use strict";n(291)},329:function(t,e,n){"use strict";n(292)},330:function(t,e,n){"use strict";n(293)},331:function(t,e,n){"use strict";n(294)},332:function(t,e,n){"use strict";n(295)},333:function(t,e,n){"use strict";n(296)},334:function(t,e,n){"use strict";var r=n(47),i=n(2),o=n(49),s=n(297),a=URLSearchParams,u=a.prototype,l=i(u.append),c=i(u.delete),h=i(u.forEach),f=i([].push),p=new a("a=1&a=2&b=3");p.delete("a",1),p.delete("b",void 0),p+""!="a=2"&&r(u,"delete",(function(t){var e=arguments.length,n=e<2?void 0:arguments[1];if(e&&void 0===n)return c(this,t);var r=[];h(this,(function(t,e){f(r,{key:e,value:t})})),s(e,1);for(var i,a=o(t),u=o(n),p=0,g=0,d=!1,v=r.length;p1?arguments[1]:void 0)}}),o("findLastIndex")},338:function(t,e,n){"use strict";var r=n(132),i=n(73),o=n(34),s=n(30),a=function(t){var e=1===t;return function(n,a,u){for(var l,c=o(n),h=i(c),f=s(h),p=r(a,u);f-- >0;)if(p(l=h[f],f,c))switch(t){case 0:return l;case 1:return f}return e?-1:void 0}};t.exports={findLast:a(0),findLastIndex:a(1)}},339:function(t,e,n){"use strict";var r=n(17),i=n(74),o=n(19).f,s=r("unscopables"),a=Array.prototype;void 0===a[s]&&o(a,s,{configurable:!0,value:i(null)}),t.exports=function(t){a[s][t]=!0}},340:function(t,e,n){"use strict";var r=n(10),i=n(6),o=n(48),s=n(11),a=n(5),u=n(28),l=n(12),c=n(29)("every",TypeError);r({target:"Iterator",proto:!0,real:!0,forced:c},{every:function(t){a(this);try{s(t)}catch(t){l(this,"throw",t)}if(c)return i(c,this,t);var e=u(this),n=0;return!o(e,(function(e,r){if(!t(e,n++))return r()}),{IS_RECORD:!0,INTERRUPTED:!0}).stopped}})},341:function(t,e,n){"use strict";var r=n(10),i=n(6),o=n(48),s=n(11),a=n(5),u=n(28),l=n(12),c=n(29)("find",TypeError);r({target:"Iterator",proto:!0,real:!0,forced:c},{find:function(t){a(this);try{s(t)}catch(t){l(this,"throw",t)}if(c)return i(c,this,t);var e=u(this),n=0;return o(e,(function(e,r){if(t(e,n++))return r(e)}),{IS_RECORD:!0,INTERRUPTED:!0}).result}})},342:function(t,e,n){"use strict";!function(e,n,r){let i;(i=r.define)&&i.amd?i([],(function(){return n})):(i=r.modules)?i["FlexSearch".toLowerCase()]=n:t.exports=n}(0,function t(e){function n(t,e){const n=e?e.id:t&&t.id;this.id=n||0===n?n:A++,this.init(t,e),s(this,"index",(function(){return this.a?Object.keys(this.a.index[this.a.keys[0]].c):Object.keys(this.c)})),s(this,"length",(function(){return this.index.length}))}function r(t,e,n,r){return this.u!==this.g&&(this.o=this.o.concat(n),this.u++,r&&this.o.length>=r&&(this.u=this.g),this.u===this.g&&(this.cache&&this.j.set(e,this.o),this.F&&this.F(this.o))),this}function i(t,e){const n=t.length,r=_(e),i=[];for(let o=0,s=0;o=s&&((t=(t=t[a-(i+.5>>0)])[n]||(t[n]=[]))[t.length]=r),i)}function c(t,e){if(t){const n=Object.keys(t);for(let r=0,i=n.length;r(t=t.length-e.length)?1:t?-1:0}function p(t,e){return(t=t[O])<(e=e[O])?-1:t>e?1:0}function g(t,e){const n=O.length;for(let r=0;re?1:0}function d(t,e,n){return t?{page:t,next:e?""+e:null,result:n}:n}function v(t,e,n,r,i,o,s){let a,u=[];if(!0===n){n="0";var l=""}else l=n&&n.split(":");const c=t.length;if(1s&&(l=0),a=(l=l||0)+e,a=this.m.length&&(this.C=0),this.m[this.C].postMessage({add:!0,id:t,content:e}),this.c[s]=""+this.C,n&&n(),this;if(!o){if(this.async&&"function"!=typeof importScripts){let i=this;return s=new Promise((function(n){setTimeout((function(){i.add(t,e,null,r,!0),i=null,n()}))})),n?(s.then(n),this):s}if(n)return this.add(t,e,null,r,!0),n(),this}if(!(e=this.encode(e)).length)return this;o=_(n=this.f)?n(e):e.split(this.split),this.filter&&(o=i(o,this.filter));const p=x();p._ctx=x();const g=o.length,d=this.threshold,v=this.depth,m=this.b,y=this.i,b=this.D;for(let e=0;ef;n--)l(y,p,h=a.substring(f,n),t,e,c,d,m-1)}break;default:if(u=l(y,p,a,t,1,c,d,m-1),v&&1=d)for(u=p._ctx[a]||(p._ctx[a]=x()),a=this.h[a]||(this.h[a]=k(m-(d||0))),0>(c=e-v)&&(c=0),(h=e+v+1)>g&&(h=g);ci;n--)r=o[n-1],o[n]=r,e[r]=n;o[i]=t,e[t]=i}}}return e},t}();return n}(function(){const t={},e="undefined"!=typeof Blob&&"undefined"!=typeof URL&&URL.createObjectURL;return function(n,r,i,o,s){return i=e?URL.createObjectURL(new Blob(["("+i.toString()+")()"],{type:"text/javascript"})):n+".min.js",t[n+="-"+r]||(t[n]=[]),t[n][s]=new Worker(i),t[n][s].onmessage=o,t[n][s]}}()),this)},343:function(t,e,n){"use strict";n(299)},344:function(t,e,n){"use strict";n(300)},345:function(t,e,n){"use strict";n(301)},346:function(t,e,n){"use strict";n(302)},347:function(t,e,n){"use strict";n(303)},348:function(t,e,n){"use strict";n(304)},349:function(t,e,n){"use strict";n(306)},350:function(t,e,n){var r=n(31),i=n(13),o=n(23);t.exports=function(t){return"string"==typeof t||!i(t)&&o(t)&&"[object String]"==r(t)}},351:function(t,e,n){"use strict";n(307)},352:function(t,e,n){"use strict";n(308)},353:function(t,e,n){"use strict";n(309)},354:function(t,e,n){"use strict";n(310)},355:function(t,e,n){"use strict";n(311)},356:function(t,e,n){"use strict";n(312)},357:function(t,e,n){"use strict";n(313)},358:function(t,e,n){"use strict";n(314)},359:function(t,e,n){"use strict";n(315)},360:function(t,e,n){"use strict";n(316)},361:function(t,e,n){"use strict";n(317)},362:function(t,e,n){"use strict";n(318)},363:function(t,e,n){"use strict";n(319)},364:function(t,e,n){"use strict";n(320)},365:function(t,e,n){"use strict";n(321)},367:function(t,e,n){"use strict";n.r(e);n(4),n(72);var r=n(21),i={props:{item:{required:!0}},computed:{link(){return Object(r.c)(this.item.link)},exact(){return this.$site.locales?Object.keys(this.$site.locales).some(t=>t===this.link):"/"===this.link}},methods:{isExternal:r.g,isMailto:r.h,isTel:r.i,focusoutAction(){this.$emit("focusout")}}},o=n(15),s=Object(o.a)(i,(function(){var t=this,e=t._self._c;return t.isExternal(t.link)?e("a",{staticClass:"nav-link external",attrs:{href:t.link,target:t.isMailto(t.link)||t.isTel(t.link)?null:"_blank",rel:t.isMailto(t.link)||t.isTel(t.link)?null:"noopener noreferrer"},on:{focusout:t.focusoutAction}},[t._v("\n "+t._s(t.item.text)+"\n "),e("OutboundLink")],1):e("router-link",{staticClass:"nav-link",attrs:{to:t.link,exact:t.exact},nativeOn:{focusout:function(e){return t.focusoutAction.apply(null,arguments)}}},[t._v(t._s(t.item.text))])}),[],!1,null,null,null).exports,a=function(t,e){return(a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])})(t,e)};function u(t,e){function n(){this.constructor=t}a(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}var l=function(){return(l=Object.assign||function(t){for(var e,n=1,r=arguments.length;n0,m=function(){if("string"==typeof g){var t=/os (\d\d?_\d(_\d)?)/.exec(g);if(!t)return!1;var e=t[1].split("_").map((function(t){return parseInt(t,10)}));return!!(13===e[0]&&e[1]>=4)}return!1}(),y=!1;if(p){try{var _={};Object.defineProperty(_,"passive",{get:function(){y=!0}}),window.addEventListener("test-passive",(function(){}),_)}catch(t){}}function b(){return window.performance&&window.performance.now&&window.performance.timing?window.performance.now()+window.performance.timing.navigationStart:+new Date}var w=function(t,e){for(var n in e)t[n]=e[n];return t};function k(t){return null==t}function x(t,e,n){return tn?n:t}var P=p&&document.createElement("div").style,C=function(){if(!p)return!1;for(var t=0,e=[{key:"standard",value:"transform"},{key:"webkit",value:"webkitTransform"},{key:"Moz",value:"MozTransform"},{key:"O",value:"OTransform"},{key:"ms",value:"msTransform"}];tdocument.documentElement.clientWidth-u||a>document.documentElement.clientHeight-u||s0?-1:n<0?1:0},o=i(e.x,t.x),s=i(e.y,t.y),a=n.x-r.x,u=n.y-r.y;return o*a<=0&&s*u<=0})(t,e,o,r)&&n.hooks.trigger(n.hooks.eventTypes.move,o),n.pending||(n.callStopWhenPending?n.callStopWhenPending=!1:n.hooks.trigger(n.hooks.eventTypes.end,o)),r=o,n.pending&&(n.timer=W(i))};this.callStopWhenPending&&this.setCallStop(!1),q(this.timer),i()},e.prototype.transitionTime=function(t){void 0===t&&(t=0),this.style[j.transitionDuration]=t+"ms",this.hooks.trigger(this.hooks.eventTypes.time,t)},e.prototype.transitionTimingFunction=function(t){this.style[j.transitionTimingFunction]=t,this.hooks.trigger(this.hooks.eventTypes.timeFunction,t)},e.prototype.transitionProperty=function(){this.style[j.transitionProperty]=j.transform},e.prototype.move=function(t,e,n,r){this.setPending(n>0),this.transitionTimingFunction(r),this.transitionProperty(),this.transitionTime(n),this.translate(e);var i=3===this.options.probeType;n&&i&&this.startProbe(t,e),n||(this._reflow=this.content.offsetHeight,i&&this.hooks.trigger(this.hooks.eventTypes.move,e),this.hooks.trigger(this.hooks.eventTypes.end,e))},e.prototype.doStop=function(){var t=this.pending;if(this.setForceStopped(!1),this.setCallStop(!1),t){this.setPending(!1),q(this.timer);var e=this.translater.getComputedPosition(),n=e.x,r=e.y;this.transitionTime(),this.translate({x:n,y:r}),this.setForceStopped(!0),this.setCallStop(!0),this.hooks.trigger(this.hooks.eventTypes.forceStop,{x:n,y:r})}return t},e.prototype.stop=function(){this.doStop()&&this.hooks.trigger(this.hooks.eventTypes.callStop)},e}(nt),it=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return u(e,t),e.prototype.move=function(t,e,n,r){if(!n)return this.translate(e),3===this.options.probeType&&this.hooks.trigger(this.hooks.eventTypes.move,e),void this.hooks.trigger(this.hooks.eventTypes.end,e);this.animate(t,e,n,r)},e.prototype.animate=function(t,e,n,r){var i=this,o=b(),s=o+n,a=3===this.options.probeType,u=function(){var l=b();if(l>=s)return i.translate(e),a&&i.hooks.trigger(i.hooks.eventTypes.move,e),void i.hooks.trigger(i.hooks.eventTypes.end,e);var c=r(l=(l-o)/n),h={};Object.keys(e).forEach((function(n){var r=t[n],i=e[n];h[n]=(i-r)*c+r})),i.translate(h),a&&i.hooks.trigger(i.hooks.eventTypes.move,h),i.pending&&(i.timer=W(u)),i.pending||(i.callStopWhenPending?i.callStopWhenPending=!1:i.hooks.trigger(i.hooks.eventTypes.end,e))};this.setPending(!0),this.callStopWhenPending&&this.setCallStop(!1),q(this.timer),u()},e.prototype.doStop=function(){var t=this.pending;if(this.setForceStopped(!1),this.setCallStop(!1),t){this.setPending(!1),q(this.timer);var e=this.translater.getComputedPosition();this.setForceStopped(!0),this.setCallStop(!0),this.hooks.trigger(this.hooks.eventTypes.forceStop,e)}return t},e.prototype.stop=function(){this.doStop()&&this.hooks.trigger(this.hooks.eventTypes.callStop)},e}(nt);var ot,st,at,ut,lt=function(){function t(t,e,n){this.wrapper=t,this.options=n,this.hooks=new Q(["beforeComputeBoundary","computeBoundary","momentum","end","ignoreHasScroll"]),this.refresh(e)}return t.prototype.start=function(){this.dist=0,this.setMovingDirection(0),this.setDirection(0)},t.prototype.move=function(t){return t=this.hasScroll?t:0,this.setMovingDirection(t),this.performDampingAlgorithm(t,this.options.outOfBoundaryDampingFactor)},t.prototype.setMovingDirection=function(t){this.movingDirection=t>0?-1:t<0?1:0},t.prototype.setDirection=function(t){this.direction=t>0?-1:t<0?1:0},t.prototype.performDampingAlgorithm=function(t,e){var n=this.currentPos+t;return(n>this.minScrollPos||nthis.minScrollPos&&this.options.bounces[0]||nthis.minScrollPos?this.minScrollPos:this.maxScrollPos),n},t.prototype.end=function(t){var e={duration:0},n=Math.abs(this.currentPos-this.startPos);if(this.options.momentum&&tthis.options.momentumLimitDistance){var r=-1===this.direction&&this.options.bounces[0]||1===this.direction&&this.options.bounces[1]?this.wrapperSize:0;e=this.hasScroll?this.momentum(this.currentPos,this.startPos,t,this.maxScrollPos,this.minScrollPos,r,this.options):{destination:this.currentPos,duration:0}}else this.hooks.trigger(this.hooks.eventTypes.end,e);return e},t.prototype.momentum=function(t,e,n,r,i,o,s){void 0===s&&(s=this.options);var a=t-e,u=Math.abs(a)/n,l=s.deceleration,c=s.swipeBounceTime,h=s.swipeTime,f={destination:t+u*u/l*(a<0?-1:1),duration:Math.min(h,2*u/l),rate:15};return this.hooks.trigger(this.hooks.eventTypes.momentum,f,a),f.destinationi&&(f.destination=o?Math.min(i+o/4,i+o/f.rate*u):i,f.duration=c),f.destination=Math.round(f.destination),f},t.prototype.updateDirection=function(){var t=this.currentPos-this.absStartPos;this.setDirection(t)},t.prototype.refresh=function(t){var e=this.options.rect,n=e.size,r=e.position,i="static"===window.getComputedStyle(this.wrapper,null).position,o=X(this.wrapper);this.wrapperSize=this.wrapper["width"===n?"clientWidth":"clientHeight"],this.setContent(t);var s=X(this.content);this.contentSize=s[n],this.relativeOffset=s[r],i&&(this.relativeOffset-=o[r]),this.computeBoundary(),this.setDirection(0)},t.prototype.setContent=function(t){t!==this.content&&(this.content=t,this.resetState())},t.prototype.resetState=function(){this.currentPos=0,this.startPos=0,this.dist=0,this.setDirection(0),this.setMovingDirection(0),this.resetStartPos()},t.prototype.computeBoundary=function(){this.hooks.trigger(this.hooks.eventTypes.beforeComputeBoundary);var t={minScrollPos:0,maxScrollPos:this.wrapperSize-this.contentSize};t.maxScrollPos<0&&(t.maxScrollPos-=this.relativeOffset,0===this.options.specifiedIndexAsContent&&(t.minScrollPos=-this.relativeOffset)),this.hooks.trigger(this.hooks.eventTypes.computeBoundary,t),this.minScrollPos=t.minScrollPos,this.maxScrollPos=t.maxScrollPos,this.hasScroll=this.options.scrollable&&this.maxScrollPosthis.minScrollPos?t=this.minScrollPos:te+this.directionLockThreshold?this.directionLocked="horizontal":e>=t+this.directionLockThreshold?this.directionLocked="vertical":this.directionLocked="none")},t.prototype.handleEventPassthrough=function(t){var e=ht[this.directionLocked];if(e){if(this.eventPassthrough===e.yes)return ct.yes(t);if(this.eventPassthrough===e.no)return ct.no(t)}return!1},t}(),pt=function(){function t(t,e,n,r,i){this.hooks=new Q(["start","beforeMove","scrollStart","scroll","beforeEnd","end","scrollEnd","contentNotMoved","detectMovingDirection","coordinateTransformation"]),this.scrollBehaviorX=t,this.scrollBehaviorY=e,this.actionsHandler=n,this.animater=r,this.options=i,this.directionLockAction=new ft(i.directionLockThreshold,i.freeScroll,i.eventPassthrough),this.enabled=!0,this.bindActionsHandler()}return t.prototype.bindActionsHandler=function(){var t=this;this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.start,(function(e){return!t.enabled||t.handleStart(e)})),this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.move,(function(e){var n=e.deltaX,r=e.deltaY,i=e.e;if(!t.enabled)return!0;var o=function(t,e,n){return 2===n?[e,-t]:3===n?[-t,-e]:4===n?[-e,t]:[t,e]}(n,r,t.options.quadrant),s={deltaX:o[0],deltaY:o[1]};return t.hooks.trigger(t.hooks.eventTypes.coordinateTransformation,s),t.handleMove(s.deltaX,s.deltaY,i)})),this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.end,(function(e){return!t.enabled||t.handleEnd(e)})),this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.click,(function(e){t.enabled&&!e._constructed&&t.handleClick(e)}))},t.prototype.handleStart=function(t){var e=b();this.fingerMoved=!1,this.contentMoved=!1,this.startTime=e,this.directionLockAction.reset(),this.scrollBehaviorX.start(),this.scrollBehaviorY.start(),this.animater.doStop(),this.scrollBehaviorX.resetStartPos(),this.scrollBehaviorY.resetStartPos(),this.hooks.trigger(this.hooks.eventTypes.start,t)},t.prototype.handleMove=function(t,e,n){if(!this.hooks.trigger(this.hooks.eventTypes.beforeMove,n)){var r=this.scrollBehaviorX.getAbsDist(t),i=this.scrollBehaviorY.getAbsDist(e),o=b();if(this.checkMomentum(r,i,o))return!0;if(this.directionLockAction.checkMovingDirection(r,i,n))return this.actionsHandler.setInitiated(),!0;var s=this.directionLockAction.adjustDelta(t,e),a=this.scrollBehaviorX.getCurrentPos(),u=this.scrollBehaviorX.move(s.deltaX),l=this.scrollBehaviorY.getCurrentPos(),c=this.scrollBehaviorY.move(s.deltaY);if(!this.hooks.trigger(this.hooks.eventTypes.detectMovingDirection)){this.fingerMoved||(this.fingerMoved=!0);var h=u!==a||c!==l;this.contentMoved||h||this.hooks.trigger(this.hooks.eventTypes.contentNotMoved),!this.contentMoved&&h&&(this.contentMoved=!0,this.hooks.trigger(this.hooks.eventTypes.scrollStart)),this.contentMoved&&h&&(this.animater.translate({x:u,y:c}),this.dispatchScroll(o))}}},t.prototype.dispatchScroll=function(t){t-this.startTime>this.options.momentumLimitTime&&(this.startTime=t,this.scrollBehaviorX.updateStartPos(),this.scrollBehaviorY.updateStartPos(),1===this.options.probeType&&this.hooks.trigger(this.hooks.eventTypes.scroll,this.getCurrentPos())),this.options.probeType>1&&this.hooks.trigger(this.hooks.eventTypes.scroll,this.getCurrentPos())},t.prototype.checkMomentum=function(t,e,n){return n-this.endTime>this.options.momentumLimitTime&&e0?Math.ceil(e):Math.floor(e),n=n>0?Math.ceil(n):Math.floor(n),{x:e=x(e,o,i),y:n=x(n,u,a)}},t.prototype.handleClick=function(t){N(t.target,this.options.preventDefaultException)||(B(t),t.stopPropagation())},t.prototype.getCurrentPos=function(){return{x:this.scrollBehaviorX.getCurrentPos(),y:this.scrollBehaviorY.getCurrentPos()}},t.prototype.refresh=function(){this.endTime=0},t.prototype.destroy=function(){this.hooks.destroy()},t}();function gt(t,e,n,r){var i=["momentum","momentumLimitTime","momentumLimitDistance","deceleration","swipeBounceTime","swipeTime","outOfBoundaryDampingFactor","specifiedIndexAsContent"].reduce((function(e,n){return e[n]=t[n],e}),{});return i.scrollable=!!t[e],i.bounces=n,i.rect=r,i}function dt(t,e,n){n.forEach((function(n){var r,i;"string"==typeof n?r=i=n:(r=n.source,i=n.target),t.on(r,(function(){for(var t=[],n=0;n1&&t1||e>1))return!0},t.prototype.momentum=function(t,e){var n={time:0,easing:U.swiper,newX:t.x,newY:t.y},r=this.scrollBehaviorX.end(e),i=this.scrollBehaviorY.end(e);if(n.newX=k(r.destination)?n.newX:r.destination,n.newY=k(i.destination)?n.newY:i.destination,n.time=Math.max(r.duration,i.duration),this.hooks.trigger(this.hooks.eventTypes.momentum,n,this),n.newX!==t.x||n.newY!==t.y)return(n.newX>this.scrollBehaviorX.minScrollPos||n.newXthis.scrollBehaviorY.minScrollPos||n.newY=4)}}();if(wt){try{var xt={};Object.defineProperty(xt,"passive",{get:function(){!0}}),window.addEventListener("test-passive",(function(){}),xt)}catch(t){}}var Pt=function(t,e){for(var n in e)t[n]=e[n];return t};function Ct(t,e,n){return tn?n:t}var Tt=wt&&document.createElement("div").style,St=function(){if(!wt)return!1;for(var t=0,e=[{key:"standard",value:"transform"},{key:"webkit",value:"webkitTransform"},{key:"Moz",value:"MozTransform"},{key:"O",value:"OTransform"},{key:"ms",value:"msTransform"}];t=this.pages[n][0].cx);n++);for(i=this.pages[n]?this.pages[n].length:0;r=this.pages[0][r].cy);r++);return{pageX:n,pageY:r}},t.prototype.buildPagesMatrix=function(t,e){var n,r,i,o,s=[],a=0,u=0,l=this.scroll.scroller.scrollBehaviorX.maxScrollPos,c=this.scroll.scroller.scrollBehaviorY.maxScrollPos;for(r=Math.round(t/2),i=Math.round(e/2);a>-this.scrollerWidth;){for(s[u]=[],o=0,n=0;n>-this.scrollerHeight;)s[u][o]={x:Math.max(a,l),y:Math.max(n,c),width:t,height:e,cx:a-r,cy:n-i},n-=e,o++;a-=t,u++}return s},t}(),Et=function(){function t(t,e){this.scroll=t,this.slideOptions=e,this.slideX=!1,this.slideY=!1,this.currentPage=Pt({},Bt)}return t.prototype.refresh=function(){this.pagesMatrix=new Ot(this.scroll),this.checkSlideLoop(),this.currentPage=this.getAdjustedCurrentPage()},t.prototype.getAdjustedCurrentPage=function(){var t=this.currentPage,e=t.pageX,n=t.pageY;e=Math.min(e,this.pagesMatrix.pageLengthOfX-1),n=Math.min(n,this.pagesMatrix.pageLengthOfY-1),this.loopX&&(e=Math.min(e,this.pagesMatrix.pageLengthOfX-2)),this.loopY&&(n=Math.min(n,this.pagesMatrix.pageLengthOfY-2));var r=this.pagesMatrix.getPageStats(e,n);return{pageX:e,pageY:n,x:r.x,y:r.y}},t.prototype.setCurrentPage=function(t){this.currentPage=t},t.prototype.getInternalPage=function(t,e){t>=this.pagesMatrix.pageLengthOfX?t=this.pagesMatrix.pageLengthOfX-1:t<0&&(t=0),e>=this.pagesMatrix.pageLengthOfY?e=this.pagesMatrix.pageLengthOfY-1:e<0&&(e=0);var n=this.pagesMatrix.getPageStats(t,e);return{pageX:t,pageY:e,x:n.x,y:n.y}},t.prototype.getInitialPage=function(t,e){void 0===t&&(t=!1),void 0===e&&(e=!1);var n=this.slideOptions,r=n.startPageXIndex,i=n.startPageYIndex,o=this.loopX?1:0,s=this.loopY?1:0,a=t?o:this.currentPage.pageX,u=t?s:this.currentPage.pageY;e?(a=this.loopX?r+1:r,u=this.loopY?i+1:i):(a=t?o:this.currentPage.pageX,u=t?s:this.currentPage.pageY);var l=this.pagesMatrix.getPageStats(a,u);return{pageX:a,pageY:u,x:l.x,y:l.y}},t.prototype.getExposedPage=function(t){var e=Pt({},t);return this.loopX&&(e.pageX=this.fixedPage(e.pageX,this.pagesMatrix.pageLengthOfX-2)),this.loopY&&(e.pageY=this.fixedPage(e.pageY,this.pagesMatrix.pageLengthOfY-2)),e},t.prototype.getExposedPageByPageIndex=function(t,e){var n={pageX:t,pageY:e};this.loopX&&(n.pageX=t+1),this.loopY&&(n.pageY=e+1);var r=this.pagesMatrix.getPageStats(n.pageX,n.pageY);return{x:r.x,y:r.y,pageX:t,pageY:e}},t.prototype.getWillChangedPage=function(t){return t=Pt({},t),this.loopX&&(t.pageX=this.fixedPage(t.pageX,this.pagesMatrix.pageLengthOfX-2),t.x=this.pagesMatrix.getPageStats(t.pageX+1,0).x),this.loopY&&(t.pageY=this.fixedPage(t.pageY,this.pagesMatrix.pageLengthOfY-2),t.y=this.pagesMatrix.getPageStats(0,t.pageY+1).y),t},t.prototype.fixedPage=function(t,e){for(var n=[],r=0;r1?this.slideX=!0:this.slideX=!1,this.pagesMatrix.pages[0]&&this.pagesMatrix.pageLengthOfY>1?this.slideY=!0:this.slideY=!1,this.loopX=this.wannaLoop&&this.slideX,this.loopY=this.wannaLoop&&this.slideY,this.slideX&&this.slideY&&bt("slide does not support two direction at the same time.")},t}(),It=[{key:"next",name:"next"},{key:"prev",name:"prev"},{key:"goToPage",name:"goToPage"},{key:"getCurrentPage",name:"getCurrentPage"},{key:"startPlay",name:"startPlay"},{key:"pausePlay",name:"pausePlay"}].map((function(t){return{key:t.key,sourceKey:"plugins.slide."+t.name}})),Dt=function(){function t(t){this.scroll=t,this.cachedClonedPageDOM=[],this.resetLooping=!1,this.autoplayTimer=0,this.satisfyInitialization()&&this.init()}return t.prototype.satisfyInitialization=function(){return!(this.scroll.scroller.content.children.length<=0)||(bt("slide need at least one slide page to be initialised.please check your DOM layout."),!1)},t.prototype.init=function(){this.willChangeToPage=Pt({},Bt),this.handleBScroll(),this.handleOptions(),this.handleHooks(),this.createPages()},t.prototype.createPages=function(){this.pages=new Et(this.scroll,this.options)},t.prototype.handleBScroll=function(){this.scroll.registerType(["slideWillChange","slidePageChanged"]),this.scroll.proxy(It)},t.prototype.handleOptions=function(){var t=!0===this.scroll.options.slide?{}:this.scroll.options.slide,e={loop:!0,threshold:.1,speed:400,easing:At.bounce,listenFlick:!0,autoplay:!0,interval:3e3,startPageXIndex:0,startPageYIndex:0};this.options=Pt(e,t)},t.prototype.handleLoop=function(t){var e=this.options.loop,n=this.scroll.scroller.content,r=n.children.length;e&&(n!==t?(this.resetLoopChangedStatus(),this.removeClonedSlidePage(t),r>1&&this.cloneFirstAndLastSlidePage(n)):3===r&&this.initialised?(this.removeClonedSlidePage(n),this.moreToOnePageInLoop=!0,this.oneToMorePagesInLoop=!1):r>1?(this.initialised&&0===this.cachedClonedPageDOM.length?(this.oneToMorePagesInLoop=!0,this.moreToOnePageInLoop=!1):(this.removeClonedSlidePage(n),this.resetLoopChangedStatus()),this.cloneFirstAndLastSlidePage(n)):this.resetLoopChangedStatus())},t.prototype.resetLoopChangedStatus=function(){this.moreToOnePageInLoop=!1,this.oneToMorePagesInLoop=!1},t.prototype.handleHooks=function(){var t=this,e=this.scroll.hooks,n=this.scroll.scroller.hooks,r=this.options.listenFlick;this.prevContent=this.scroll.scroller.content,this.hooksFn=[],this.registerHooks(this.scroll,this.scroll.eventTypes.beforeScrollStart,this.pausePlay),this.registerHooks(this.scroll,this.scroll.eventTypes.scrollEnd,this.modifyCurrentPage),this.registerHooks(this.scroll,this.scroll.eventTypes.scrollEnd,this.startPlay),this.scroll.eventTypes.mousewheelMove&&(this.registerHooks(this.scroll,this.scroll.eventTypes.mousewheelMove,(function(){return!0})),this.registerHooks(this.scroll,this.scroll.eventTypes.mousewheelEnd,(function(e){1!==e.directionX&&1!==e.directionY||t.next(),-1!==e.directionX&&-1!==e.directionY||t.prev()}))),this.registerHooks(e,e.eventTypes.refresh,this.refreshHandler),this.registerHooks(e,e.eventTypes.destroy,this.destroy),this.registerHooks(n,n.eventTypes.beforeRefresh,(function(){t.handleLoop(t.prevContent),t.setSlideInlineStyle()})),this.registerHooks(n,n.eventTypes.momentum,this.modifyScrollMetaHandler),this.registerHooks(n,n.eventTypes.scroll,this.scrollHandler),this.registerHooks(n,n.eventTypes.checkClick,this.startPlay),r&&this.registerHooks(n,n.eventTypes.flick,this.flickHandler)},t.prototype.startPlay=function(){var t=this,e=this.options,n=e.interval;e.autoplay&&(clearTimeout(this.autoplayTimer),this.autoplayTimer=window.setTimeout((function(){t.next()}),n))},t.prototype.pausePlay=function(){this.options.autoplay&&clearTimeout(this.autoplayTimer)},t.prototype.setSlideInlineStyle=function(){var t=this.scroll.scroller,e=t.content,n=t.wrapper,r=this.scroll.options;[{direction:"scrollX",sizeType:"offsetWidth",styleType:"width"},{direction:"scrollY",sizeType:"offsetHeight",styleType:"height"}].forEach((function(t){var i=t.direction,o=t.sizeType,s=t.styleType;if(r[i]){for(var a=n[o],u=e.children,l=u.length,c=0;c({sortPosts:[],postListOffsetTop:0}),created(){this.setPosts()},mounted(){},watch:{currentPage(){this.$route.query.p!=this.currentPage&&this.$router.push({query:{...this.$route.query,p:this.currentPage}}),this.setPosts()},category(){this.setPosts()},tag(){this.setPosts()}},methods:{setPosts(){const t=this.currentPage,e=this.perPage;let n=[];n=this.category?this.$groupPosts.categories[this.category]:this.tag?this.$groupPosts.tags[this.tag]:this.$sortPosts,this.sortPosts=n.slice((t-1)*e,t*e)}}}),Yt=(n(327),Object(o.a)(jt,(function(){var t=this,e=t._self._c;return e("div",{ref:"postList",staticClass:"post-list"},[e("transition-group",{attrs:{tag:"div",name:"post"}},t._l(t.sortPosts,(function(n){return e("div",{key:n.key,staticClass:"post card-box",class:n.frontmatter.sticky&&"iconfont icon-zhiding"},[e("div",{staticClass:"title-wrapper"},[e("h2",[e("router-link",{attrs:{to:n.path}},[t._v("\n "+t._s(n.title)+"\n "),n.frontmatter.titleTag?e("span",{staticClass:"title-tag"},[t._v(t._s(n.frontmatter.titleTag))]):t._e()])],1),t._v(" "),e("div",{staticClass:"article-info"},[n.author&&n.author.href?e("a",{staticClass:"iconfont icon-touxiang",attrs:{title:"作者",target:"_blank",href:n.author.href}},[t._v(t._s(n.author.name?n.author.name:n.author))]):n.author?e("span",{staticClass:"iconfont icon-touxiang",attrs:{title:"作者"}},[t._v(t._s(n.author.name?n.author.name:n.author))]):t._e(),t._v(" "),n.frontmatter.date?e("span",{staticClass:"iconfont icon-riqi",attrs:{title:"创建时间"}},[t._v(t._s(n.frontmatter.date.split(" ")[0]))]):t._e(),t._v(" "),!1!==t.$themeConfig.category&&n.frontmatter.categories?e("span",{staticClass:"iconfont icon-wenjian",attrs:{title:"分类"}},t._l(n.frontmatter.categories,(function(n,r){return e("router-link",{key:r,attrs:{to:"/categories/?category="+encodeURIComponent(n)}},[t._v(t._s(n))])})),1):t._e(),t._v(" "),!1!==t.$themeConfig.tag&&n.frontmatter.tags&&n.frontmatter.tags[0]?e("span",{staticClass:"iconfont icon-biaoqian tags",attrs:{title:"标签"}},t._l(n.frontmatter.tags,(function(n,r){return e("router-link",{key:r,attrs:{to:"/tags/?tag="+encodeURIComponent(n)}},[t._v(t._s(n))])})),1):t._e()])]),t._v(" "),n.excerpt?e("div",{staticClass:"excerpt-wrapper"},[e("div",{staticClass:"excerpt",domProps:{innerHTML:t._s(n.excerpt)}}),t._v(" "),e("router-link",{staticClass:"readmore iconfont icon-jiantou-you",attrs:{to:n.path}},[t._v("阅读全文")])],1):t._e()])})),0)],1)}),[],!1,null,null,null).exports),Xt=(n(16),{name:"UpdateArticle",props:{length:{type:[String,Number],default:3},moreArticle:String},data:()=>({posts:[],currentPath:""}),created(){this.posts=this.$site.pages,this.currentPath=this.$page.path},computed:{topPublishPosts(){return this.$sortPostsByDate?this.$sortPostsByDate.filter(t=>{const{path:e}=t;return e!==this.currentPath}).slice(0,this.length):[]},isShowArticle(){const{frontmatter:t}=this.$page;return!(!1!==t.article)}},methods:{getNum:t=>t<9?"0"+(t+1):t+1,getDate:t=>t.frontmatter.date?t.frontmatter.date.split(" ")[0].slice(5,10):""},watch:{$route(){this.currentPath=this.$page.path}}}),Nt=(n(328),Object(o.a)(Xt,(function(){var t=this,e=t._self._c;return e("div",{class:["article-list",{"no-article-list":t.isShowArticle}]},[e("div",{staticClass:"article-title"},[e("router-link",{staticClass:"iconfont icon-bi",attrs:{to:t.moreArticle||"/archives/"}},[t._v("最近更新")])],1),t._v(" "),e("div",{staticClass:"article-wrapper"},[t._l(t.topPublishPosts,(function(n,r){return e("dl",{key:r},[e("dd",[t._v(t._s(t.getNum(r)))]),t._v(" "),e("dt",[e("router-link",{attrs:{to:n.path}},[e("div",[t._v("\n "+t._s(n.title)+"\n "),n.frontmatter.titleTag?e("span",{staticClass:"title-tag"},[t._v("\n "+t._s(n.frontmatter.titleTag)+"\n ")]):t._e()])]),t._v(" "),e("span",{staticClass:"date"},[t._v(t._s(t.getDate(n)))])],1)])})),t._v(" "),e("dl",[e("dd"),t._v(" "),e("dt",[e("router-link",{staticClass:"more",attrs:{to:t.moreArticle||"/archives/"}},[t._v("更多文章>")])],1)])],2)])}),[],!1,null,null,null).exports),Rt={props:{total:{type:Number,default:10},perPage:{type:Number,default:10},currentPage:{type:Number,default:1}},computed:{pages(){return Math.ceil(this.total/this.perPage)}},methods:{threeNum(){let t=3;const e=this.currentPage,n=this.pages;return t=e<3?3:e>n-3?n-2:e,t},goPrex(){let t=this.currentPage;t>1&&this.handleEmit(--t)},goNext(){let t=this.currentPage;t3,expression:"currentPage > 3"}],staticClass:"ellipsis ell-two",attrs:{title:"上两页"},on:{click:function(e){return t.goIndex(t.currentPage-2)}}}),t._v(" "),e("span",{directives:[{name:"show",rawName:"v-show",value:t.currentPage<=3,expression:"currentPage <= 3"}],staticClass:"card-box",class:{active:2===t.currentPage},on:{click:function(e){return t.goIndex(2)}}},[t._v("2")]),t._v(" "),e("span",{staticClass:"card-box",class:{active:t.currentPage>=3&&t.currentPage<=t.pages-2},on:{click:function(e){t.goIndex(t.threeNum())}}},[t._v(t._s(t.threeNum()))]),t._v(" "),e("span",{directives:[{name:"show",rawName:"v-show",value:t.currentPage=t.pages-2,expression:"currentPage >= pages - 2"}],staticClass:"card-box",class:{active:t.currentPage===t.pages-1},on:{click:function(e){return t.goIndex(t.pages-1)}}},[t._v(t._s(t.pages-1))]),t._v(" "),e("span",{staticClass:"card-box",class:{active:t.currentPage===t.pages},on:{click:function(e){return t.goIndex(t.pages)}}},[t._v(t._s(t.pages))])]),t._v(" "),e("span",{staticClass:"card-box next iconfont icon-jiantou-you",class:{disabled:t.currentPage===t.pages},on:{click:function(e){return t.goNext()}}},[e("p",[t._v("下一页")])])])}),[],!1,null,null,null).exports),Ut={computed:{blogger(){return this.$themeConfig.blogger},social(){return this.$themeConfig.social}}},Ht=(n(330),Object(o.a)(Ut,(function(){var t=this,e=t._self._c;return e("aside",{staticClass:"blogger-wrapper card-box"},[e("div",{staticClass:"avatar"},[e("img",{attrs:{src:t.blogger.avatar,alt:"头像",title:"我好看吗"}})]),t._v(" "),t.social&&t.social.icons&&t.social.icons.length?e("div",{staticClass:"icons"},t._l(t.social.icons,(function(n,r){return e("a",{key:r,class:["iconfont",n.iconClass],style:{width:100/t.social.icons.length+"%"},attrs:{href:n.link,title:n.title,target:"_blank"}})})),0):t._e(),t._v(" "),e("div",{staticClass:"blogger"},[e("span",{staticClass:"name"},[t._v(t._s(t.blogger.name))]),t._v(" "),e("span",{staticClass:"slogan"},[t._v(t._s(t.blogger.slogan))])])])}),[],!1,null,null,null).exports),Ft={props:{category:{type:String,default:""},categoriesData:{type:Array,default:[]},length:{type:[String,Number],default:"all"}},computed:{categories(){return"all"===this.length?this.categoriesData:this.categoriesData.slice(0,this.length)}}},Wt=(n(331),Object(o.a)(Ft,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"categories-wrapper card-box"},[e("router-link",{staticClass:"title iconfont icon-wenjianjia",attrs:{to:"/categories/",title:"全部分类"}},[t._v(t._s("all"===t.length?"全部分类":"文章分类"))]),t._v(" "),e("div",{staticClass:"categories"},[t._l(t.categories,(function(n,r){return e("router-link",{key:r,class:{active:n.key===t.category},attrs:{to:"/categories/?category="+encodeURIComponent(n.key)}},[t._v("\n "+t._s(n.key)+"\n "),e("span",[t._v(t._s(n.length))])])})),t._v(" "),"all"!==t.length&&t.length({tagBgColor:["#11a8cd","#F8B26A","#67CC86","#E15B64","#F47E60","#849B87"],tagStyleList:[]}),created(){for(let t=0,e=this.tags.length;tt.length?e("router-link",{attrs:{to:"/tags/"}},[t._v("更多...")]):t._e()],2)],1)}),[],!1,null,null,null).exports);_t.use(Dt);var Kt={data:()=>({isMQMobile:!1,slide:null,currentPageIndex:0,playTimer:0,mark:0,total:0,perPage:10,currentPage:1}),computed:{homeData(){return{...this.$page.frontmatter}},hasFeatures(){return!(!this.homeData.features||!this.homeData.features.length)},homeSidebarB(){const{htmlModules:t}=this.$themeConfig;return t?t.homeSidebarB:""},showBanner(){return!(this.$route.query.p&&1!=this.$route.query.p&&(!this.homeData.postList||"detailed"===this.homeData.postList))},bannerBgStyle(){let t=this.homeData.bannerBg;return t&&"auto"!==t?"none"===t?this.$themeConfig.bodyBgImg?"":"background: var(--mainBg);color: var(--textColor)":t.indexOf("background:")>-1?t:t.indexOf(".")>-1?`background: url(${this.$withBase(t)}) center center / cover no-repeat`:void 0:this.$themeConfig.bodyBgImg?"":"background: rgb(40,40,45) url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAYAAAAe2bNZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABOSURBVFhH7c6xCQAgDAVRR9A6E4hLu4uLiWJ7tSnuQcIvr2TRYsw3/zOGGEOMIcYQY4gxxBhiDDGGGEOMIcYQY4gxxBhiDLkx52W4Gn1tuslCtHJvL54AAAAASUVORK5CYII=)"},actionLink(){return{link:this.homeData.actionLink,text:this.homeData.actionText}}},components:{NavLink:s,MainLayout:$t,PostList:Yt,UpdateArticle:Nt,BloggerBar:Ht,CategoriesBar:Wt,TagsBar:Gt,Pagination:zt},created(){this.total=this.$sortPosts.length},beforeMount(){this.isMQMobile=window.innerWidth<720},mounted(){this.$route.query.p&&(this.currentPage=Number(this.$route.query.p)),!this.hasFeatures||!this.isMQMobile||this.$route.query.p&&1!=this.$route.query.p||this.init(),this.hasFeatures&&window.addEventListener("resize",()=>{this.isMQMobile=window.innerWidth<720,!this.isMQMobile||this.slide||this.mark||(this.mark++,setTimeout(()=>{this.init()},60))})},beforeDestroy(){clearTimeout(this.playTimer),this.slide&&this.slide.destroy()},watch:{"$route.query.p"(){this.$route.query.p?this.currentPage=Number(this.$route.query.p):this.currentPage=1,this.hasFeatures&&1===this.currentPage&&this.isMQMobile&&setTimeout(()=>{this.slide&&this.slide.destroy(),this.init()},0)}},methods:{init(){clearTimeout(this.playTimer),this.slide=new _t(this.$refs.slide,{scrollX:!0,scrollY:!1,slide:{loop:!0,threshold:100},useTransition:!0,momentum:!1,bounce:!1,stopPropagation:!1,probeType:2,preventDefault:!1}),this.slide.on("beforeScrollStart",()=>{clearTimeout(this.playTimer)}),this.slide.on("scrollEnd",()=>{this.autoGoNext()}),this.slide.on("slideWillChange",t=>{this.currentPageIndex=t.pageX}),this.autoGoNext()},autoGoNext(){clearTimeout(this.playTimer),this.playTimer=setTimeout(()=>{this.slide.next()},4e3)},handlePagination(t){this.currentPage=t},getScrollTop:()=>window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop}},Qt=(n(333),Object(o.a)(Kt,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"home-wrapper"},[e("div",{staticClass:"banner",class:{"hide-banner":!t.showBanner},style:t.bannerBgStyle},[e("div",{staticClass:"banner-conent",style:!t.homeData.features&&!t.homeData.heroImage&&"padding-top: 7rem"},[e("header",{staticClass:"hero"},[t.homeData.heroImage?e("img",{attrs:{src:t.$withBase(t.homeData.heroImage),alt:t.homeData.heroAlt}}):t._e(),t._v(" "),t.homeData.heroText?e("h1",{attrs:{id:"main-title"}},[t._v("\n "+t._s(t.homeData.heroText)+"\n ")]):t._e(),t._v(" "),t.homeData.tagline?e("p",{staticClass:"description"},[t._v("\n "+t._s(t.homeData.tagline)+"\n ")]):t._e(),t._v(" "),t.homeData.actionText&&t.homeData.actionLink?e("p",{staticClass:"action"},[e("NavLink",{staticClass:"action-button",attrs:{item:t.actionLink}})],1):t._e()]),t._v(" "),t.hasFeatures&&!t.isMQMobile?e("div",{staticClass:"features"},t._l(t.homeData.features,(function(n,r){return e("div",{key:r,staticClass:"feature"},[n.link?e("router-link",{attrs:{to:n.link}},[n.imgUrl?e("img",{staticClass:"feature-img",attrs:{src:t.$withBase(n.imgUrl),alt:n.title}}):t._e(),t._v(" "),e("h2",[t._v(t._s(n.title))]),t._v(" "),e("p",[t._v(t._s(n.details))])]):e("a",{attrs:{href:"javascript:;"}},[n.imgUrl?e("img",{staticClass:"feature-img",attrs:{src:t.$withBase(n.imgUrl),alt:n.title}}):t._e(),t._v(" "),e("h2",[t._v(t._s(n.title))]),t._v(" "),e("p",[t._v(t._s(n.details))])])],1)})),0):t._e()]),t._v(" "),t.hasFeatures?e("div",{directives:[{name:"show",rawName:"v-show",value:t.isMQMobile,expression:"isMQMobile"}],staticClass:"slide-banner"},[e("div",{staticClass:"banner-wrapper"},[e("div",{ref:"slide",staticClass:"slide-banner-scroll"},[e("div",{staticClass:"slide-banner-wrapper"},t._l(t.homeData.features,(function(n,r){return e("div",{key:r,staticClass:"slide-item"},[n.link?e("router-link",{attrs:{to:n.link}},[n.imgUrl?e("img",{staticClass:"feature-img",attrs:{src:t.$withBase(n.imgUrl),alt:n.title}}):t._e(),t._v(" "),e("h2",[t._v(t._s(n.title))]),t._v(" "),e("p",[t._v(t._s(n.details))])]):e("a",{attrs:{href:"javascript:;"}},[n.imgUrl?e("img",{staticClass:"feature-img",attrs:{src:t.$withBase(n.imgUrl),alt:n.title}}):t._e(),t._v(" "),e("h2",[t._v(t._s(n.title))]),t._v(" "),e("p",[t._v(t._s(n.details))])])],1)})),0)]),t._v(" "),e("div",{staticClass:"docs-wrapper"},t._l(t.homeData.features.length,(function(n,r){return e("span",{key:r,staticClass:"doc",class:{active:t.currentPageIndex===r}})})),0)])]):t._e()]),t._v(" "),e("MainLayout",{scopedSlots:t._u([{key:"mainLeft",fn:function(){return["simple"===t.homeData.postList?e("UpdateArticle",{staticClass:"card-box",attrs:{length:t.homeData.simplePostListLength||10,moreArticle:t.$themeConfig.updateBar&&t.$themeConfig.updateBar.moreArticle}}):t.homeData.postList&&"detailed"!==t.homeData.postList?t._e():[e("PostList",{attrs:{currentPage:t.currentPage,perPage:t.perPage}}),t._v(" "),e("Pagination",{directives:[{name:"show",rawName:"v-show",value:Math.ceil(t.total/t.perPage)>1,expression:"Math.ceil(total / perPage) > 1"}],attrs:{total:t.total,perPage:t.perPage,currentPage:t.currentPage},on:{getCurrentPage:t.handlePagination}})],t._v(" "),e("Content",{staticClass:"theme-vdoing-content custom card-box"})]},proxy:!0},t.homeData.hideRightBar?null:{key:"mainRight",fn:function(){return[t.$themeConfig.blogger?e("BloggerBar"):t._e(),t._v(" "),!1!==t.$themeConfig.category&&t.$categoriesAndTags.categories.length?e("CategoriesBar",{attrs:{categoriesData:t.$categoriesAndTags.categories,length:10}}):t._e(),t._v(" "),!1!==t.$themeConfig.tag&&t.$categoriesAndTags.tags.length?e("TagsBar",{attrs:{tagsData:t.$categoriesAndTags.tags,length:30}}):t._e(),t._v(" "),t.homeSidebarB?e("div",{staticClass:"custom-html-box card-box",domProps:{innerHTML:t._s(t.homeSidebarB)}}):t._e()]},proxy:!0}],null,!0)})],1)}),[],!1,null,"7d2bb426",null).exports),Jt=(n(22),n(334),n(335),n(336),n(337),n(340),n(341),n(342)),Zt=n.n(Jt),Vt=n(298),te=n.n(Vt);let ee=null,ne=null,re=null,ie=null;const oe=/[\u3131-\u314e|\u314f-\u3163|\uac00-\ud7a3]|[\u4E00-\u9FCC\u3400-\u4DB5\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\ud840-\ud868][\udc00-\udfff]|\ud869[\udc00-\uded6\udf00-\udfff]|[\ud86a-\ud86c][\udc00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d]|[\u3041-\u3096]|[\u30A1-\u30FA]/giu;var se={buildIndex(t,e){const n=t.filter(t=>!t.frontmatter||!1!==t.frontmatter.search),r={encode:e.encode||"simple",tokenize:e.tokenize||"forward",split:e.split||/\W+/,async:!0,doc:{id:"key",field:["title","headersStr","content"]}};ee=new Zt.a(r),ee.add(n);const i=n.filter(t=>t.charsets.cyrillic),o=n.filter(t=>t.charsets.cjk);i.length&&(ne=new Zt.a({...r,encode:"icase",split:/\s+/,tokenize:"forward"}),ne.add(i)),o.length&&(re=new Zt.a({...r,encode:!1,tokenize:function(t){const e=[];let n=null;do{n=oe.exec(t),n&&e.push(n[0])}while(n);return e}}),re.add(o)),ie=te.a.keyBy(n,"path")},async match(t,e,n=7){const r=[{field:"title",query:t,limit:n,boost:10},{field:"headersStr",query:t,limit:n,boost:7},{field:"content",query:t,limit:n}],i=await ee.search(r),o=ne?await ne.search(r):[],s=re?await re.search(r):[],a=te.a.uniqBy([...i,...o,...s],"path").map(n=>({...n,parentPageTitle:ae(n),...ue(n,pe(t),e)})),u=te.a.groupBy(a,"parentPageTitle");return te.a.values(u).map(t=>t.map((t,e)=>0===e?t:{...t,parentPageTitle:null})).flat()},normalizeString:pe};function ae(t){const e=t.path.split("/");let n="/";e[1]&&(n=`/${e[1]}/`);return(ie[n]||t).title}function ue(t,e,n){const r=function(t,e,n){const r=n.map(e=>ce(t,e)||he(t,e)).filter(t=>t);if(0===r.length)return null;if(r.every(t=>null!=t.headerIndex))return ce(t,e)||r[0];return he(t,e)||r.find(t=>null==t.headerIndex)}(t,e.toLowerCase(),n);if(!r)return{...le(t),slug:"",contentStr:null};if(null!=r.headerIndex)return{...le(t,r.headerIndex,r),slug:"#"+t.headers[r.headerIndex].slug,contentStr:null};let i=te.a.findLastIndex(t.headers||[],t=>null!=t.charIndex&&t.charIndext.level===n.level-1,e-1))&&(e=null)}const i=r.map(t=>t.title).join(" > "),o=r.slice(0,-1),s=te.a.sum(o.map(t=>(t.title||"").length))+3*o.length;return{headingStr:i,headingHighlight:n&&null!=n.headerIndex&&[n.charIndex+s,n.termLength]}}function ce(t,e){if(!t.headers)return null;for(let n=0;n=s.length)return{contentStr:s,contentHighlight:u};const l=te.a.round((120-r)/2),c=Math.max(a-l,0),h=Math.min(c+120,s.length);let f=s.slice(c,h);return u[0]=u[0]-c,c>0&&(f="..."+f,u[0]=u[0]+3),h({query:"",focused:!1,focusIndex:0,placeholder:void 0,suggestions:null}),computed:{queryTerms(){if(!this.query)return[];return se.normalizeString(this.query).split(/[^\p{L}\p{N}_]+/iu).filter(t=>t)},showSuggestions(){return this.focused&&this.suggestions&&this.suggestions.length},alignRight(){return(this.$site.themeConfig.nav||[]).length+(this.$site.repo?1:0)<=2}},watch:{query(){this.getSuggestions()}},mounted(){se.buildIndex(this.$site.pages,{}||{}),this.placeholder=this.$site.themeConfig.searchPlaceholder||"",document.addEventListener("keydown",this.onHotkey);const t=this.urlParams();if(t){const e=t.get("query");e&&(this.query=decodeURI(e),this.focused=!0)}},beforeDestroy(){document.removeEventListener("keydown",this.onHotkey)},methods:{async getSuggestions(){if(!this.query||!this.queryTerms.length)return void(this.suggestions=[]);let t=await se.match(this.query,this.queryTerms,this.$site.themeConfig.searchMaxSuggestions||5);ge.processSuggestions&&(t=await ge.processSuggestions(t,this.query,this.queryTerms)),this.suggestions=t.map(t=>({...t,headingDisplay:de(t.headingStr,t.headingHighlight),contentDisplay:de(t.contentStr,t.contentHighlight)}))},getPageLocalePath(t){for(const e in this.$site.locales||{})if("/"!==e&&0===t.path.indexOf(e))return e;return"/"},isSearchable(t){let e=null;return null===e||(e=Array.isArray(e)?e:new Array(e),e.filter(e=>t.path.match(e)).length>0)},onHotkey(t){t.srcElement===document.body&&["s","/"].includes(t.key)&&(this.$refs.input.focus(),t.preventDefault())},onUp(){this.showSuggestions&&(this.focusIndex>0?this.focusIndex--:this.focusIndex=this.suggestions.length-1)},onDown(){this.showSuggestions&&(this.focusIndexwindow.location.search?new URLSearchParams(window.location.search):null}},me=(n(343),Object(o.a)(ve,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"search-box"},[e("input",{ref:"input",class:{focused:t.focused},attrs:{"aria-label":"Search",placeholder:t.placeholder,autocomplete:"off",spellcheck:"false"},domProps:{value:t.query},on:{input:function(e){t.query=e.target.value},focus:function(e){t.focused=!0},blur:function(e){t.focused=!1},keyup:[function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.go(t.focusIndex)},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"up",38,e.key,["Up","ArrowUp"])?null:t.onUp.apply(null,arguments)},function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"down",40,e.key,["Down","ArrowDown"])?null:t.onDown.apply(null,arguments)}]}}),t._v(" "),t.showSuggestions?e("ul",{staticClass:"suggestions",class:{"align-right":t.alignRight},on:{mouseleave:t.unfocus}},t._l(t.suggestions,(function(n,r){return e("li",{key:r,staticClass:"suggestion",class:{focused:r===t.focusIndex},on:{mousedown:function(e){return t.go(r)},mouseenter:function(e){return t.focus(r)}}},[e("a",{attrs:{href:n.path+n.slug},on:{click:function(t){t.preventDefault()}}},[n.parentPageTitle?e("div",{staticClass:"parent-page-title",domProps:{innerHTML:t._s(n.parentPageTitle)}}):t._e(),t._v(" "),e("div",{staticClass:"suggestion-row"},[e("div",{staticClass:"page-title"},[t._v(t._s(n.title||n.path))]),t._v(" "),e("div",{staticClass:"suggestion-content"},[n.headingStr?e("div",{staticClass:"header"},[t._v("\n "+t._s(n.headingDisplay.prefix)),e("span",{staticClass:"highlight"},[t._v(t._s(n.headingDisplay.highlightedContent))]),t._v(t._s(n.headingDisplay.suffix)+"\n ")]):t._e(),t._v(" "),n.contentStr?e("div",[t._v("\n "+t._s(n.contentDisplay.prefix)),e("span",{staticClass:"highlight"},[t._v(t._s(n.contentDisplay.highlightedContent))]),t._v(t._s(n.contentDisplay.suffix)+"\n ")]):t._e()])])])])})),0):t._e()])}),[],!1,null,null,null).exports),ye=(n(344),Object(o.a)({},(function(){var t=this,e=t._self._c;return e("div",{staticClass:"sidebar-button",attrs:{title:"目录"},on:{click:function(e){return t.$emit("toggle-sidebar")}}},[e("svg",{staticClass:"icon",attrs:{xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",role:"img",viewBox:"0 0 448 512"}},[e("path",{attrs:{fill:"currentColor",d:"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"}})])])}),[],!1,null,null,null).exports),_e=n(324),be=n(133),we=n.n(be),ke={components:{NavLink:s,DropdownTransition:_e.a},data:()=>({open:!1,isMQMobile:!1}),props:{item:{required:!0}},computed:{dropdownAriaLabel(){return this.item.ariaLabel||this.item.text}},beforeMount(){this.isMQMobile=window.innerWidth<720,window.addEventListener("resize",()=>{this.isMQMobile=window.innerWidth<720})},methods:{toggle(){this.isMQMobile&&(this.open=!this.open)},isLastItemOfArray:(t,e)=>we()(e)===t},watch:{$route(){this.open=!1}}},xe=(n(346),{components:{NavLink:s,DropdownLink:Object(o.a)(ke,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"dropdown-wrapper",class:{open:t.open}},[e("button",{staticClass:"dropdown-title",attrs:{type:"button","aria-label":t.dropdownAriaLabel},on:{click:t.toggle}},[t.item.link?e("router-link",{staticClass:"link-title",attrs:{to:t.item.link}},[t._v(t._s(t.item.text))]):t._e(),t._v(" "),e("span",{directives:[{name:"show",rawName:"v-show",value:!t.item.link,expression:"!item.link"}],staticClass:"title"},[t._v(t._s(t.item.text))]),t._v(" "),e("span",{staticClass:"arrow",class:t.open?"down":"right"})],1),t._v(" "),e("DropdownTransition",[e("ul",{directives:[{name:"show",rawName:"v-show",value:t.open,expression:"open"}],staticClass:"nav-dropdown"},t._l(t.item.items,(function(n,r){return e("li",{key:n.link||r,staticClass:"dropdown-item"},["links"===n.type?e("h4",[t._v(t._s(n.text))]):t._e(),t._v(" "),"links"===n.type?e("ul",{staticClass:"dropdown-subitem-wrapper"},t._l(n.items,(function(r){return e("li",{key:r.link,staticClass:"dropdown-subitem"},[e("NavLink",{attrs:{item:r},on:{focusout:function(e){t.isLastItemOfArray(r,n.items)&&t.isLastItemOfArray(n,t.item.items)&&t.toggle()}}})],1)})),0):e("NavLink",{attrs:{item:n},on:{focusout:function(e){t.isLastItemOfArray(n,t.item.items)&&t.toggle()}}})],1)})),0)])],1)}),[],!1,null,null,null).exports},computed:{userNav(){return this.$themeLocaleConfig.nav||this.$site.themeConfig.nav||[]},nav(){const{locales:t}=this.$site;if(t&&Object.keys(t).length>1){const e=this.$page.path,n=this.$router.options.routes,r=this.$site.themeConfig.locales||{},i={text:this.$themeLocaleConfig.selectText||"Languages",ariaLabel:this.$themeLocaleConfig.ariaLabel||"Select language",items:Object.keys(t).map(i=>{const o=t[i],s=r[i]&&r[i].label||o.lang;let a;return o.lang===this.$lang?a=e:(a=e.replace(this.$localeConfig.path,i),n.some(t=>t.path===a)||(a=i)),{text:s,link:a}})};return[...this.userNav,i]}return this.userNav},userLinks(){return(this.nav||[]).map(t=>Object.assign(Object(r.k)(t),{items:(t.items||[]).map(r.k)}))},repoLink(){const{repo:t}=this.$site.themeConfig;return t?/^https?:/.test(t)?t:"https://github.com/"+t:null},repoLabel(){if(!this.repoLink)return;if(this.$site.themeConfig.repoLabel)return this.$site.themeConfig.repoLabel;const t=this.repoLink.match(/^https?:\/\/[^/]+/)[0],e=["GitHub","GitLab","Bitbucket"];for(let n=0;n({linksWrapMaxWidth:null}),mounted(){const t=parseInt(Ce(this.$el,"paddingLeft"))+parseInt(Ce(this.$el,"paddingRight")),e=()=>{document.documentElement.clientWidth<719?this.linksWrapMaxWidth=null:this.linksWrapMaxWidth=this.$el.offsetWidth-t-(this.$refs.siteName&&this.$refs.siteName.offsetWidth||0)};e(),window.addEventListener("resize",e,!1)},computed:{algolia(){return this.$themeLocaleConfig.algolia||this.$site.themeConfig.algolia||{}},isAlgoliaSearch(){return this.algolia&&this.algolia.apiKey&&this.algolia.indexName}}},Se=(n(348),Object(o.a)(Te,(function(){var t=this,e=t._self._c;return e("header",{staticClass:"navbar blur"},[e("SidebarButton",{on:{"toggle-sidebar":function(e){return t.$emit("toggle-sidebar")}}}),t._v(" "),e("router-link",{staticClass:"home-link",attrs:{to:t.$localePath}},[t.$site.themeConfig.logo?e("img",{staticClass:"logo",attrs:{src:t.$withBase(t.$site.themeConfig.logo),alt:t.$siteTitle}}):t._e(),t._v(" "),t.$siteTitle?e("span",{ref:"siteName",staticClass:"site-name",class:{"can-hide":t.$site.themeConfig.logo}},[t._v(t._s(t.$siteTitle))]):t._e()]),t._v(" "),e("div",{staticClass:"links",style:t.linksWrapMaxWidth?{"max-width":t.linksWrapMaxWidth+"px"}:{}},[t.isAlgoliaSearch?e("AlgoliaSearchBox",{attrs:{options:t.algolia}}):!1!==t.$site.themeConfig.search&&!1!==t.$page.frontmatter.search?e("SearchBox"):t._e(),t._v(" "),e("NavLinks",{staticClass:"can-hide"})],1)],1)}),[],!1,null,null,null).exports),Le=n(305),Ae=n.n(Le),Be={name:"PageEdit",computed:{tags(){return this.$frontmatter.tags},lastUpdated(){return this.$page.lastUpdated},lastUpdatedText(){return"string"==typeof this.$themeLocaleConfig.lastUpdated?this.$themeLocaleConfig.lastUpdated:"string"==typeof this.$site.themeConfig.lastUpdated?this.$site.themeConfig.lastUpdated:"Last Updated"},editLink(){const t=Ae()(this.$page.frontmatter.editLink)?this.$site.themeConfig.editLinks:this.$page.frontmatter.editLink,{repo:e,docsDir:n="",docsBranch:r="master",docsRepo:i=e}=this.$site.themeConfig;return t&&i&&this.$page.relativePath?this.createEditLink(e,i,n,r,this.$page.relativePath):null},editLinkText(){return this.$themeLocaleConfig.editLinkText||this.$site.themeConfig.editLinkText||"Edit this page"}},methods:{createEditLink(t,e,n,i,o){if(/bitbucket.org/.test(e)){return e.replace(r.b,"")+"/src"+`/${i}/`+(n?n.replace(r.b,"")+"/":"")+o+`?mode=edit&spa=0&at=${i}&fileviewer=file-view-default`}if(/gitlab.com/.test(e)){return e.replace(r.b,"")+"/-/edit"+`/${i}/`+(n?n.replace(r.b,"")+"/":"")+o}const s=/gitee.com/;if(s.test(e)){return e.replace(s,"gitee.com/-/ide/project")+"/edit"+`/${i}/-/`+(n?n.replace(r.b,"")+"/":"")+o}return(r.j.test(e)?e:"https://github.com/"+e).replace(r.b,"")+"/edit"+`/${i}/`+(n?n.replace(r.b,"")+"/":"")+o}}},Me=(n(349),Object(o.a)(Be,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"page-edit"},[t.editLink?e("div",{staticClass:"edit-link"},[e("a",{attrs:{href:t.editLink,target:"_blank",rel:"noopener noreferrer"}},[t._v(t._s(t.editLinkText))]),t._v(" "),e("OutboundLink")],1):t._e(),t._v(" "),!1!==t.$themeConfig.tag&&t.tags&&t.tags[0]?e("div",{staticClass:"tags"},t._l(t.tags,(function(n,r){return e("router-link",{key:r,attrs:{to:"/tags/?tag="+encodeURIComponent(n),title:"标签"}},[t._v("#"+t._s(n))])})),1):t._e(),t._v(" "),t.lastUpdated?e("div",{staticClass:"last-updated"},[e("span",{staticClass:"prefix"},[t._v(t._s(t.lastUpdatedText)+":")]),t._v(" "),e("span",{staticClass:"time"},[t._v(t._s(t.lastUpdated))])]):t._e()])}),[],!1,null,null,null).exports),Oe=n(350),Ee=n.n(Oe),Ie={name:"PageNav",props:["sidebarItems"],computed:{prev(){return $e(De.PREV,this)},next(){return $e(De.NEXT,this)}},methods:{showTooltip(t){const e=document.body.clientWidth,n=t.clientX,r=t.target.querySelector(".tooltip");if(!r)return;const i=r.style;nt,getPageLinkConfig:({frontmatter:t})=>t.next},PREV:{resolveLink:function(t,e){return je(t,e,-1)},getThemeLinkConfig:({prevLinks:t})=>t,getPageLinkConfig:({frontmatter:t})=>t.prev}};function $e(t,{$themeConfig:e,$page:n,$route:i,$site:o,sidebarItems:s}){const{resolveLink:a,getThemeLinkConfig:u,getPageLinkConfig:l}=t,c=u(e),h=l(n),f=Ae()(h)?c:h;return!1===f?void 0:Ee()(f)?Object(r.l)(o.pages,f,i.path):a(n,s)}function je(t,e,n){const r=[];!function t(e,n){for(let r=0,i=e.length;r({date:"",classify1:"",classifyList:[],cataloguePermalink:"",author:null,categories:[]}),created(){this.getPageInfo()},watch:{"$route.path"(){this.classifyList=[],this.getPageInfo()}},methods:{getPageInfo(){const t=this.$page,{relativePath:e}=t,{sidebar:n}=this.$themeConfig,r=e.split("/");r.forEach((t,e)=>{const n=t.split(".");if(e!==r.length-1)if(1===n)this.classifyList.push(n[0]);else{const e=t.indexOf(".");this.classifyList.push(t.substring(e+1)||"")}}),this.classify1=this.classifyList[0];const i=n&&n.catalogue?n.catalogue[this.classify1]:"",o=this.$frontmatter.author||this.$themeConfig.author;let s=(t.frontmatter.date||"").split(" ")[0];const{categories:a}=this.$frontmatter;this.date=s,this.cataloguePermalink=i,this.author=o,this.categories=a},getLink(t){const{cataloguePermalink:e}=this;return t===e?e:`${e}${"/"===e.charAt(e.length-1)?"":"/"}#${t}`}}}),Re=(n(352),Object(o.a)(Ne,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"articleInfo-wrap"},[e("div",{staticClass:"articleInfo"},[t.classify1&&"_posts"!==t.classify1?e("ul",{staticClass:"breadcrumbs"},[e("li",[e("router-link",{staticClass:"iconfont icon-home",attrs:{to:"/",title:"首页"}})],1),t._v(" "),t._l(t.classifyList,(function(n){return e("li",{key:n},[t.cataloguePermalink?e("router-link",{attrs:{to:t.getLink(n)}},[t._v(t._s(n))]):!1!==t.$themeConfig.category?e("router-link",{attrs:{to:"/categories/?category="+encodeURIComponent(n),title:"分类"}},[t._v(t._s(n))]):e("span",[t._v(t._s(n))])],1)}))],2):t._e(),t._v(" "),e("div",{staticClass:"info"},[t.author?e("div",{staticClass:"author iconfont icon-touxiang",attrs:{title:"作者"}},[t.author.href||t.author.link&&"string"==typeof t.author.link?e("a",{staticClass:"beLink",attrs:{href:t.author.href||t.author.link,target:"_blank",title:"作者"}},[t._v(t._s(t.author.name))]):e("a",{attrs:{href:"javascript:;"}},[t._v(t._s(t.author.name||t.author))])]):t._e(),t._v(" "),t.date?e("div",{staticClass:"date iconfont icon-riqi",attrs:{title:"创建时间"}},[e("a",{attrs:{href:"javascript:;"}},[t._v(t._s(t.date))])]):t._e(),t._v(" "),!1===t.$themeConfig.category||t.classify1&&"_posts"!==t.classify1||!t.categories?t._e():e("div",{staticClass:"date iconfont icon-wenjian",attrs:{title:"分类"}},t._l(t.categories,(function(n,r){return e("router-link",{key:r,attrs:{to:"/categories/?category="+encodeURIComponent(n)}},[t._v(t._s(n+" "))])})),1)])])])}),[],!1,null,"06225672",null).exports),ze={data:()=>({pageData:null,isStructuring:!0,appointDir:{}}),created(){this.getPageData();const t=this.$themeConfig.sidebar;t&&"auto"!==t||(this.isStructuring=!1,console.error("目录页数据依赖于结构化的侧边栏数据,请在主题设置中将侧边栏字段设置为'structuring',否则无法获取目录数据。"))},methods:{getPageData(){const t=this.$frontmatter.pageComponent;t&&t.data?this.pageData={...t.data,title:this.$frontmatter.title}:console.error("请在front matter中设置pageComponent和pageComponent.data数据")},getCatalogueList(){const{sidebar:t}=this.$site.themeConfig,{data:e}=this.$frontmatter.pageComponent;let n=(e.path||e.key).split("/"),r=t[`/${n[0]}/`];return n.length>1&&(n.shift(),r=this.appointDirDeal(0,n,r)),r||console.error("未获取到目录数据,请查看front matter中设置的path是否正确。"),r},type:t=>Object.prototype.toString.call(t).match(/\[object (.*?)\]/)[1].toLowerCase(),appointDirDeal(t,e,n){let r=e[t];void 0!==r&&-1!==r.indexOf(".")&&(r=r.substring(r.indexOf(".")+1));for(let i=0;i({headers:[],hashText:""}),mounted(){this.getHeadersData(),this.getHashText()},watch:{$route(){this.headers=this.$page.headers,this.getHashText()}},methods:{getHeadersData(){this.headers=this.$page.headers},getHashText(){this.hashText=decodeURIComponent(window.location.hash.slice(1))}}},Fe=(n(354),{data:()=>({badges:["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAABGpJREFUSA3tVVtoXFUU3fvOI53UlmCaKIFmwEhsE7QK0ipFEdHEKpXaZGrp15SINsXUWvBDpBgQRKi0+KKoFeJHfZA+ED9KKoIU2gYD9UejTW4rVIzm0VSTziPzuNu1z507dibTTjL4U/DAzLn3nL3X2o91ziX6f9wMFdh6Jvbm9nNSV0msViVO6tN1Rm7NMu2OpeJ9lWBUTDxrJbYTS0hInuwciu9eLHlFxCLCZEk3MegsJmZ5K/JD6t7FkFdEvGUo1g7qJoG3MHImqRIn8/nzY1K9UPKKiJmtnUqHVE3Gbuay6vJE/N2FEmuxFjW2nUuE0yQXRRxLiTUAzs36zhZvOXJPdX850EVnnLZkB8prodQoM5JGj7Xk2mvC7JB8tG04Ef5PiXtG0UtxupRQSfTnBoCy554x18yJHI6I+G5Eru4LHmPJZEQsrvPUbMiA8G/WgMK7w7I+ez7++o2ANfbrjvaOl1tFMs+htG3IrZH9/hDX1Pr8Tc0UvH8tcX29KzAgIGcEkINyW5BF9x891hw6VYqgJHEk0huccS7vh3C6gTiODL+26huuBtbct8eZnqLML8PkxGYpuPZBqtqwkSjgc4mB5gbgig5i+y0UDK35LMxXisn9xQtK+nd26gTIHsHe/oblK/b29fUmN/8Y+9jAQrnBp56m1LcDlDp9irKTExSKduXJVWSqdBMA08pEJnEIOB3FPPMybu/oeV8zFeYN3xx576Q6RH+VmplE4ncQV5v+5rzSoyOU7PuEAg8g803PwBJ0CExno/jcMbN8tONYeOmHiuUNryvm3fRUy4tMPVLdAGkUhNWuggGrJcXPv+ouCjz0MKUHz1J2/E8IC9nqTabcxgaBYM0hPhD5Y65FsbxRQKxCQrDjDctW7PUM3HuZunFyifSAqEfuzCp48Il24luWUWZoyJCaPR82jE0+kFA643wRFVni4RYSq3ohJO2pZ7B5dO4xkDWbEpossJPLSrPjYID8rS2UHTlvyNxqIGsg674XJJ7vnh5L7PNwC4hh2sjCI96mzszOTpxLF0T7l88Yz7lAuK6OnL8gXLOnTvpzSb22YG8W7us3jSebFHeeqnXRG1vt+MoUM84LQIBmMsCTAcOauTh0T0l0neQK7m2bLMt2mGxU3HYssS0J2cdv5wljlPsrIuZLAG/2DOZIXgCYT8uMGZN+e2kSirfxZOPCsC0f24nTZzspnVn9VePS1Z5vubmAGGXG8ZFno9Hel0yfA5ZPhF7Dh972BQJ2qCpgH67lmWtBYbvk6sz02wjky2vXyz0XErP/kFB619js1BtwfOV4OPRqOQBjy3Qbk18vigUPPSD5ceHnwck7W9bhAqZdd7SuG7w4/P2F/GaJh8c7e9qgow+Q7cGBo+98WsLkuktFqiZabtXuQTu/Y5ETbR0v7tNSFnvrmu6pjdoan2KjMu8q/Hmj1EfCO2ZGfEIbIXKUlw8qaX9/b2oeSJmFksSeT/Fn0V3nSypChh4Gjh74ybO9aeZ/AN2dwciu2/MhAAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAABH1JREFUSA3tVl1oHFUUPmdmd2ltklqbpJDiNnXFmgbFktho7YMPNiJSSZM0+CAYSkUELVhM6YuwIPpgoOKDqOBDC0XE2CQoNtQXBUFTTcCi+Wlh1V2TQExsUzcltd3M9Tt3ZjZzZ2fT+OJTL8yeM+eee757fmeJbq//KQL8X3DUSFOcfr7cRsRtxNQMWueeVzOkaITIGqQHNg5y8+jNW9ldM7A6nTpAjuolUikAwq7CE3WcM2RRDz+XGVgN3FptU/aUSlvq9Pa3iZ1+sgAqJyyAFqkipd9dqiwHF3P65YycLWc/6sqGrvoEoIp6DOFaX5h6+dnfjkWprwqsPk0dUGq5vySwDImC10KxFHgGL1SWoc92O3eVht09qdXNH11I2SsTsJYqMWzihqGMi+A+Garf3BAuuLI5oGlULyNfyB/HYNujwktOfRrMr5t77NmevqaUopx0grnKAyvVpmwUDB4x6FPXuGvYLTDwWsejwgtgkYKPqRJg8SV6xaiZ3ZTppGneS4yfH5/66fZSDHv+QZci/+h5c5UHtpy67JUqGppM0sh0Nc1dW6/N1W5Yoqat8/TU/VnadmdeW2PLLSyh0cvxBs3KbqTmwYPpxN4do/mzE8nEpvX/UMu2Wbp74zUAK5q6WkHns7V0eWkdPbPzd3rxkTGybadYySumVzhcaJFbs5UrEkQ/+CK8gF5dnh/6ciIZ73gwQ927L1IitoxKLXYP3SjYdOrHHfTZhRRlFyrorafPk20B3HPD1y2G3qKZME5Jcf3t/HUC13/8tSd++vqFveMUTwAUxSUFI1QekR1+bIze3D9MF2aq6cPvG72CgnldWCFqyRw3lwH8ZMerjTD9ElRO7Gv44wNpC90aASqGfVlz/Rx17srQ57/UU26hkhQqUB7dBR71WmzQhHUnblGmVOEw0jhbV1n9OlXUDCIRGaNV5Jp43N516fN7JmnTHdfp7Hgy0luO4aMhtkLL8Bi3bUWYvzh5Mn1dTxrL6QmGuRhGL/TiTTxRoEdTszSaq9GR0NGA3KdkOz3hqSV3MIDhQ5IVX/Ivx3umBti2es2h4eZby7x8br1rkf7Mo90AqC8aQ3sJeNzqFRu+vSANAQe3PL7l0HGOAdwDCeZYvNKeoZp1Qfs6Aipndh86HmFRi0LAnEO47wsqM6cdfjh3jBPUzhZy7nvlUfFsamED1VQt6aISHVymXZ/B2aCtIG8AI8xfobj2d3en1wWVhOeHELKmLQ1s211s88comkv4UCwWyF787mJdYXtNfhKAXVqnKTq8QZvGAGGOfaTo5pGZ/PwbUCr5+DPr/1J92JNHr9aOl/F3iI5+O1nfybsGxoimvZ3ViWSluDITw3P37mypheDIPY0tw7+O/5ApbkYw+zpfaUVu32Pi98+defdUhEpZkRFq0aqyNh9FuL9hpYbEm6iwi0z2REd09ZmyENEbuhjDWzKvZXTqKYaBIr3tt5kuPtQBZFvEUwHt60vfCNu41XsksH9Ij1BMMz1Y0OOunHNShFIP5868g5zeXmuLwL9T4b6Q2+KejgAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAABKFJREFUSA3tVl1oFVcQnrMbrak3QUgkya1akpJYcrUtIqW1JvFBE9LiQ5v6JmJpolbMg32rVrhgoYK0QiMY6i9Y6EMaW5D+xFJaTYItIuK2Kr3+BJNwkxBj05sQY3b3nM6cs2dv9t7NT/vQJw/sndk5M/PNzJkzewGerP+pAmy+ON8lLzUJgA8ZYxYIYZmGYRnctDaWvJJAmTtfP1pvXsBCCPP8QFcCaRkZYACgDZFO4stNIcBCajEOlmmC9XpJ9bAGCaPaPmzPl32dvLSVu3BWCTQs0XQQ6g0DYgwLIoAZbBCdW/i+781o1VVlm/410mw4h06Y7bIPHNyWDyL4FHkX03Q8SrzNhZTZriieckWt7cL6MM85YcLpsi/7O9/iXFT6MswI0DmmpkSaJ0qLxFIm3+i1THHB3zmBH3PYx9CcykcLOeQVVa7QtdxTgQgEleX2AjHYfwA+2ddV77ruGoJUbhGDI09YSNXyMpUt5ylOzxgbUmtOp7NmbNt8v3arjTBfYELmLUV+M+nSawNNAUqpT3ClJWg5I3BLT+cGW/DXNGCa6tx1aakCGEigArTn4TDIPdrXXYKCZNrHLMCOEPvHBlLQ99s9eHB7EB6NTki73CVPQ2F5MSx/uRQixfmq7rK0wYD8w8E905bnPDfwoWs/rfv93NWN/ZfvwsLIU7A09gxECyISeGJkHAau98L97tuw7NXnoPyNF8FcYGLGKsOs0mN3OEyec9esGW/ZEl945dTP34wlR2FZVQWU1q0Cw8Tr7p+hgLLNL0FPxx/Q35mA8aEUrH6nCgwEl0tn7wUiZYJnNRh6DK4UH/k0lfyrsBKdPVv/AriGIQcEDQZ65LBAGe2Rzui9Ybjz7XUppz1/uKBbyVPGkN3ZAeC6hr0x7Nr38N5+EqkoOm17xpoqR9ohQF55ERSvr4Dkr3chNfC3DMzGJlNBElW8w9nsGQvhNGIzDkXzCg8cLK951xHsFBlTJspJNi3ZFIMF2AeDV3q8DNOB+YHi6QTrChDIWDBRi5U5f+ZMfJLu3ccrqxtdxk4SKH336LFxSmkqefwU5T8fhdSdQf9IVKD6aNiwI/hnmcAZ91isYMJIaCUCx9W098+LgruikeTqzqqxKPUwqJyCPJiyemVVZBOijDGjD38Os0jOiSPL1z3SPjXNANbiNPXAdzTfukjjuknNBbyz3nwgTd3AVFqUJ5hpHlq9MveLnWwttUfoygBmvVjuikxND3znrhsELnZk7k+OjIGxeNEkomyLVta0xxn+HZhjBc4YZ/AFjHjz9u3xRZl2BN4aq9nFwWh16IrQ1aHHEd3j1+4/dB9OtH4e29A2H1DyHQRmOSfQZ1Fy7MHBTGB6J/Djq6p3OxyO2cB+4Car7v/o3GXgfAkj23+x9ID1Teoamo/SXcbvSf2PX7Vc8DdCmE1vN9di+32P9/5YR3vLnhCVGUWBjEkr3yh4H8v9CzmsbdhzOKzsJKM90iFdaTMjRPhGVsakRvOaRidljo6H6G7j+ctrJpsP+4COhDIl0La2+FS4+5mlocBaXY5QnGZysIBYoeSsl5qQzrSj/cgNrfuEzlWBfwA+EjrZyWUvpAAAAABJRU5ErkJggg=="],currentBadge:""}),created(){this.$themeConfig.titleBadgeIcons&&(this.badges=this.$themeConfig.titleBadgeIcons),this.currentBadge=this.getBadge()},watch:{"$route.path"(){this.currentBadge=this.getBadge()}},methods:{getBadge(){return this.badges[Math.floor(Math.random()*this.badges.length)]}}}),We={mixins:[Fe],data:()=>({updateBarConfig:null}),props:["sidebarItems"],components:{PageEdit:Me,PageNav:Xe,ArticleInfo:Re,Catalogue:Ue,UpdateArticle:Nt,RightMenu:Object(o.a)(He,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"right-menu-wrapper"},[e("div",{staticClass:"right-menu-margin"},[e("div",{staticClass:"right-menu-title"},[t._v("目录")]),t._v(" "),e("div",{staticClass:"right-menu-content"},t._l(t.headers,(function(n,r){return e("div",{key:r,class:["right-menu-item","level"+n.level,{active:n.slug===t.hashText}]},[e("a",{attrs:{href:"#"+n.slug}},[t._v(t._s(n.title))])])})),0)])])}),[],!1,null,null,null).exports},created(){this.updateBarConfig=this.$themeConfig.updateBar},computed:{bgStyle(){const{contentBgStyle:t}=this.$themeConfig;return t?"bg-style-"+t:""},isShowUpdateBar(){return!this.updateBarConfig||!1!==this.updateBarConfig.showToArticle},showTitle(){return!this.$frontmatter.pageComponent},showRightMenu(){const{$frontmatter:t,$themeConfig:e,$page:n}=this,{sidebar:r}=t;return!1!==e.rightMenuBar&&n.headers&&!1!==(t&&r&&!1!==r)},pageComponent(){return!!this.$frontmatter.pageComponent&&this.$frontmatter.pageComponent.name},isShowSlotT(){return this.getShowStatus("pageTshowMode")},isShowSlotB(){return this.getShowStatus("pageBshowMode")}},methods:{getShowStatus(t){const{htmlModules:e}=this.$themeConfig;return!!e&&("article"===e[t]?this.isArticle():"custom"!==e[t]||!this.isArticle())},isArticle(){return!1!==this.$frontmatter.article}}},qe=(n(355),Object(o.a)(We,(function(){var t=this,e=t._self._c;return e("div",[e("main",{staticClass:"page"},[e("div",{class:"theme-vdoing-wrapper "+t.bgStyle},[t.isArticle()?e("ArticleInfo"):e("div",{staticClass:"placeholder"}),t._v(" "),t.pageComponent?e(t.pageComponent,{tag:"component",staticClass:"theme-vdoing-content"}):t._e(),t._v(" "),e("div",{staticClass:"content-wrapper"},[t.showRightMenu?e("RightMenu"):t._e(),t._v(" "),t.showTitle?e("h1",[!1!==t.$themeConfig.titleBadge?e("img",{attrs:{src:t.currentBadge}}):t._e(),t._v(t._s(this.$page.title)),t.$frontmatter.titleTag?e("span",{staticClass:"title-tag"},[t._v(t._s(t.$frontmatter.titleTag))]):t._e()]):t._e(),t._v(" "),t.isShowSlotT?t._t("top"):t._e(),t._v(" "),e("Content",{staticClass:"theme-vdoing-content"})],2),t._v(" "),t.isShowSlotB?t._t("bottom"):t._e(),t._v(" "),e("PageEdit"),t._v(" "),e("PageNav",t._b({},"PageNav",{sidebarItems:t.sidebarItems},!1))],2),t._v(" "),t.isShowUpdateBar?e("UpdateArticle",{attrs:{length:3,moreArticle:t.updateBarConfig&&t.updateBarConfig.moreArticle}}):t._e()],1)])}),[],!1,null,null,null).exports),Ge={data:()=>({category:"",total:0,perPage:10,currentPage:1}),components:{MainLayout:$t,PostList:Yt,Pagination:zt,CategoriesBar:Wt},mounted(){const t=this.$route.query.category;t?(this.category=t,this.total=this.$groupPosts.categories[t].length):this.total=this.$sortPosts.length,this.$route.query.p&&(this.currentPage=Number(this.$route.query.p));const e=document.querySelector(".categories");e&&setTimeout(()=>{const t=e.querySelector(".active"),n=t?t.offsetTop:0;e.scrollTo({top:n,behavior:"smooth"})},300)},methods:{handlePagination(t){this.currentPage=t}},watch:{"$route.query.category"(t){this.category=t?decodeURIComponent(t):"",this.category?this.total=this.$groupPosts.categories[this.category].length:this.total=this.$sortPosts.length,this.currentPage=1}}},Ke=(n(356),Object(o.a)(Ge,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"custom-page categories-page"},[e("MainLayout",{scopedSlots:t._u([{key:"mainLeft",fn:function(){return[t.$categoriesAndTags.categories.length?e("CategoriesBar",{attrs:{categoriesData:t.$categoriesAndTags.categories,category:t.category}}):t._e(),t._v(" "),e("PostList",{attrs:{currentPage:t.currentPage,perPage:t.perPage,category:t.category}}),t._v(" "),e("Pagination",{directives:[{name:"show",rawName:"v-show",value:Math.ceil(t.total/t.perPage)>1,expression:"Math.ceil(total / perPage) > 1"}],attrs:{total:t.total,perPage:t.perPage,currentPage:t.currentPage},on:{getCurrentPage:t.handlePagination}})]},proxy:!0},{key:"mainRight",fn:function(){return[t.$categoriesAndTags.categories.length?e("CategoriesBar",{attrs:{categoriesData:t.$categoriesAndTags.categories,category:t.category}}):t._e()]},proxy:!0}])})],1)}),[],!1,null,null,null).exports),Qe={data:()=>({tag:"",total:0,perPage:10,currentPage:1}),components:{MainLayout:$t,PostList:Yt,Pagination:zt,TagsBar:Gt},mounted(){const t=this.$route.query.tag;t?(this.tag=t,this.total=this.$groupPosts.tags[t].length):this.total=this.$sortPosts.length,this.$route.query.p&&(this.currentPage=Number(this.$route.query.p))},methods:{handlePagination(t){this.currentPage=t}},watch:{"$route.query.tag"(t){this.tag=t?decodeURIComponent(t):"",this.tag?this.total=this.$groupPosts.tags[this.tag].length:this.total=this.$sortPosts.length,this.currentPage=1}}},Je=(n(357),Object(o.a)(Qe,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"custom-page tags-page"},[e("MainLayout",{scopedSlots:t._u([{key:"mainLeft",fn:function(){return[t.$categoriesAndTags.tags.length?e("TagsBar",{attrs:{tagsData:t.$categoriesAndTags.tags,tag:t.tag}}):t._e(),t._v(" "),e("PostList",{attrs:{currentPage:t.currentPage,perPage:t.perPage,tag:t.tag}}),t._v(" "),e("Pagination",{directives:[{name:"show",rawName:"v-show",value:Math.ceil(t.total/t.perPage)>1,expression:"Math.ceil(total / perPage) > 1"}],attrs:{total:t.total,perPage:t.perPage,currentPage:t.currentPage},on:{getCurrentPage:t.handlePagination}})]},proxy:!0},{key:"mainRight",fn:function(){return[t.$categoriesAndTags.tags.length?e("TagsBar",{attrs:{tagsData:t.$categoriesAndTags.tags,tag:t.tag}}):t._e()]},proxy:!0}])})],1)}),[],!1,null,null,null).exports),Ze=n(76),Ve=n.n(Ze),tn={mixins:[Fe],data:()=>({postsList:[],countByYear:{},perPage:80,currentPage:1}),created(){this.getPageData();const{$sortPostsByDate:t,countByYear:e}=this;for(let n=0;n{if(this.postsList.lengthr&&n+r>=i-250&&this.loadmore()}},200))},methods:{getPageData(){const t=this.currentPage,e=this.perPage;this.postsList=this.postsList.concat(this.$sortPostsByDate.slice((t-1)*e,t*e))},loadmore(){this.currentPage=this.currentPage+1,this.getPageData()},getYear(t){const e=this.postsList[t];if(!e)return;const{frontmatter:{date:n}}=e;return n&&"string"===Object(r.n)(n)?n.slice(0,4):void 0},getDate(t){const{frontmatter:{date:e}}=t;if(e&&"string"===Object(r.n)(e))return e.slice(5,10)}}},en=(n(358),Object(o.a)(tn,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"custom-page archives-page"},[e("div",{staticClass:"theme-vdoing-wrapper"},[e("h1",[!1!==t.$themeConfig.titleBadge?e("img",{attrs:{src:t.currentBadge}}):t._e(),t._v("\n "+t._s(t.$page.title)+"\n ")]),t._v(" "),e("div",{staticClass:"count"},[t._v("\n 总共 "),e("i",[t._v(t._s(t.$sortPostsByDate.length))]),t._v(" 篇文章\n ")]),t._v(" "),e("ul",[t._l(t.postsList,(function(n,r){return[(t.year=t.getYear(r))!==t.getYear(r-1)?e("li",{key:r+t.$sortPostsByDate.length,staticClass:"year"},[e("h2",[t._v("\n "+t._s(t.year)+"\n "),e("span",[e("i",[t._v(t._s(t.countByYear[t.year]))]),t._v(" 篇\n ")])])]):t._e(),t._v(" "),e("li",{key:r},[e("router-link",{attrs:{to:n.path}},[e("span",{staticClass:"date"},[t._v(t._s(t.getDate(n)))]),t._v("\n "+t._s(n.title)+"\n "),n.frontmatter.titleTag?e("span",{staticClass:"title-tag"},[t._v("\n "+t._s(n.frontmatter.titleTag)+"\n ")]):t._e()])],1)]}))],2)])])}),[],!1,null,null,null).exports),nn={name:"Sidebar",components:{SidebarLinks:n(323).default,NavLinks:Pe},props:["items"],computed:{blogger(){return this.$themeConfig.blogger}}},rn=(n(361),Object(o.a)(nn,(function(){var t=this,e=t._self._c;return e("aside",{staticClass:"sidebar"},[t.blogger?e("div",{staticClass:"blogger"},[e("img",{attrs:{src:t.blogger.avatar}}),t._v(" "),e("div",{staticClass:"blogger-info"},[e("h3",[t._v(t._s(t.blogger.name))]),t._v(" "),t.blogger.social?e("div",{staticClass:"icons"},t._l(t.blogger.social.icons,(function(t,n){return e("a",{key:n,class:["iconfont",t.iconClass],attrs:{href:t.link,title:t.title,target:"_blank"}})})),0):e("span",[t._v(t._s(t.blogger.slogan))])])]):t._e(),t._v(" "),e("NavLinks"),t._v(" "),t._t("top"),t._v(" "),e("SidebarLinks",{attrs:{depth:0,items:t.items}}),t._v(" "),t._t("bottom")],2)}),[],!1,null,null,null).exports),on=Object.assign||function(t){for(var e=1;e({threshold:100,scrollTop:null,showCommentBut:!1,commentTop:null,currentMode:"",showModeBox:!1,modeList:[{name:"跟随系统",icon:"icon-zidong",KEY:"auto"},{name:"浅色模式",icon:"icon-rijianmoshi",KEY:"light"},{name:"深色模式",icon:"icon-yejianmoshi",KEY:"dark"},{name:"阅读模式",icon:"icon-yuedu",KEY:"read"}],_scrollTimer:null,_textareaEl:null,_recordScrollTop:null,COMMENT_SELECTOR_1:"#vuepress-plugin-comment",COMMENT_SELECTOR_2:"#valine-vuepress-comment",COMMENT_SELECTOR_3:".vssue"}),mounted(){if(this.currentMode=cn.get("mode")||this.$themeConfig.defaultMode||"auto",this.scrollTop=this.getScrollTop(),window.addEventListener("scroll",Ve()(()=>{this.scrollTop=this.getScrollTop()},100)),window.addEventListener("load",()=>{this.getCommentTop()}),document.documentElement.clientWidth<719){this.$refs.modeBox.onclick=()=>{this.showModeBox=!1},window.addEventListener("scroll",Ve()(()=>{this.showModeBox&&(this.showModeBox=!1)},100))}const t=document.querySelectorAll(".buttons .button");for(let e=0;e{n.classList.remove("hover")},150)}))}},computed:{showToTop(){return this.scrollTop>this.threshold}},methods:{toggleMode(t){this.currentMode=t,this.$emit("toggle-theme-mode",t)},getScrollTop:()=>window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,scrollToTop(){window.scrollTo({top:0,behavior:"smooth"}),this.scrollTop=0},getCommentTop(){setTimeout(()=>{let t=document.querySelector(this.COMMENT_SELECTOR_1)||document.querySelector(this.COMMENT_SELECTOR_2)||document.querySelector(this.COMMENT_SELECTOR_3);t&&(this.showCommentBut=!1!==this.$frontmatter.comment&&!0!==this.$frontmatter.home,this.commentTop=t.offsetTop-58)},500)},scrollToComment(){window.scrollTo({top:this.commentTop,behavior:"smooth"}),this._textareaEl=document.querySelector(this.COMMENT_SELECTOR_1+" textarea")||document.querySelector(this.COMMENT_SELECTOR_2+" input")||document.querySelector(this.COMMENT_SELECTOR_3+" textarea"),this._textareaEl&&this.getScrollTop()!==this._recordScrollTop?document.addEventListener("scroll",this._handleListener):this._textareaEl&&this.getScrollTop()===this._recordScrollTop&&this._handleFocus()},_handleListener(){clearTimeout(this._scrollTimer),this._scrollTimer=setTimeout(()=>{document.removeEventListener("scroll",this._handleListener),this._recordScrollTop=this.getScrollTop(),this._handleFocus()},30)},_handleFocus(){this._textareaEl.focus(),this._textareaEl.classList.add("yellowBorder"),setTimeout(()=>{this._textareaEl.classList.remove("yellowBorder")},500)}},watch:{"$route.path"(){this.showCommentBut=!1,this.getCommentTop()}}},fn=(n(362),Object(o.a)(hn,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"buttons"},[e("transition",{attrs:{name:"fade"}},[e("div",{directives:[{name:"show",rawName:"v-show",value:t.showToTop,expression:"showToTop"}],staticClass:"button blur go-to-top iconfont icon-fanhuidingbu",attrs:{title:"返回顶部"},on:{click:t.scrollToTop}})]),t._v(" "),e("div",{directives:[{name:"show",rawName:"v-show",value:t.showCommentBut,expression:"showCommentBut"}],staticClass:"button blur go-to-comment iconfont icon-pinglun",attrs:{title:"去评论"},on:{click:t.scrollToComment}}),t._v(" "),e("div",{staticClass:"button blur theme-mode-but iconfont icon-zhuti",attrs:{title:"主题模式"},on:{mouseenter:function(e){t.showModeBox=!0},mouseleave:function(e){t.showModeBox=!1},click:function(e){t.showModeBox=!0}}},[e("transition",{attrs:{name:"mode"}},[e("ul",{directives:[{name:"show",rawName:"v-show",value:t.showModeBox,expression:"showModeBox"}],ref:"modeBox",staticClass:"select-box",on:{click:function(t){t.stopPropagation()},touchstart:function(t){t.stopPropagation()}}},t._l(t.modeList,(function(n){return e("li",{key:n.KEY,staticClass:"iconfont",class:[n.icon,{active:n.KEY===t.currentMode}],on:{click:function(e){return t.toggleMode(n.KEY)}}},[t._v("\n "+t._s(n.name)+"\n ")])})),0)])],1)],1)}),[],!1,null,null,null).exports),pn={computed:{social(){return this.$themeConfig.social},footer(){return this.$themeConfig.footer}}},gn=(n(363),Object(o.a)(pn,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"footer"},[t.social&&t.social.icons?e("div",{staticClass:"icons"},t._l(t.social.icons,(function(t,n){return e("a",{key:n,class:["iconfont",t.iconClass],attrs:{href:t.link,title:t.title,target:"_blank"}})})),0):t._e(),t._v(" "),t._v("\n Theme by\n "),e("a",{attrs:{href:"https://github.com/xugaoyi/vuepress-theme-vdoing",target:"_blank",title:"本站主题"}},[t._v("Vdoing")]),t._v(" "),t.footer?[t._v("\n | Copyright © "+t._s(t.footer.createYear)+"-"+t._s((new Date).getFullYear())+"\n "),e("span",{domProps:{innerHTML:t._s(t.footer.copyrightInfo)}})]:t._e()],2)}),[],!1,null,null,null).exports),dn={data:()=>({bgImg:"",opacity:.5}),mounted(){let{bodyBgImg:t,bodyBgImgOpacity:e,bodyBgImgInterval:n=15}=this.$themeConfig;if("string"===Object(r.n)(t))this.bgImg=t;else if("array"===Object(r.n)(t)){let e=0,r=null;this.bgImg=t[e],clearInterval(r),r=setInterval(()=>{if(++e>=t.length&&(e=0),this.bgImg=t[e],t[e+1]){(new Image).src=t[e+1]}},1e3*n)}void 0!==e&&(this.opacity=e)}},vn=(n(364),Object(o.a)(dn,(function(){return(0,this._self._c)("div",{staticClass:"body-bg",style:`background: url(${this.bgImg}) center center / cover no-repeat;opacity:${this.opacity}`})}),[],!1,null,null,null).exports);var mn={components:{Home:Qt,Navbar:Se,Page:qe,CategoriesPage:Ke,TagsPage:Je,ArchivesPage:en,Sidebar:rn,Footer:gn,Buttons:fn,BodyBgImg:vn},data:()=>({hideNavbar:!1,isSidebarOpen:!0,showSidebar:!1,themeMode:"auto",showWindowLB:!0,showWindowRB:!0}),computed:{sidebarSlotTop(){return this.getHtmlStr("sidebarT")},sidebarSlotBottom(){return this.getHtmlStr("sidebarB")},pageSlotTop(){return this.getHtmlStr("pageT")},pageSlotBottom(){return this.getHtmlStr("pageB")},windowLB(){return this.getHtmlStr("windowLB")},windowRB(){return this.getHtmlStr("windowRB")},showRightMenu(){const{headers:t}=this.$page;return!this.$frontmatter.home&&!1!==this.$themeConfig.rightMenuBar&&t&&t.length&&!1!==this.$frontmatter.sidebar},shouldShowNavbar(){const{themeConfig:t}=this.$site,{frontmatter:e}=this.$page;return!1!==e.navbar&&!1!==t.navbar&&(this.$title||t.logo||t.repo||t.nav||this.$themeLocaleConfig.nav)},shouldShowSidebar(){const{frontmatter:t}=this.$page;return!t.home&&!1!==t.sidebar&&this.sidebarItems.length&&!1!==t.showSidebar},sidebarItems(){return Object(r.m)(this.$page,this.$page.regularPath,this.$site,this.$localePath)},pageClasses(){const t=this.$page.frontmatter.pageClass;return[{"no-navbar":!this.shouldShowNavbar,"hide-navbar":this.hideNavbar,"sidebar-open":this.isSidebarOpen,"no-sidebar":!this.shouldShowSidebar,"have-rightmenu":this.showRightMenu,"have-body-img":this.$themeConfig.bodyBgImg,"only-sidebarItem":1===this.sidebarItems.length&&"page"===this.sidebarItems[0].type},t]}},created(){const t=this.$themeConfig.sidebarOpen;!1===t&&(this.isSidebarOpen=t)},beforeMount(){this.isSidebarOpenOfclientWidth();const t=cn.get("mode"),{defaultMode:e}=this.$themeConfig;e&&"auto"!==e&&!t?this.themeMode=e:t&&"auto"!==t&&"auto"!==e?this.themeMode=t:this._autoMode(),this.setBodyClass();const n=this.$themeConfig.social;if(n&&n.iconfontCssFile){let t=document.createElement("link");t.setAttribute("rel","stylesheet"),t.setAttribute("type","text/css"),t.setAttribute("href",n.iconfontCssFile),document.head.appendChild(t)}},mounted(){const t=document.location.hash;if(t.length>1){const e=decodeURIComponent(t.substring(1)),n=document.getElementById(e);n&&n.scrollIntoView()}this.showSidebar=!0,this.$router.afterEach(()=>{this.isSidebarOpenOfclientWidth()});let e=0,n=0;window.addEventListener("scroll",te.a.throttle(()=>{this.isSidebarOpen||(e=this.getScrollTop(),this.hideNavbar=n58,setTimeout(()=>{n=e},0))},300))},watch:{isSidebarOpen(){this.isSidebarOpen&&(this.hideNavbar=!1)},themeMode(){this.setBodyClass()}},methods:{getHtmlStr(t){const{htmlModules:e}=this.$themeConfig;return e?e[t]:""},setBodyClass(){let{pageStyle:t="card",bodyBgImg:e}=this.$themeConfig;("card"!==t&&"line"!==t||e)&&(t="card"),document.body.className=`theme-mode-${this.themeMode} theme-style-${t}`},getScrollTop:()=>window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,isSidebarOpenOfclientWidth(){document.documentElement.clientWidth<719&&(this.isSidebarOpen=!1)},toggleSidebar(t){this.isSidebarOpen="boolean"==typeof t?t:!this.isSidebarOpen,this.$emit("toggle-sidebar",this.isSidebarOpen)},_autoMode(){window.matchMedia("(prefers-color-scheme: dark)").matches?this.themeMode="dark":this.themeMode="light"},toggleThemeMode(t){"auto"===t?this._autoMode():this.themeMode=t,cn.set("mode",t)},onTouchStart(t){this.touchStart={x:t.changedTouches[0].clientX,y:t.changedTouches[0].clientY}},onTouchEnd(t){const e=t.changedTouches[0].clientX-this.touchStart.x,n=t.changedTouches[0].clientY-this.touchStart.y;Math.abs(e)>Math.abs(n)&&Math.abs(e)>40&&(e>0&&this.touchStart.x<=80?this.toggleSidebar(!0):this.toggleSidebar(!1))}}},yn=(n(365),Object(o.a)(mn,(function(){var t=this,e=t._self._c;return e("div",{staticClass:"theme-container",class:t.pageClasses,on:{touchstart:t.onTouchStart,touchend:t.onTouchEnd}},[t.shouldShowNavbar?e("Navbar",{on:{"toggle-sidebar":t.toggleSidebar}}):t._e(),t._v(" "),e("div",{staticClass:"sidebar-mask",on:{click:function(e){return t.toggleSidebar(!1)}}}),t._v(" "),!1!==t.$themeConfig.sidebarHoverTriggerOpen?e("div",{staticClass:"sidebar-hover-trigger"}):t._e(),t._v(" "),e("Sidebar",{directives:[{name:"show",rawName:"v-show",value:t.showSidebar,expression:"showSidebar"}],attrs:{items:t.sidebarItems},on:{"toggle-sidebar":t.toggleSidebar},scopedSlots:t._u([t.sidebarSlotTop?{key:"top",fn:function(){return[e("div",{staticClass:"sidebar-slot sidebar-slot-top",domProps:{innerHTML:t._s(t.sidebarSlotTop)}})]},proxy:!0}:null,t.sidebarSlotBottom?{key:"bottom",fn:function(){return[e("div",{staticClass:"sidebar-slot sidebar-slot-bottom",domProps:{innerHTML:t._s(t.sidebarSlotBottom)}})]},proxy:!0}:null],null,!0)}),t._v(" "),t.$page.frontmatter.home?e("Home"):t.$page.frontmatter.categoriesPage?e("CategoriesPage"):t.$page.frontmatter.tagsPage?e("TagsPage"):t.$page.frontmatter.archivesPage?e("ArchivesPage"):e("Page",{attrs:{"sidebar-items":t.sidebarItems},scopedSlots:t._u([t.pageSlotTop?{key:"top",fn:function(){return[e("div",{staticClass:"page-slot page-slot-top",domProps:{innerHTML:t._s(t.pageSlotTop)}})]},proxy:!0}:null,t.pageSlotBottom?{key:"bottom",fn:function(){return[e("div",{staticClass:"page-slot page-slot-bottom",domProps:{innerHTML:t._s(t.pageSlotBottom)}})]},proxy:!0}:null],null,!0)}),t._v(" "),e("Footer"),t._v(" "),e("Buttons",{ref:"buttons",on:{"toggle-theme-mode":t.toggleThemeMode}}),t._v(" "),t.$themeConfig.bodyBgImg?e("BodyBgImg"):t._e(),t._v(" "),t.windowLB?e("div",{directives:[{name:"show",rawName:"v-show",value:t.showWindowLB,expression:"showWindowLB"}],staticClass:"custom-html-window custom-html-window-lb"},[e("div",{staticClass:"custom-wrapper"},[e("span",{staticClass:"close-but",on:{click:function(e){t.showWindowLB=!1}}},[t._v("×")]),t._v(" "),e("div",{domProps:{innerHTML:t._s(t.windowLB)}})])]):t._e(),t._v(" "),t.windowRB?e("div",{directives:[{name:"show",rawName:"v-show",value:t.showWindowRB,expression:"showWindowRB"}],staticClass:"custom-html-window custom-html-window-rb"},[e("div",{staticClass:"custom-wrapper"},[e("span",{staticClass:"close-but",on:{click:function(e){t.showWindowRB=!1}}},[t._v("×")]),t._v(" "),e("div",{domProps:{innerHTML:t._s(t.windowRB)}})])]):t._e()],1)}),[],!1,null,null,null));e.default=yn.exports}}]); \ No newline at end of file diff --git a/assets/js/20.0284ceba.js b/assets/js/20.0284ceba.js new file mode 100644 index 0000000..0a52495 --- /dev/null +++ b/assets/js/20.0284ceba.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{384:function(t,n,s){"use strict";s.r(n);var e=s(15),o=Object(e.a)({},(function(){return(0,this._self._c)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/21.25bb2d53.js b/assets/js/21.25bb2d53.js new file mode 100644 index 0000000..fef7ea4 --- /dev/null +++ b/assets/js/21.25bb2d53.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{386:function(t,n,s){"use strict";s.r(n);var e=s(15),o=Object(e.a)({},(function(){return(0,this._self._c)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/22.b1f31a26.js b/assets/js/22.b1f31a26.js new file mode 100644 index 0000000..366021e --- /dev/null +++ b/assets/js/22.b1f31a26.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{385:function(t,n,s){"use strict";s.r(n);var e=s(15),o=Object(e.a)({},(function(){return(0,this._self._c)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/23.834cd45f.js b/assets/js/23.834cd45f.js new file mode 100644 index 0000000..46c1669 --- /dev/null +++ b/assets/js/23.834cd45f.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{387:function(t,r,a){"use strict";a.r(r);var e=a(15),o=Object(e.a)({},(function(){var t=this,r=t._self._c;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("p",{attrs:{align:"center"}},[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial"}},[r("img",{staticClass:"no-zoom",attrs:{alt:"star",src:"https://img.shields.io/github/stars/dunwu/algorithm-tutorial?style=for-the-badge"}})]),t._v(" "),r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial"}},[r("img",{staticClass:"no-zoom",attrs:{alt:"fork",src:"https://img.shields.io/github/forks/dunwu/algorithm-tutorial?style=for-the-badge"}})]),t._v(" "),r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/commits/master"}},[r("img",{staticClass:"no-zoom",attrs:{alt:"build",src:"https://img.shields.io/github/actions/workflow/status/dunwu/algorithm-tutorial/deploy.yml?style=for-the-badge"}})]),t._v(" "),r("a",{attrs:{href:"https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh"}},[r("img",{staticClass:"no-zoom",attrs:{alt:"code style",src:"https://img.shields.io/github/license/dunwu/algorithm-tutorial?style=for-the-badge"}})])]),t._v(" "),r("h1",{attrs:{align:"center"}},[t._v("ALGORITHM-TUTORIAL")]),t._v(" "),r("blockquote",[r("p",[t._v("💾 algorithm-tutorial 是一个数据结构与算法教程。")]),t._v(" "),r("p",[t._v("掌握数据结构与算法,你看待问题的深度,解决问题的角度就会完全不一样。")]),t._v(" "),r("ul",[r("li",[t._v("🔁 项目同步维护:"),r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Github"),r("OutboundLink")],1),t._v(" | "),r("a",{attrs:{href:"https://gitee.com/turnon/algorithm-tutorial/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Gitee"),r("OutboundLink")],1)]),t._v(" "),r("li",[t._v("📖 电子书阅读:"),r("a",{attrs:{href:"https://dunwu.github.io/algorithm-tutorial/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Github Pages"),r("OutboundLink")],1),t._v(" | "),r("a",{attrs:{href:"http://turnon.gitee.io/algorithm-tutorial/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Gitee Pages"),r("OutboundLink")],1)])])]),t._v(" "),r("h2",{attrs:{id:"📖-内容"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#📖-内容"}},[t._v("#")]),t._v(" 📖 内容")]),t._v(" "),r("p",[r("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20200702071922.png",alt:"img"}})]),t._v(" "),r("ul",[r("li",[t._v("综合")]),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/00.综合/01.数据结构和算法指南.html"}},[t._v("数据结构和算法指南")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/00.综合/02.复杂度分析.html"}},[t._v("复杂度分析")]),t._v(" - 关键词:"),r("strong",[r("code",[t._v("时间复杂度")])]),t._v("、"),r("strong",[r("code",[t._v("空间复杂度")])]),t._v("、"),r("strong",[r("code",[t._v("大 O 表示法")])]),t._v("、"),r("strong",[r("code",[t._v("复杂度量级")])])],1),t._v(" "),r("li",[t._v("线性表\n"),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/01.线性表/01.数组和链表.html"}},[t._v("数组和链表")]),t._v(" - 关键词:"),r("strong",[r("code",[t._v("线性表")])]),t._v("、"),r("strong",[r("code",[t._v("一维数组")])]),t._v("、"),r("strong",[r("code",[t._v("多维数组")])]),t._v("、"),r("strong",[r("code",[t._v("随机访问")])]),t._v("、"),r("strong",[r("code",[t._v("单链表")])]),t._v("、"),r("strong",[r("code",[t._v("双链表")])]),t._v("、"),r("strong",[r("code",[t._v("循环链表")])])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/01.线性表/02.栈和队列.html"}},[t._v("栈和队列")]),t._v(" - 关键词:"),r("strong",[r("code",[t._v("先进后出")])]),t._v("、"),r("strong",[r("code",[t._v("后进先出")])]),t._v("、"),r("strong",[r("code",[t._v("循环队列")])])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/01.线性表/11.线性表的查找.html"}},[t._v("线性表的查找")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/01.线性表/12.线性表的排序.html"}},[t._v("线性表的排序")])],1)])]),t._v(" "),r("li",[t._v("树\n"),r("ul",[r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/02.树/01.树和二叉树.html"}},[t._v("树和二叉树")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/02.树/02.堆.html"}},[t._v("堆")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/02.树/03.B+树.html"}},[t._v("B+树")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/02.树/04.LSM树.html"}},[t._v("LSM 树")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/02.树/05.字典树.html"}},[t._v("字典树")])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/02.树/06.红黑树.html"}},[t._v("红黑树")])],1)])]),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/03.哈希表.html"}},[t._v("哈希表")]),t._v(" - 关键词:"),r("strong",[r("code",[t._v("哈希函数")])]),t._v("、"),r("strong",[r("code",[t._v("装载因子")])]),t._v("、"),r("strong",[r("code",[t._v("哈希冲突")])]),t._v("、"),r("strong",[r("code",[t._v("开放寻址法")])]),t._v("、"),r("strong",[r("code",[t._v("拉链法")])])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/04.跳表.html"}},[t._v("跳表")]),t._v(" - 关键词:"),r("strong",[r("code",[t._v("多级索引")])])],1),t._v(" "),r("li",[r("RouterLink",{attrs:{to:"/01.数据结构和算法/05.图.html"}},[t._v("图")])],1)]),t._v(" "),r("h2",{attrs:{id:"💻-刷题"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#💻-刷题"}},[t._v("#")]),t._v(" 💻 刷题")]),t._v(" "),r("h3",{attrs:{id:"数组"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#数组"}},[t._v("#")]),t._v(" 数组")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("三数之和"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("两数之和"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E4%BA%8C%E7%BB%B4%E6%95%B0%E7%BB%84.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二维数组"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E5%88%A0%E9%99%A4%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E9%A1%B9.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("删除排序数组中的重复项"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E5%8A%A0%E4%B8%80.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("加一"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9F%A5%E6%89%BE%E5%85%83%E7%B4%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%92%8C%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E4%BD%8D%E7%BD%AE.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("在排序数组中查找元素的第一个和最后一个位置"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9F%A5%E6%89%BE%E6%95%B0%E5%AD%97I.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("在排序数组中查找数字 I"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E5%AD%98%E5%9C%A8%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A0.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("存在重复元素"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E5%AF%B9%E8%A7%92%E7%BA%BF%E9%81%8D%E5%8E%86.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("对角线遍历"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E5%AF%BB%E6%89%BE%E6%95%B0%E7%BB%84%E7%9A%84%E4%B8%AD%E5%BF%83%E7%B4%A2%E5%BC%95.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("寻找数组的中心索引"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E5%B0%86%E6%95%B0%E7%BB%84%E5%88%86%E6%88%90%E5%92%8C%E7%9B%B8%E7%AD%89%E7%9A%84%E4%B8%89%E4%B8%AA%E9%83%A8%E5%88%86.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("将数组分成和相等的三个部分"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E6%95%B0%E7%BB%84%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("数组二分查找"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E6%95%B0%E7%BB%84%E6%8B%86%E5%88%861.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("数组拆分 1"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E6%97%8B%E8%BD%AC%E6%95%B0%E7%BB%84.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("旋转数组"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E6%97%8B%E8%BD%AC%E7%9F%A9%E9%98%B5.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("旋转矩阵"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E6%9C%80%E5%A4%A7%E8%BF%9E%E7%BB%AD1%E7%9A%84%E4%B8%AA%E6%95%B0.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("最大连续 1 的个数"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E6%9D%A8%E8%BE%89%E4%B8%89%E8%A7%92.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("杨辉三角"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E6%9D%A8%E8%BE%89%E4%B8%89%E8%A7%922.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("杨辉三角 2"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E6%A8%A1%E6%8B%9FArrayList1.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("模拟 ArrayList1"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E6%A8%A1%E6%8B%9FArrayList2.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("模拟 ArrayList2"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E7%A7%BB%E5%8A%A8%E9%9B%B6.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("移动零"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("移除元素"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E8%87%B3%E5%B0%91%E6%98%AF%E5%85%B6%E4%BB%96%E6%95%B0%E5%AD%97%E4%B8%A4%E5%80%8D%E7%9A%84%E6%9C%80%E5%A4%A7%E6%95%B0.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("至少是其他数字两倍的最大数"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("螺旋矩阵"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("长度最小的子数组"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/%E9%9B%B6%E7%9F%A9%E9%98%B5.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("零矩阵"),r("OutboundLink")],1)])]),t._v(" "),r("h3",{attrs:{id:"链表"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#链表"}},[t._v("#")]),t._v(" 链表")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E4%B8%A4%E6%95%B0%E7%9B%B8%E5%8A%A0.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("两数相加"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E4%BA%8C%E8%BF%9B%E5%88%B6%E9%93%BE%E8%A1%A8%E8%BD%AC%E6%95%B4%E6%95%B0.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二进制链表转整数"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E5%88%A0%E9%99%A4%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A0.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("删除排序链表中的重复元素"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E5%8D%95%E9%93%BE%E8%A1%A8%E7%A4%BA%E4%BE%8B.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("单链表示例"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E5%8F%8C%E9%93%BE%E8%A1%A8%E7%A4%BA%E4%BE%8B.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("双链表示例"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("反转链表"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E5%90%88%E5%B9%B6K%E4%B8%AA%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("合并 K 个排序链表"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E5%90%88%E5%B9%B6K%E4%B8%AA%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8%E8%A7%A3%E6%B3%952.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("合并 K 个排序链表解法 2"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%9C%89%E5%BA%8F%E9%93%BE%E8%A1%A8.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("合并两个有序链表"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E5%9B%9E%E6%96%87%E9%93%BE%E8%A1%A8.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("回文链表"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("排序链表"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("环形链表"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E7%9B%B8%E4%BA%A4%E9%93%BE%E8%A1%A8.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("相交链表"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E7%A7%BB%E9%99%A4%E9%87%8D%E5%A4%8D%E8%8A%82%E7%82%B9.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("移除重复节点"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("移除链表元素"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E8%BF%94%E5%9B%9E%E5%80%92%E6%95%B0%E7%AC%ACk%E4%B8%AA%E8%8A%82%E7%82%B9.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("返回倒数第 k 个节点"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/%E9%93%BE%E8%A1%A8%E7%9A%84%E4%B8%AD%E9%97%B4%E7%BB%93%E7%82%B9.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("链表的中间结点"),r("OutboundLink")],1)])]),t._v(" "),r("h3",{attrs:{id:"栈"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#栈"}},[t._v("#")]),t._v(" 栈")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E4%B8%89%E5%90%88%E4%B8%80.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("三合一"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E5%9F%BA%E6%9C%AC%E8%AE%A1%E7%AE%97%E5%99%A8.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("基本计算器"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E6%9C%80%E5%B0%8F%E6%A0%88.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("最小栈"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E6%9C%80%E5%B0%8F%E6%A0%882.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("最小栈 2"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("有效的括号"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E6%A0%88%E6%8E%92%E5%BA%8F.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("栈排序"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E6%A3%92%E7%90%83%E6%AF%94%E8%B5%9B.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("棒球比赛"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E6%AF%94%E8%BE%83%E5%90%AB%E9%80%80%E6%A0%BC%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("比较含退格的字符串"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E7%94%A8%E6%A0%88%E5%AE%9E%E7%8E%B0%E9%98%9F%E5%88%97.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("用栈实现队列"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/%E7%94%A8%E9%98%9F%E5%88%97%E5%AE%9E%E7%8E%B0%E6%A0%88.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("用队列实现栈"),r("OutboundLink")],1)])]),t._v(" "),r("h3",{attrs:{id:"队列"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#队列"}},[t._v("#")]),t._v(" 队列")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/%E5%8A%A8%E6%80%81%E6%89%A9%E5%AE%B9%E6%95%B0%E7%BB%84%E5%AE%9E%E7%8E%B0%E7%9A%84%E9%98%9F%E5%88%97.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("动态扩容数组实现的队列"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/%E6%95%B0%E7%BB%84%E5%AE%9E%E7%8E%B0%E7%9A%84%E9%98%9F%E5%88%97.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("数组实现的队列"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/%E6%9C%80%E8%BF%91%E7%9A%84%E8%AF%B7%E6%B1%82%E6%AC%A1%E6%95%B0.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("最近的请求次数"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/%E8%AE%BE%E8%AE%A1%E5%BE%AA%E7%8E%AF%E9%98%9F%E5%88%97.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("设计循环队列"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/%E9%93%BE%E8%A1%A8%E5%AE%9E%E7%8E%B0%E7%9A%84%E9%98%9F%E5%88%97.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("链表实现的队列"),r("OutboundLink")],1)])]),t._v(" "),r("h3",{attrs:{id:"字符串"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#字符串"}},[t._v("#")]),t._v(" 字符串")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/AddBinary.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二进制求和"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ImplementStrstr.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("实现 strStr()"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/LongestCommonPrefix.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("最长公共前缀"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ReverseString.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("反转字符串"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ReverseWordsInAString.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("反转字符串中的单词"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ReverseWordsInAString3.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("反转字符串中的单词 III"),r("OutboundLink")],1)])]),t._v(" "),r("h3",{attrs:{id:"树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#树"}},[t._v("#")]),t._v(" 树")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/N%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%A4%A7%E6%B7%B1%E5%BA%A6.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("N 叉树的最大深度"),r("OutboundLink")],1)])]),t._v(" "),r("h4",{attrs:{id:"二叉树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉树"}},[t._v("#")]),t._v(" 二叉树")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%AD%E7%9A%84%E6%9C%80%E5%A4%A7%E8%B7%AF%E5%BE%84%E5%92%8C.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树中的最大路径和"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的中序遍历"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%89%8D%E5%BA%8F%E9%81%8D%E5%8E%86.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的前序遍历"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的后序遍历"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%B1%82%E6%AC%A1%E9%81%8D%E5%8E%86.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的层次遍历"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%B1%82%E6%AC%A1%E9%81%8D%E5%8E%862.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的层次遍历 2"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%BA%8F%E5%88%97%E5%8C%96%E4%B8%8E%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的序列化与反序列化"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%89%80%E6%9C%89%E8%B7%AF%E5%BE%84.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的所有路径"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%A4%A7%E6%B7%B1%E5%BA%A6.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的最大深度"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%B0%8F%E6%B7%B1%E5%BA%A6.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的最小深度"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的最近公共祖先"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%94%AF%E9%BD%BF%E5%BD%A2%E5%B1%82%E6%AC%A1%E9%81%8D%E5%8E%86.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉树的锯齿形层次遍历"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E4%BB%8E%E5%85%88%E5%BA%8F%E9%81%8D%E5%8E%86%E8%BF%98%E5%8E%9F%E4%BA%8C%E5%8F%89%E6%A0%91.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("从先序遍历还原二叉树"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E5%8F%B6%E5%AD%90%E7%9B%B8%E4%BC%BC%E7%9A%84%E6%A0%91.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("叶子相似的树"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E5%A1%AB%E5%85%85%E6%AF%8F%E4%B8%AA%E8%8A%82%E7%82%B9%E7%9A%84%E4%B8%8B%E4%B8%80%E4%B8%AA%E5%8F%B3%E4%BE%A7%E8%8A%82%E7%82%B9%E6%8C%87%E9%92%88.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("填充每个节点的下一个右侧节点指针"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E5%A1%AB%E5%85%85%E6%AF%8F%E4%B8%AA%E8%8A%82%E7%82%B9%E7%9A%84%E4%B8%8B%E4%B8%80%E4%B8%AA%E5%8F%B3%E4%BE%A7%E8%8A%82%E7%82%B9%E6%8C%87%E9%92%88II.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("填充每个节点的下一个右侧节点指针 II"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E5%AF%B9%E7%A7%B0%E4%BA%8C%E5%8F%89%E6%A0%91.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("对称二叉树"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("平衡二叉树"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E7%9B%B8%E5%90%8C%E7%9A%84%E6%A0%91.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("相同的树"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E7%BF%BB%E8%BD%AC%E4%BA%8C%E5%8F%89%E6%A0%91.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("翻转二叉树"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("路径总和"),r("OutboundLink")],1)])]),t._v(" "),r("h4",{attrs:{id:"二叉搜索树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉搜索树"}},[t._v("#")]),t._v(" 二叉搜索树")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%AD%E7%9A%84%E6%8F%92%E5%85%A5%E6%93%8D%E4%BD%9C.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉搜索树中的插入操作"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉搜索树的最近公共祖先"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E8%8A%82%E7%82%B9%E6%9C%80%E5%B0%8F%E8%B7%9D%E7%A6%BB.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("二叉搜索树节点最小距离"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/%E5%B0%86%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E8%BD%AC%E6%8D%A2%E4%B8%BA%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("将有序数组转换为二叉搜索树"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/%E9%AA%8C%E8%AF%81%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("验证二叉搜索树"),r("OutboundLink")],1)])]),t._v(" "),r("h2",{attrs:{id:"📚-资料"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#📚-资料"}},[t._v("#")]),t._v(" 📚 资料")]),t._v(" "),r("ul",[r("li",[r("strong",[t._v("书籍")]),t._v(" "),r("ul",[r("li",[t._v("刷题必备\n"),r("ul",[r("li",[t._v("《剑指 offer》")]),t._v(" "),r("li",[t._v("《编程之美》")]),t._v(" "),r("li",[t._v("《编程之法:面试和算法心得》")]),t._v(" "),r("li",[t._v("《算法谜题》 都是思维题")])])]),t._v(" "),r("li",[t._v("基础\n"),r("ul",[r("li",[t._v("《"),r("a",{attrs:{href:"https://www.amazon.cn/gp/product/B00SFZH0DC/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00SFZH0DC&linkCode=as2&tag=vastwork-23",target:"_blank",rel:"noopener noreferrer"}},[t._v("编程珠玑(第 2 版)"),r("OutboundLink")],1),t._v("》")]),t._v(" "),r("li",[t._v("《"),r("a",{attrs:{href:"https://www.amazon.cn/gp/product/B0150BMQDM/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B0150BMQDM&linkCode=as2&tag=vastwork-23",target:"_blank",rel:"noopener noreferrer"}},[t._v("编程珠玑(续)"),r("OutboundLink")],1),t._v("》")]),t._v(" "),r("li",[t._v("《"),r("a",{attrs:{href:"https://www.amazon.cn/gp/product/B01LDG2DSG/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01LDG2DSG&linkCode=as2&tag=vastwork-23",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法分析 : C++描述(第 4 版)"),r("OutboundLink")],1),t._v("》")]),t._v(" "),r("li",[t._v("《"),r("a",{attrs:{href:"https://www.amazon.cn/gp/product/B002WC7NGS/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B002WC7NGS&linkCode=as2&tag=vastwork-23",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法分析 : C 语言描述(第 2 版)"),r("OutboundLink")],1),t._v("》")]),t._v(" "),r("li",[t._v("《"),r("a",{attrs:{href:"https://www.amazon.cn/gp/product/B01CNP0CG6/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01CNP0CG6&linkCode=as2&tag=vastwork-23",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法分析 : Java 语言描述(第 2 版)"),r("OutboundLink")],1),t._v("》")]),t._v(" "),r("li",[t._v("《"),r("a",{attrs:{href:"https://www.amazon.cn/gp/product/B009OCFQ0O/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B009OCFQ0O&linkCode=as2&tag=vastwork-23",target:"_blank",rel:"noopener noreferrer"}},[t._v("算法(第 4 版)"),r("OutboundLink")],1),t._v("》")])])]),t._v(" "),r("li",[t._v("算法设计\n"),r("ul",[r("li",[t._v("《"),r("a",{attrs:{href:"https://www.amazon.cn/gp/product/B00S4HCQUI/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00S4HCQUI&linkCode=as2&tag=vastwork-23",target:"_blank",rel:"noopener noreferrer"}},[t._v("算法设计与分析基础(第 3 版)"),r("OutboundLink")],1),t._v("》")]),t._v(" "),r("li",[t._v("《Algorithm Design Manual》 - 算法设计手册 红皮书")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://www.amazon.cn/gp/product/B00AK7BYJY/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00AK7BYJY&linkCode=as2&tag=vastwork-23",target:"_blank",rel:"noopener noreferrer"}},[t._v("《算法导论》"),r("OutboundLink")],1),t._v(" - 是一本对算法介绍比较全面的经典书籍")]),t._v(" "),r("li",[t._v("《Algorithms on Strings,Trees and Sequences》")]),t._v(" "),r("li",[t._v("《Advanced Data Structures》 - 各种诡异高级的数据结构和算法 如元胞自动机、斐波纳契堆、线段树 600 块")])])])])]),t._v(" "),r("li",[r("strong",[t._v("学习网站")]),t._v(" "),r("ul",[r("li",[t._v("https://github.com/TheAlgorithms/Java")]),t._v(" "),r("li",[t._v("https://github.com/nonstriater/Learn-Algorithms")]),t._v(" "),r("li",[t._v("https://github.com/trekhleb/javascript-algorithms")]),t._v(" "),r("li",[t._v("https://github.com/wangzheng0822/algo")]),t._v(" "),r("li",[t._v("https://github.com/kdn251/interviews/blob/master/README-zh-cn.md#%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84")]),t._v(" "),r("li",[r("a",{attrs:{href:"http://blog.csdn.net/v_july_v",target:"_blank",rel:"noopener noreferrer"}},[t._v("July 博客"),r("OutboundLink")],1),t._v(" "),r("ul",[r("li",[t._v("《数学建模十大经典算法》")]),t._v(" "),r("li",[t._v("《数据挖掘领域十大经典算法》")]),t._v(" "),r("li",[t._v("《十道海量数据处理面试题》")]),t._v(" "),r("li",[t._v("《数字图像处理领域的二十四个经典算法》")]),t._v(" "),r("li",[t._v("《精选微软等公司经典的算法面试 100 题》")])])]),t._v(" "),r("li",[r("a",{attrs:{href:"https://github.com/julycoding/The-Art-Of-Programming-By-July",target:"_blank",rel:"noopener noreferrer"}},[t._v("The-Art-Of-Programming-By-July"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://blog.csdn.net/column/details/ms100.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("微软面试 100 题"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://blog.csdn.net/v_JULY_v/article/details/6460494",target:"_blank",rel:"noopener noreferrer"}},[t._v("程序员编程艺术"),r("OutboundLink")],1)])])]),t._v(" "),r("li",[r("strong",[t._v("基本算法演示")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"http://sjjg.js.zwu.edu.cn/SFXX/sf1/sfys.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://sjjg.js.zwu.edu.cn/SFXX/sf1/sfys.html"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://www.cs.usfca.edu/%5C~galles/visualization/Algorithms.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://www.cs.usfca.edu/\\~galles/visualization/Algorithms.html"),r("OutboundLink")],1)])])]),t._v(" "),r("li",[r("strong",[t._v("编程网站")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"http://leetcode-cn.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("leetcode"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"http://openjudge.cn/",target:"_blank",rel:"noopener noreferrer"}},[t._v("openjudge"),r("OutboundLink")],1)])])]),t._v(" "),r("li",[r("strong",[t._v("教程")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://www.coursera.org/learn/gaoji-shuju-jiegou/",target:"_blank",rel:"noopener noreferrer"}},[t._v("高级数据结构和算法"),r("OutboundLink")],1),t._v(" 北大教授张铭老师在 coursera 上的课程。完成这门课之时,你将掌握多维数组、广义表、Trie 树、AVL 树、伸展树等高级数据结构,并结合内排序、外排序、检索、索引有关的算法,高效地解决现实生活中一些比较复杂的应用问题。当然 coursera 上也还有很多其它算法方面的视频课程。")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://class.coursera.org/algorithms-001/lecture",target:"_blank",rel:"noopener noreferrer"}},[t._v("算法设计与分析 Design and Analysis of Algorithms"),r("OutboundLink")],1),t._v(" 由北大教授 Wanling Qu 在 coursera 讲授的一门算法课程。首先介绍一些与算法有关的基础知识,然后阐述经典的算法设计思想和分析技术,主要涉及的算法设计技术是:分治策略、动态规划、贪心法、回溯与分支限界等。每个视频都配有相应的讲义(pdf 文件)以便阅读和复习。")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://time.geekbang.org/course/intro/100019701",target:"_blank",rel:"noopener noreferrer"}},[t._v("算法面试通关 40 讲"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法之美"),r("OutboundLink")],1)])])])]),t._v(" "),r("h2",{attrs:{id:"🚪-传送"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#🚪-传送"}},[t._v("#")]),t._v(" 🚪 传送")]),t._v(" "),r("p",[t._v("| "),r("a",{attrs:{href:"https://github.com/dunwu/blog",target:"_blank",rel:"noopener noreferrer"}},[t._v("技术文档归档"),r("OutboundLink")],1),t._v(" | "),r("a",{attrs:{href:"https://github.com/dunwu/algorithm-tutorial",target:"_blank",rel:"noopener noreferrer"}},[t._v("算法和数据结构教程系列"),r("OutboundLink")],1),t._v(" |")])])}),[],!1,null,null,null);r.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/24.063e120c.js b/assets/js/24.063e120c.js new file mode 100644 index 0000000..6d92a75 --- /dev/null +++ b/assets/js/24.063e120c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{388:function(t,s,a){"use strict";a.r(s);var n=a(15),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"算法代码模板"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#算法代码模板"}},[t._v("#")]),t._v(" 算法代码模板")]),t._v(" "),s("blockquote",[s("p",[t._v("算法代码模板即算法的常见套路。熟练记忆,活学活用。")])]),t._v(" "),s("h2",{attrs:{id:"递归"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#递归"}},[t._v("#")]),t._v(" 递归")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("recursion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" level"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" param1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" param2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 递归终止条件")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token constant"}},[t._v("MAX_LEVEL")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// print")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 当前处理逻辑")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("processData")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" param1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" param2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 递归")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("recursion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" param1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" param2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 如有必要,还原状态")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("reverseState")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("level"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" data"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h2",{attrs:{id:"dfs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#dfs"}},[t._v("#")]),t._v(" DFS")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Set")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Node")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" visited "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashSet")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("dfs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Node")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Set")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Node")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" visited"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n visited"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Node")]),t._v(" n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("children"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("visited"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("contains")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("dfs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" visited"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h2",{attrs:{id:"bfs"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#bfs"}},[t._v("#")]),t._v(" BFS")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("List")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("List")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Integer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("bfs")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Node")]),t._v(" root"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("List")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("List")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Integer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" list "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ArrayList")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Queue")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Node")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" queue "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LinkedList")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n queue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("offer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("root"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("queue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("isEmpty")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("List")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Integer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" levelList "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ArrayList")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" size "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" queue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("size")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 遍历当前层级所有节点")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" size"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Node")]),t._v(" n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" queue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("poll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 对节点 n 做逻辑处理")]),t._v("\n levelList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("val"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 将 n 的所有节点加入队列")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Node")]),t._v(" c "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("children"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n queue"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("offer")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("c"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("add")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("levelList"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h2",{attrs:{id:"二分查找"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#二分查找"}},[t._v("#")]),t._v(" 二分查找")]),t._v(" "),s("p",[t._v("数组的二分查找:")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" left "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" right "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" nums"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("left "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" right"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" left "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("right "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" left"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 防止数据类型溢出")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("nums"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("mid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" target"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("break")]),t._v(" or "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("nums"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("mid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" target"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n left "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n right "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h2",{attrs:{id:"动态规划"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#动态规划"}},[t._v("#")]),t._v(" 动态规划")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// DP 状态定义")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" dp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("m "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 初始状态")]),t._v("\ndp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" x"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\ndp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" y"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// DP 状态推导")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" m"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 方程根据实际场景推导")]),t._v("\n dp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" max or min "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" dp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" dp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 返回最优解")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" dp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("m"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("h2",{attrs:{id:"位运算"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#位运算"}},[t._v("#")]),t._v(" 位运算")]),t._v(" "),s("p",[t._v("记忆常用位运算公式(无他,背就完事了)")]),t._v(" "),s("table",[s("thead",[s("tr",[s("th"),t._v(" "),s("th",[t._v("二进制表达式")]),t._v(" "),s("th",[t._v("等价表达式")])])]),t._v(" "),s("tbody",[s("tr",[s("td",[t._v("判断奇偶")]),t._v(" "),s("td",[s("code",[t._v("x & 1 == 1")]),s("br"),s("code",[t._v("x & 1 == 0")])]),t._v(" "),s("td",[s("code",[t._v("x % 2 == 1")]),s("br"),s("code",[t._v("x % 2 == 0")])])]),t._v(" "),s("tr",[s("td",[t._v("清零最低位的 1")]),t._v(" "),s("td",[s("code",[t._v("x = x & (x - 1)")])]),t._v(" "),s("td")]),t._v(" "),s("tr",[s("td",[t._v("得到最低位的 1")]),t._v(" "),s("td",[s("code",[t._v("x & -x")])]),t._v(" "),s("td")])])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/25.ec0d8024.js b/assets/js/25.ec0d8024.js new file mode 100644 index 0000000..dea9f2b --- /dev/null +++ b/assets/js/25.ec0d8024.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{389:function(t,a,s){"use strict";s.r(a);var n=s(15),r=Object(n.a)({},(function(){var t=this,a=t._self._c;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"hash-表的查找"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#hash-表的查找"}},[t._v("#")]),t._v(" Hash 表的查找")]),t._v(" "),a("h2",{attrs:{id:"要点"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#要点"}},[t._v("#")]),t._v(" 要点")]),t._v(" "),a("h3",{attrs:{id:"哈希表和哈希函数"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#哈希表和哈希函数"}},[t._v("#")]),t._v(" 哈希表和哈希函数")]),t._v(" "),a("p",[t._v("在记录的存储位置和它的关键字之间是建立一个确定的对应关系(映射函数),使每个关键字和一个存储位置能"),a("strong",[t._v("唯一对应")]),t._v("。这个映射函数称为"),a("strong",[t._v("哈希函数")]),t._v(",根据这个原则建立的表称为"),a("strong",[t._v("哈希表(Hash Table)")]),t._v(",也叫"),a("strong",[t._v("哈希表")]),t._v("。")]),t._v(" "),a("p",[t._v("以上描述,如果通过数学形式来描述就是:")]),t._v(" "),a("p",[t._v("若查找关键字为 "),a("strong",[t._v("key")]),t._v(",则其值存放在 "),a("strong",[t._v("f(key)")]),t._v(" 的存储位置上。由此,"),a("strong",[t._v("不需比较便可直接取得所查记录")]),t._v("。")]),t._v(" "),a("p",[a("em",[a("strong",[t._v("注:哈希查找与线性表查找和树表查找最大的区别在于,不用数值比较。")])])]),t._v(" "),a("h3",{attrs:{id:"冲突"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#冲突"}},[t._v("#")]),t._v(" 冲突")]),t._v(" "),a("p",[t._v("若 key1 ≠ key2 ,而 f(key1) = f(key2),这种情况称为"),a("strong",[t._v("冲突(Collision)")]),t._v("。")]),t._v(" "),a("p",[t._v("根据哈希函数f(key)和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这一映射过程称为"),a("strong",[t._v("构造哈希表")]),t._v("。")]),t._v(" "),a("p",[t._v("构造哈希表这个场景就像汽车找停车位,如果车位被人占了,只能找空的地方停。")]),t._v(" "),a("p",[a("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-4f4e0c3def86f7bb.jpg",alt:"img",title:"点击查看源网页"}})]),t._v(" "),a("h2",{attrs:{id:"构造哈希表"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#构造哈希表"}},[t._v("#")]),t._v(" 构造哈希表")]),t._v(" "),a("p",[t._v("由以上内容可知,哈希查找本身其实不费吹灰之力,问题的关键在于如何构造哈希表和处理冲突。")]),t._v(" "),a("p",[t._v("常见的构造哈希表的方法有 "),a("code",[t._v("5")]),t._v(" 种:")]),t._v(" "),a("h3",{attrs:{id:"直接定址法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#直接定址法"}},[t._v("#")]),t._v(" 直接定址法")]),t._v(" "),a("p",[t._v("说白了,就是小学时学过的"),a("strong",[t._v("一元一次方程")]),t._v("。")]),t._v(" "),a("p",[t._v("即 f(key) = a * key + b。其中,a和b 是常数。")]),t._v(" "),a("h3",{attrs:{id:"数字分析法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#数字分析法"}},[t._v("#")]),t._v(" 数字分析法")]),t._v(" "),a("p",[t._v("假设关键字是R进制数(如十进制)。并且哈希表中"),a("strong",[t._v("可能出现的关键字都是事先知道的")]),t._v(",则可选取关键字的若干数位组成哈希地址。")]),t._v(" "),a("p",[t._v("选取的原则是使得到的哈希地址尽量避免冲突,即所选数位上的数字尽可能是随机的。")]),t._v(" "),a("h3",{attrs:{id:"平方取中法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#平方取中法"}},[t._v("#")]),t._v(" 平方取中法")]),t._v(" "),a("p",[t._v("取关键字平方后的中间几位为哈希地址。通常在选定哈希函数时不一定能知道关键字的全部情况,仅取其中的几位为地址不一定合适;")]),t._v(" "),a("p",[t._v("而一个数平方后的中间几位数和数的每一位都相关, 由此得到的哈希地址随机性更大。取的位数由表长决定。")]),t._v(" "),a("h3",{attrs:{id:"除留余数法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#除留余数法"}},[t._v("#")]),t._v(" 除留余数法")]),t._v(" "),a("p",[t._v("取关键字被某个"),a("strong",[t._v("不大于哈希表表长")]),t._v(" m 的数 p 除后所得的余数为哈希地址。")]),t._v(" "),a("p",[t._v("即 f(key) = key % p (p ≤ m)")]),t._v(" "),a("p",[t._v("这是一种"),a("strong",[t._v("最简单、最常用")]),t._v("的方法,它不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。")]),t._v(" "),a("p",[t._v("注意:p的选择很重要,如果选的不好,容易产生冲突。根据经验,"),a("strong",[t._v("一般情况下可以选p为素数")]),t._v("。")]),t._v(" "),a("h3",{attrs:{id:"随机数法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#随机数法"}},[t._v("#")]),t._v(" 随机数法")]),t._v(" "),a("p",[t._v("选择一个随机函数,取关键字的随机函数值为它的哈希地址,即 f(key) = random(key)。")]),t._v(" "),a("p",[t._v("通常,在关键字长度不等时采用此法构造哈希函数较为恰当。")]),t._v(" "),a("h2",{attrs:{id:"解决冲突"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#解决冲突"}},[t._v("#")]),t._v(" 解决冲突")]),t._v(" "),a("p",[t._v("设计合理的哈希函数可以减少冲突,但不能完全避免冲突。")]),t._v(" "),a("p",[t._v("所以需要有解决冲突的方法,常见有两类:")]),t._v(" "),a("h3",{attrs:{id:"开放定址法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#开放定址法"}},[t._v("#")]),t._v(" 开放定址法")]),t._v(" "),a("p",[t._v("如果两个数据元素的哈希值相同,则在哈希表中为后插入的数据元素另外选择一个表项。\n当程序查找哈希表时,如果没有在第一个对应的哈希表项中找到符合查找要求的数据元素,程序就会继续往后查找,直到找到一个符合查找要求的数据元素,或者遇到一个空的表项。")]),t._v(" "),a("p",[a("strong",[t._v("示例")])]),t._v(" "),a("p",[t._v("若要将一组关键字序列 {1, 9, 25, 11, 12, 35, 17, 29} 存放到哈希表中。")]),t._v(" "),a("p",[t._v("采用除留余数法构造哈希表;采用开放定址法处理冲突。")]),t._v(" "),a("p",[t._v("不妨设选取的p和m为13,由 f(key) = key % 13 可以得到下表。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://upload-images.jianshu.io/upload_images/3101171-06a789e7f9b31da6.png",alt:"img"}})]),t._v(" "),a("p",[t._v("需要注意的是,在上图中有两个关键字的探查次数为 2 ,其他都是1。")]),t._v(" "),a("p",[t._v("这个过程是这样的:")]),t._v(" "),a("p",[t._v("a. 12 % 13 结果是12,而它的前面有个 25 ,25 % 13 也是12,存在冲突。")]),t._v(" "),a("p",[t._v("我们使用开放定址法 (12 + 1) % 13 = 0,没有冲突,完成。")]),t._v(" "),a("p",[t._v("b. 35 % 13 结果是 9,而它的前面有个 9,9 % 13也是 9,存在冲突。")]),t._v(" "),a("p",[t._v("我们使用开放定址法 (9 + 1) % 13 = 10,没有冲突,完成。")]),t._v(" "),a("h3",{attrs:{id:"拉链法"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#拉链法"}},[t._v("#")]),t._v(" 拉链法")]),t._v(" "),a("p",[t._v("将哈希值相同的数据元素存放在一个链表中,在查找哈希表的过程中,当查找到这个链表时,必须采用线性查找方法。")]),t._v(" "),a("p",[t._v("在这种方法中,哈希表中每个单元存放的不再是记录本身,而是相应同义词单链表的头指针。")]),t._v(" "),a("p",[a("strong",[t._v("示例")])]),t._v(" "),a("p",[t._v("如果对开放定址法示例中提到的序列使用拉链法,得到的结果如下图所示:")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://upload-images.jianshu.io/upload_images/3101171-c14e03882e8a0f3a.png",alt:"img"}})]),t._v(" "),a("h2",{attrs:{id:"实现一个哈希表"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#实现一个哈希表"}},[t._v("#")]),t._v(" 实现一个哈希表")]),t._v(" "),a("p",[t._v("假设要实现一个哈希表,要求")]),t._v(" "),a("p",[t._v("a. 哈希函数采用"),a("strong",[t._v("除留余数法")]),t._v(",即 f(key) = key % p (p ≤ m)")]),t._v(" "),a("p",[t._v("b. 解决冲突采用"),a("strong",[t._v("开放定址法")]),t._v(",即 f"),a("sub",[t._v("2")]),t._v("(key) = (f(key)+i) % size (p ≤ m)")]),t._v(" "),a("p",[t._v("(1)定义哈希表的数据结构")]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashTable")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 关键字")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" data "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 数值")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" count "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 探查次数")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("(2)在哈希表中查找关键字key")]),t._v(" "),a("p",[t._v("根据设定的哈希函数,计算哈希地址。如果出现地址冲突,则按设定的处理冲突的方法寻找下一个地址。")]),t._v(" "),a("p",[t._v("如此反复,直到不冲突为止(查找成功)或某个地址为空(查找失败)。")]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 查找哈希表\n * 构造哈希表采用除留取余法,即f(key) = key mod p (p ≤ size)\n * 解决冲突采用开放定址法,即f2(key) = (f(key) + i) mod p (1 ≤ i ≤ size-1)\n * ha为哈希表,p为模,size为哈希表大小,key为要查找的关键字\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("searchHashTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" size"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("%")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 采用除留取余法找哈希地址")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 若发生冲突,用开放定址法找下一个哈希地址")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("NULLKEY")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("%")]),t._v(" size"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 查找成功")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FAILED")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 查找失败")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("(3)删除关键字为key的记录")]),t._v(" "),a("p",[t._v("在采用开放定址法处理冲突的哈希表上执行删除操作,只能在被删记录上做删除标记,而不能真正删除记录。")]),t._v(" "),a("p",[t._v("找到要删除的记录,将关键字置为删除标记DELKEY。")]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("deleteHashTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" size"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("searchHashTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" size"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("FAILED")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 找到记录")]),t._v("\n ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("DELKEY")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 将该位置的关键字置为DELKEY")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("SUCCESS")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("NULLKEY")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 查找不到记录,直接返回NULLKEY")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("(4)插入关键字为key的记录")]),t._v(" "),a("p",[t._v("将待插入的关键字key插入哈希表\n先调用查找算法,若在表中找到待插入的关键字,则插入失败;\n若在表中找到一个开放地址,则将待插入的结点插入到其中,则插入成功。")]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insertHashTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" size"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("%")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 通过哈希函数获取哈希地址")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("NULLKEY")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("DELKEY")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 如果没有冲突,直接插入")]),t._v("\n ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 如果有冲突,使用开放定址法处理冲突")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("%")]),t._v(" size"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 寻找下一个哈希地址")]),t._v("\n i"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("NULLKEY")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("DELKEY")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("(5)建立哈希表")]),t._v(" "),a("p",[t._v("先将哈希表中各关键字清空,使其地址为开放的,然后调用插入算法将给定的关键字序列依次插入。")]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("insertHashTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("HashTable")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" size"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("%")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 通过哈希函数获取哈希地址")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("NULLKEY")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("DELKEY")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 如果没有冲突,直接插入")]),t._v("\n ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 如果有冲突,使用开放定址法处理冲突")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("do")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("addr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("%")]),t._v(" size"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 寻找下一个哈希地址")]),t._v("\n i"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("NULLKEY")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("DELKEY")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" key"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n ha"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("addr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("h3",{attrs:{id:"完整示例"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#完整示例"}},[t._v("#")]),t._v(" 完整示例")]),t._v(" "),a("p",[a("a",{attrs:{href:"https://github.com/dunwu/algorithm/blob/master/codes/src/main/java/io/github/dunwu/algorithm/search/HashDemo.java",target:"_blank",rel:"noopener noreferrer"}},[t._v("示例代码"),a("OutboundLink")],1)]),t._v(" "),a("h2",{attrs:{id:"资源"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#资源"}},[t._v("#")]),t._v(" 资源")]),t._v(" "),a("p",[t._v("《数据结构习题与解析》(B级第3版)")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/26.1433f331.js b/assets/js/26.1433f331.js new file mode 100644 index 0000000..6ad3fe6 --- /dev/null +++ b/assets/js/26.1433f331.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{390:function(t,r,a){"use strict";a.r(r);var e=a(15),_=Object(e.a)({},(function(){var t=this,r=t._self._c;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h1",{attrs:{id:"算法思路"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#算法思路"}},[t._v("#")]),t._v(" 算法思路")]),t._v(" "),r("h2",{attrs:{id:"递归"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#递归"}},[t._v("#")]),t._v(" 递归")]),t._v(" "),r("h3",{attrs:{id:"使用递归的条件"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#使用递归的条件"}},[t._v("#")]),t._v(" 使用递归的条件")]),t._v(" "),r("p",[t._v("递归需要满足的三个条件")]),t._v(" "),r("ul",[r("li",[r("strong",[t._v("一个问题的解可以分解为几个子问题的解")])]),t._v(" "),r("li",[r("strong",[t._v("这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一样")])]),t._v(" "),r("li",[r("strong",[t._v("存在递归终止条件")])])]),t._v(" "),r("h3",{attrs:{id:"递归代码要警惕堆栈溢出"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#递归代码要警惕堆栈溢出"}},[t._v("#")]),t._v(" 递归代码要警惕堆栈溢出")]),t._v(" "),r("p",[t._v("函数调用会使用栈来保存临时变量。每调用一个函数,都会将临时变量封装为栈帧压入内存栈,等函数执行完成返回时,才出栈。系统栈或者虚拟机栈空间一般都不大。如果递归求解的数据规模很大,调用层次很深,一直压入栈,就会有堆栈溢出的风险。")]),t._v(" "),r("p",[t._v("那么,如何避免出现堆栈溢出呢?")]),t._v(" "),r("p",[t._v("我们可以通过在代码中限制递归调用的最大深度的方式来解决这个问题")]),t._v(" "),r("h2",{attrs:{id:"贪心算法"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#贪心算法"}},[t._v("#")]),t._v(" 贪心算法")]),t._v(" "),r("h3",{attrs:{id:"贪心算法思路"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#贪心算法思路"}},[t._v("#")]),t._v(" 贪心算法思路")]),t._v(" "),r("p",[t._v("贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择,就能得到问题的答案。贪心算法需要充分挖掘题目中条件,没有固定的模式,解决有贪心算法需要一定的直觉和经验。")]),t._v(" "),r("p",[t._v("贪心算法"),r("strong",[t._v("不是对所有问题都能得到整体最优解")]),t._v("。能使用贪心算法解决的问题具有「贪心选择性质」。「贪心选择性质」严格意义上需要数学证明。能使用贪心算法解决的问题必须具备「无后效性」,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。")]),t._v(" "),r("h3",{attrs:{id:"贪心算法的应用"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#贪心算法的应用"}},[t._v("#")]),t._v(" 贪心算法的应用")]),t._v(" "),r("p",[t._v("霍夫曼编码(Huffman Coding)")]),t._v(" "),r("p",[t._v("Prim 和 Kruskal 最小生成树算法")]),t._v(" "),r("p",[t._v("Dijkstra 单源最短路径算法")]),t._v(" "),r("h2",{attrs:{id:"分治算法"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#分治算法"}},[t._v("#")]),t._v(" 分治算法")]),t._v(" "),r("p",[t._v("分治算法的核心就是分而治之,也就是将原问题划分成 n 个规模较小,并且结构与原问题相似的子问题,分别解决这些子问题,然后再合并其结果,得到原问题的解。")]),t._v(" "),r("p",[r("strong",[t._v("分治算法是一种处理问题的思想,递归是一种编程技巧")]),t._v("。分治算法一般都比较适合用递归来实现。分治算法的递归实现中,每一层递归都会涉及这样三个操作:")]),t._v(" "),r("ul",[r("li",[t._v("分解:将原问题分解成一系列子问题;")]),t._v(" "),r("li",[t._v("解决:递归地求解各个子问题,若子问题足够小,则直接求解;")]),t._v(" "),r("li",[t._v("合并:将子问题的结果合并成原问题。")])]),t._v(" "),r("p",[t._v("分治算法能解决的问题,一般需要满足下面这几个条件:")]),t._v(" "),r("ul",[r("li",[t._v("原问题与分解成的小问题具有相同的模式;")]),t._v(" "),r("li",[t._v("原问题分解成的子问题可以独立求解,子问题之间没有相关性,这一点是分治算法跟动态规划的明显区别,等我们讲到动态规划的时候,会详细对比这两种算法;")]),t._v(" "),r("li",[t._v("具有分解终止条件,也就是说,当问题足够小时,可以直接求解;")]),t._v(" "),r("li",[t._v("可以将子问题合并成原问题,而这个合并操作的复杂度不能太高,否则就起不到减小算法总体复杂度的效果了。")])]),t._v(" "),r("h2",{attrs:{id:"回溯算法"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#回溯算法"}},[t._v("#")]),t._v(" 回溯算法")]),t._v(" "),r("h3",{attrs:{id:"回溯算法思路"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#回溯算法思路"}},[t._v("#")]),t._v(" 回溯算法思路")]),t._v(" "),r("p",[r("strong",[t._v("回溯法")]),t._v(" 采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:")]),t._v(" "),r("ul",[r("li",[r("p",[t._v("找到一个可能存在的正确的答案;")])]),t._v(" "),r("li",[r("p",[t._v("在尝试了所有可能的分步方法后宣告该问题没有答案。")])])]),t._v(" "),r("p",[r("strong",[t._v("解决一个回溯问题,实际上就是一个决策树的遍历过程")]),t._v("。")]),t._v(" "),r("ul",[r("li",[r("strong",[t._v("路径")]),t._v(":也就是已经做出的选择。")]),t._v(" "),r("li",[r("strong",[t._v("选择列表")]),t._v(":也就是你当前可以做的选择。")]),t._v(" "),r("li",[r("strong",[t._v("结束条件")]),t._v(":也就是到达决策树底层,无法再做选择的条件。")])]),t._v(" "),r("p",[t._v("回溯算法的骨架:")]),t._v(" "),r("div",{staticClass:"language-text extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[t._v("result = []\ndef backtrack(路径, 选择列表):\n if 满足结束条件:\n result.add(路径)\n return\n\n for 选择 in 选择列表:\n 做选择\n backtrack(路径, 选择列表)\n 撤销选择\n")])])]),r("p",[r("strong",[t._v("其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」")])]),t._v(" "),r("h3",{attrs:{id:"回溯算法应用"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#回溯算法应用"}},[t._v("#")]),t._v(" 回溯算法应用")]),t._v(" "),r("p",[t._v("回溯算法典型问题:")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/permutations/",target:"_blank",rel:"noopener noreferrer"}},[t._v("46. 全排列(中等)"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/permutations-ii/",target:"_blank",rel:"noopener noreferrer"}},[t._v("47. 全排列 II(中等)"),r("OutboundLink")],1)]),t._v(" "),r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/n-queens/",target:"_blank",rel:"noopener noreferrer"}},[t._v("N 皇后(困难)"),r("OutboundLink")],1)])]),t._v(" "),r("ol",{attrs:{start:"37"}},[r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/sudoku-solver/",target:"_blank",rel:"noopener noreferrer"}},[t._v("解数独(困难)"),r("OutboundLink")],1)])]),t._v(" "),r("blockquote",[r("p",[r("a",{attrs:{href:"https://zhuanlan.zhihu.com/p/93530380",target:"_blank",rel:"noopener noreferrer"}},[t._v("知乎:回溯算法套路详解 - labuladong的文章"),r("OutboundLink")],1)])]),t._v(" "),r("h2",{attrs:{id:"动态规划"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#动态规划"}},[t._v("#")]),t._v(" 动态规划")]),t._v(" "),r("h3",{attrs:{id:"动态规划思路"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#动态规划思路"}},[t._v("#")]),t._v(" 动态规划思路")]),t._v(" "),r("p",[t._v("动态规划比较适合用来求解最优问题,比如求最大值、最小值等等。")]),t._v(" "),r("p",[t._v("动态规划的应用")]),t._v(" "),r("p",[t._v("买卖股票的最佳时机")]),t._v(" "),r("h2",{attrs:{id:"参考资料"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法之美"),r("OutboundLink")],1)]),t._v(" "),r("li",[t._v("回溯")]),t._v(" "),r("li",[r("a",{attrs:{href:"https://zhuanlan.zhihu.com/p/93530380",target:"_blank",rel:"noopener noreferrer"}},[t._v("知乎:回溯算法套路详解 - labuladong的文章"),r("OutboundLink")],1)])])])}),[],!1,null,null,null);r.default=_.exports}}]); \ No newline at end of file diff --git a/assets/js/27.a827f6fa.js b/assets/js/27.a827f6fa.js new file mode 100644 index 0000000..1201965 --- /dev/null +++ b/assets/js/27.a827f6fa.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{391:function(e,r,t){"use strict";t.r(r);var a=t(15),n=Object(a.a)({},(function(){var e=this,r=e._self._c;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h1",{attrs:{id:"数据结构-树"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#数据结构-树"}},[e._v("#")]),e._v(" 数据结构 - 树")]),e._v(" "),r("h2",{attrs:{id:"二叉树经典题"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉树经典题"}},[e._v("#")]),e._v(" 二叉树经典题")]),e._v(" "),r("h3",{attrs:{id:"深度优先搜索-dfs"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#深度优先搜索-dfs"}},[e._v("#")]),e._v(" 深度优先搜索(DFS)")]),e._v(" "),r("p",[e._v("在这个策略中,我们采用 深度 作为优先级,以便从跟开始一直到达某个确定的叶子,然后再返回到达另一个分支。深度优先搜索策略又可以根据根节点、左孩子和右孩子的相对顺序被细分为"),r("strong",[e._v("先序遍历")]),e._v(","),r("strong",[e._v("中序遍历")]),e._v("和"),r("strong",[e._v("后序遍历")]),e._v("。")]),e._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/binary-tree-preorder-traversal",target:"_blank",rel:"noopener noreferrer"}},[e._v("二叉树的前序遍历"),r("OutboundLink")],1)]),e._v(" "),r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/binary-tree-inorder-traversal",target:"_blank",rel:"noopener noreferrer"}},[e._v("二叉树的中序遍历"),r("OutboundLink")],1)]),e._v(" "),r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/binary-tree-postorder-traversal",target:"_blank",rel:"noopener noreferrer"}},[e._v("二叉树的后序遍历"),r("OutboundLink")],1)])]),e._v(" "),r("h3",{attrs:{id:"宽度优先搜索-bfs"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#宽度优先搜索-bfs"}},[e._v("#")]),e._v(" 宽度优先搜索(BFS)")]),e._v(" "),r("p",[e._v("我们按照高度顺序一层一层的访问整棵树,高层次的节点将会比低层次的节点先被访问到。")]),e._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/binary-tree-level-order-traversal",target:"_blank",rel:"noopener noreferrer"}},[e._v("二叉树的层序遍历"),r("OutboundLink")],1)])]),e._v(" "),r("h3",{attrs:{id:"二叉树和递归"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉树和递归"}},[e._v("#")]),e._v(" 二叉树和递归")]),e._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/maximum-depth-of-binary-tree",target:"_blank",rel:"noopener noreferrer"}},[e._v("二叉树的最大深度"),r("OutboundLink")],1)]),e._v(" "),r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/symmetric-tree",target:"_blank",rel:"noopener noreferrer"}},[e._v("对称二叉树"),r("OutboundLink")],1)]),e._v(" "),r("li",[r("a",{attrs:{href:"https://leetcode-cn.com/problems/path-sum",target:"_blank",rel:"noopener noreferrer"}},[e._v("路径总和"),r("OutboundLink")],1)])]),e._v(" "),r("h3",{attrs:{id:"其他"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#其他"}},[e._v("#")]),e._v(" 其他")]),e._v(" "),r("ul",[r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/",target:"_blank",rel:"noopener noreferrer"}},[e._v("maximum-depth-of-binary-tree"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/balanced-binary-tree/",target:"_blank",rel:"noopener noreferrer"}},[e._v("balanced-binary-tree"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/",target:"_blank",rel:"noopener noreferrer"}},[e._v("binary-tree-maximum-path-sum"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/",target:"_blank",rel:"noopener noreferrer"}},[e._v("lowest-common-ancestor-of-a-binary-tree"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/binary-tree-level-order-traversal/",target:"_blank",rel:"noopener noreferrer"}},[e._v("binary-tree-level-order-traversal"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/",target:"_blank",rel:"noopener noreferrer"}},[e._v("binary-tree-level-order-traversal-ii"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/",target:"_blank",rel:"noopener noreferrer"}},[e._v("binary-tree-zigzag-level-order-traversal"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/validate-binary-search-tree/",target:"_blank",rel:"noopener noreferrer"}},[e._v("validate-binary-search-tree"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/",target:"_blank",rel:"noopener noreferrer"}},[e._v("insert-into-a-binary-search-tree"),r("OutboundLink")],1)])]),e._v(" "),r("h2",{attrs:{id:"二叉搜索树经典题"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#二叉搜索树经典题"}},[e._v("#")]),e._v(" 二叉搜索树经典题")]),e._v(" "),r("ul",[r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/validate-binary-search-tree/",target:"_blank",rel:"noopener noreferrer"}},[e._v("validate-binary-search-tree"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/",target:"_blank",rel:"noopener noreferrer"}},[e._v("insert-into-a-binary-search-tree"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/delete-node-in-a-bst/",target:"_blank",rel:"noopener noreferrer"}},[e._v("delete-node-in-a-bst"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("[ ] "),r("a",{attrs:{href:"https://leetcode-cn.com/problems/balanced-binary-tree/",target:"_blank",rel:"noopener noreferrer"}},[e._v("balanced-binary-tree"),r("OutboundLink")],1)])])])}),[],!1,null,null,null);r.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/3.4fe76a9d.js b/assets/js/3.4fe76a9d.js new file mode 100644 index 0000000..0c3ae6a --- /dev/null +++ b/assets/js/3.4fe76a9d.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{322:function(t,e,n){},366:function(t,e,n){"use strict";n(322)},392:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:(t,{props:e,slots:n})=>t("span",{class:["badge",e.type],style:{verticalAlign:e.vertical}},e.text||n().default)},a=(n(366),n(15)),p=Object(a.a)(i,void 0,void 0,!1,null,"d5affa18",null);e.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/4.bb51c7f4.js b/assets/js/4.bb51c7f4.js new file mode 100644 index 0000000..505d06f --- /dev/null +++ b/assets/js/4.bb51c7f4.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{288:function(t,s,n){},325:function(t,s,n){"use strict";n(288)},368:function(t,s,n){"use strict";n.r(s);const i=["这里什么都没有。","我是谁?我在哪?","这是一个Four-Oh-Four.","看来我们的链接坏掉了~"];var o={methods:{getMsg:()=>i[Math.floor(Math.random()*i.length)]}},e=(n(325),n(15)),a=Object(e.a)(o,(function(){var t=this._self._c;return t("div",{staticClass:"theme-container"},[t("div",{staticClass:"theme-vdoing-content"},[t("span",[this._v("404")]),this._v(" "),t("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),t("router-link",{attrs:{to:"/"}},[this._v("返回首页")])],1)])}),[],!1,null,"439bb2a8",null);s.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/5.a848069e.js b/assets/js/5.a848069e.js new file mode 100644 index 0000000..cbb95ab --- /dev/null +++ b/assets/js/5.a848069e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{370:function(t,_,v){"use strict";v.r(_);var s=v(15),a=Object(s.a)({},(function(){var t=this,_=t._self._c;return _("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[_("h1",{attrs:{id:"数据结构和算法指南"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#数据结构和算法指南"}},[t._v("#")]),t._v(" 数据结构和算法指南")]),t._v(" "),_("h2",{attrs:{id:"_1-为什么学习数据结构和算法"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#_1-为什么学习数据结构和算法"}},[t._v("#")]),t._v(" 1. 为什么学习数据结构和算法")]),t._v(" "),_("ul",[_("li",[_("strong",[t._v("为了找到一份好工作")]),t._v(":大厂面试喜欢考算法")]),t._v(" "),_("li",[_("strong",[t._v("更深入了解流行技术的设计思想")]),t._v(":数据结构和算法是计算机基础学科,很多框架、中间、底层系统设的设计,都借鉴了其思想。因此,掌握数据结构和算法,有利于更深入了解这些技术的设计思想。")]),t._v(" "),_("li",[t._v("提升个人的编程水平")]),t._v(" "),_("li",[t._v("不满足于做业务狗,拓展性能思考的视角")])]),t._v(" "),_("h2",{attrs:{id:"_2-如何学习数据结构和算法"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#_2-如何学习数据结构和算法"}},[t._v("#")]),t._v(" 2. 如何学习数据结构和算法")]),t._v(" "),_("p",[t._v("数据结构就是指一组数据的存储结构。算法就是操作数据的一组方法。")]),t._v(" "),_("p",[t._v("数据结构和算法是相辅相成的。"),_("strong",[t._v("数据结构是为算法服务的,算法要作用在特定的数据结构之上。")])]),t._v(" "),_("p",[t._v("先要学会复杂度分析,才能识别数据结构和算法的利弊。")]),t._v(" "),_("ul",[_("li",[t._v("循序渐进")]),t._v(" "),_("li",[t._v("边学边练,适度刷题")]),t._v(" "),_("li",[t._v("学习并思考:学而不思则罔,思而不学则殆")]),t._v(" "),_("li",[t._v("知识需要沉淀,不要想试图一下子掌握所有")])])])}),[],!1,null,null,null);_.default=a.exports}}]); \ No newline at end of file diff --git a/assets/js/6.24c3df5c.js b/assets/js/6.24c3df5c.js new file mode 100644 index 0000000..3e0d0bd --- /dev/null +++ b/assets/js/6.24c3df5c.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{373:function(t,s,a){"use strict";a.r(s);var n=a(15),r=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"复杂度分析"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#复杂度分析"}},[t._v("#")]),t._v(" 复杂度分析")]),t._v(" "),s("h2",{attrs:{id:"为什么需要复杂度分析"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#为什么需要复杂度分析"}},[t._v("#")]),t._v(" 为什么需要复杂度分析")]),t._v(" "),s("p",[t._v("衡量算法的优劣,有两种评估方式:事前估计和后期测试。")]),t._v(" "),s("p",[t._v("后期测试有性能测试、基准测试(Benchmark)等手段。")]),t._v(" "),s("p",[t._v("但是,后期测试有以下限制:")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("测试结果非常依赖测试环境")]),t._v("。如:不同机型、不同编译器版本、不同硬件配置等等,都会影响测试结果。")]),t._v(" "),s("li",[s("strong",[t._v("测试结果受数据规模的影响很大")]),t._v("。")])]),t._v(" "),s("p",[t._v("所以,需要一种方法,可以不受环境或数据规模的影响,粗略地估计算法的执行效率。这种方法就是复杂度分析。")]),t._v(" "),s("h2",{attrs:{id:"时间复杂度分析"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度分析"}},[t._v("#")]),t._v(" 时间复杂度分析")]),t._v(" "),s("h3",{attrs:{id:"大-o-表示法"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#大-o-表示法"}},[t._v("#")]),t._v(" 大 O 表示法")]),t._v(" "),s("p",[t._v("假设问题的规模为 n,则程序的时间复杂度表示为 "),s("code",[t._v("T(n)")]),t._v("。"),s("strong",[t._v("代码的执行时间 T(n) 与每行代码的执行次数 n 成正比")]),t._v("。")]),t._v(" "),s("p",[t._v("当 n 增大时,T(n) 也随之增大,想要准确估计其变化比较困难。所以,可以采用大 O 时间复杂度来粗略估计其复杂度,其表达式为:"),s("strong",[s("code",[t._v("T(n) = O(f(n))")])]),t._v("。")]),t._v(" "),s("p",[s("strong",[t._v("大 O 表示法")]),t._v("实际上并不具体表示代码真正的执行时间,而是表示"),s("strong",[t._v("代码执行时间随数据规模增长的变化趋势")]),t._v(",所以,也叫作"),s("strong",[t._v("渐进时间复杂度")]),t._v("(asymptotic time complexity),简称"),s("strong",[t._v("时间复杂度")]),t._v("。")]),t._v(" "),s("h3",{attrs:{id:"时间复杂度分析的要点"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度分析的要点"}},[t._v("#")]),t._v(" 时间复杂度分析的要点")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("只关注循环执行次数最多的一段代码")])]),t._v(" "),s("li",[s("strong",[t._v("加法法则:总复杂度等于量级最大的那段代码的复杂度")])]),t._v(" "),s("li",[s("strong",[t._v("乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积")])])]),t._v(" "),s("h3",{attrs:{id:"最好、最坏和平均情况"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#最好、最坏和平均情况"}},[t._v("#")]),t._v(" 最好、最坏和平均情况")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("最好情况时间复杂度")]),t._v("(best case time complexity):"),s("strong",[t._v("在最理想的情况下,执行代码的时间复杂度")]),t._v("。例如:在最理想的情况下,要查找的变量 x 正好是数组的第一个元素,此时最好情况时间复杂度为 1。")]),t._v(" "),s("li",[s("strong",[t._v("最坏情况时间复杂度")]),t._v("(worst case time complexity):"),s("strong",[t._v("在最糟糕的情况下,执行代码的时间复杂度")]),t._v("。例如:在最理想的情况下,要查找的变量 x 正好是数组的最后个元素,此时最好情况时间复杂度为 n。")]),t._v(" "),s("li",[s("strong",[t._v("平均情况时间复杂度")]),t._v("(average case time complexity):平均时间复杂度的全称应该叫"),s("strong",[t._v("加权平均时间复杂度")]),t._v("或者"),s("strong",[t._v("期望时间复杂度")]),t._v("。")])]),t._v(" "),s("h3",{attrs:{id:"时间复杂度分析示例"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#时间复杂度分析示例"}},[t._v("#")]),t._v(" 时间复杂度分析示例")]),t._v(" "),s("p",[t._v("【示例】从 1 累加到 100 的时间复杂度是多少?")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" sum "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("N")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("100")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("N")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n sum "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" sum "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("时间复杂度计算:显然,这段代码执行了 100 次加法,其时间复杂度和 N 的大小完全一致")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("T(n) = O(n)\n")])])]),s("p",[t._v("【示例】嵌套循环的时间复杂度是多少?")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("M")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("N")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("M")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("N")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"i = "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('", j = "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("时间复杂度计算:")]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("T(n) = (M-1)(N-1) = O(M*N) ≈ O(N^2)\n")])])]),s("p",[t._v("【示例】递归函数的时间复杂度是多少?思考一下斐波那契数列 "),s("code",[t._v("f(n) = f(n-1) + f(n-2)")]),t._v(" 的时间复杂度是多少?")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320110642.png",alt:"img"}})]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("T(n) = O(2^N)\n")])])]),s("h2",{attrs:{id:"空间复杂度分析"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#空间复杂度分析"}},[t._v("#")]),t._v(" 空间复杂度分析")]),t._v(" "),s("p",[t._v("时间复杂度的全称是"),s("strong",[t._v("渐进时间复杂度")]),t._v(","),s("strong",[t._v("表示算法的执行时间与数据规模之间的增长关系")]),t._v("。")]),t._v(" "),s("p",[t._v("类比一下,空间复杂度全称就是"),s("strong",[t._v("渐进空间复杂度")]),t._v("(asymptotic space complexity),"),s("strong",[t._v("表示算法的存储空间与数据规模之间的增长关系")]),t._v("。")]),t._v(" "),s("h2",{attrs:{id:"复杂度量级"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#复杂度量级"}},[t._v("#")]),t._v(" 复杂度量级")]),t._v(" "),s("p",[t._v("复杂度有以下量级:")]),t._v(" "),s("ul",[s("li",[s("strong",[s("code",[t._v("O(1)")])]),t._v(":常数复杂度")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("O(log n)")])]),t._v(":对数复杂度")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("O(n)")])]),t._v(":线性复杂度")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("O(nlog n)")])]),t._v(":线性对数阶复杂度")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("O(n^2)")])]),t._v(":平方复杂度")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("O(n^3)")])]),t._v(":立方复杂度")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("O(n^k)")])]),t._v(":K 次方复杂度")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("O(2^n)")])]),t._v(":指数复杂度")]),t._v(" "),s("li",[s("strong",[s("code",[t._v("O(n!)")])]),t._v(":阶乘复杂度")])]),t._v(" "),s("p",[t._v("在数据量比较小的时候,复杂度量级差异并不明显;但是,随着数据规模大小的变化,差异会逐渐突出。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320160627.png",alt:"img"}})]),t._v(" "),s("p",[s("code",[t._v("O(1)")]),t._v(" 复杂度示例:")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" num "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("100")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"num = "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" num"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),s("p",[s("code",[t._v("O(log n)")]),t._v(" 对数复杂度示例:")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" max "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("100")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" max"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"i = "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[s("code",[t._v("O(n)")]),t._v(" 复杂度示例:")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" max "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("100")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" max"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"i = "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[s("code",[t._v("O(n^2)")]),t._v(" 复杂度示例:")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("M")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("N")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("20")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("M")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("N")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"i = "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('", j = "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[s("code",[t._v("O(k^n)")]),t._v(" 复杂度示例:")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" max "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Math")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("pow")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" max"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"i = "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h2",{attrs:{id:"常见数据结构的复杂度"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#常见数据结构的复杂度"}},[t._v("#")]),t._v(" 常见数据结构的复杂度")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20200702071922.png",alt:"img"}})]),t._v(" "),s("h2",{attrs:{id:"参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法之美"),s("OutboundLink")],1)])])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/7.6f0d505e.js b/assets/js/7.6f0d505e.js new file mode 100644 index 0000000..1b28310 --- /dev/null +++ b/assets/js/7.6f0d505e.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{369:function(t,s,a){"use strict";a.r(s);var n=a(15),e=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"数组和链表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数组和链表"}},[t._v("#")]),t._v(" 数组和链表")]),t._v(" "),s("blockquote",[s("p",[t._v("数组和链表分别代表了连续空间和不连续空间的存储方式,它们是线性表(Linear List)的典型代表。其他所有的数据结构,比如栈、队列、二叉树、B+ 树等,实际上都是这两者的结合和变化。")])]),t._v(" "),s("h2",{attrs:{id:"数组"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数组"}},[t._v("#")]),t._v(" 数组")]),t._v(" "),s("p",[t._v("数组用 "),s("strong",[t._v("连续")]),t._v(" 的内存空间来存储数据。")]),t._v(" "),s("h3",{attrs:{id:"数组的访问"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数组的访问"}},[t._v("#")]),t._v(" 数组的访问")]),t._v(" "),s("p",[t._v("数组元素的访问是以行或列索引的单一下标表示。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320115836.png",alt:"img"}})]),t._v(" "),s("p",[t._v("在上面的例子中,数组 a 中有 5 个元素。"),s("code",[t._v("也就是说")]),t._v(",a 的长度是 6 。我们可以使用 a[0] 来表示数组中的第一个元素。因此,a[0] = A 。类似地,a[1] = B,a[2] = C,依此类推。")]),t._v(" "),s("h3",{attrs:{id:"数组的插入"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数组的插入"}},[t._v("#")]),t._v(" 数组的插入")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320115848.png",alt:"img"}})]),t._v(" "),s("h3",{attrs:{id:"数组的删除"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数组的删除"}},[t._v("#")]),t._v(" 数组的删除")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320115859.png",alt:"img"}})]),t._v(" "),s("h3",{attrs:{id:"数组的特性"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数组的特性"}},[t._v("#")]),t._v(" 数组的特性")]),t._v(" "),s("p",[t._v("数组设计之初是在形式上依赖内存分配而成的,所以必须在使用前预先分配好空间大小。这使得数组有以下特性:")]),t._v(" "),s("ol",[s("li",[s("strong",[t._v("用连续的内存空间来存储数据")]),t._v("。")]),t._v(" "),s("li",[s("strong",[t._v("数组支持随机访问,根据下标随机访问的时间复杂度为 "),s("code",[t._v("O(1)")])]),t._v("。")]),t._v(" "),s("li",[s("strong",[t._v("数组的插入、删除操作,平均时间复杂度为 "),s("code",[t._v("O(n)")])]),t._v("。")]),t._v(" "),s("li",[s("strong",[t._v("空间大小固定")]),t._v(",一旦建立,不能再改变。扩容只能采用复制数组的方式。")]),t._v(" "),s("li",[t._v("在旧式编程语言中(如有中阶语言之称的 C),程序不会对数组的操作做下界判断,也就有潜在的越界操作的风险。")])]),t._v(" "),s("h3",{attrs:{id:"多维数组"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#多维数组"}},[t._v("#")]),t._v(" 多维数组")]),t._v(" "),s("p",[t._v("数组是有下标和值组成集合。")]),t._v(" "),s("p",[t._v("如果数组的下标有多个维度,即为多维数组。比如:二维数组可以视为『数组元素为一维数组』的一维数组;三维数组可以视为『数组元素为二维数组』的一维数组;依次类推。")]),t._v(" "),s("p",[t._v("下图是由 M 个行向量,N 个列向量组成的二维数组.")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320152607.png",alt:"img"}})]),t._v(" "),s("h2",{attrs:{id:"链表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#链表"}},[t._v("#")]),t._v(" 链表")]),t._v(" "),s("blockquote",[s("p",[s("strong",[t._v("链表用不连续的内存空间来存储数据;并通过一个指针按顺序将这些空间串起来,形成一条链")]),t._v("。")])]),t._v(" "),s("p",[t._v("区别于数组,链表中的元素不是存储在内存中连续的一片区域,链表中的数据存储在每一个称之为「结点」复合区域里,在每一个结点除了存储数据以外,还保存了到下一个节点的指针(Pointer)。由于不必按顺序存储,链表在插入数据的时候可以达到 "),s("code",[t._v("O(1)")]),t._v(" 的复杂度,但是查找一个节点或者访问特定编号的节点则需要 "),s("code",[t._v("O(n)")]),t._v(" 的时间。")]),t._v(" "),s("p",[t._v("链表具有以下特性:")]),t._v(" "),s("ul",[s("li",[t._v("链表允许插入和移除任意位置上的节点,其时间复杂度为 "),s("code",[t._v("O(1)")])]),t._v(" "),s("li",[t._v("链表没有数组的随机访问特性,"),s("strong",[t._v("链表只支持顺序访问")]),t._v(",其时间复杂度为 "),s("code",[t._v("O(n)")]),t._v("。")]),t._v(" "),s("li",[t._v("数组的空间大小是固定的,而"),s("strong",[t._v("链表的空间大小可以动态增长")]),t._v("。相比于数组,链表支持扩容,显然更为灵活,但是由于多了指针域,空间开销也更大。")]),t._v(" "),s("li",[t._v("链表相比于数组,多了头指针、尾指针(非必要),合理使用可以大大提高访问效率。")])]),t._v(" "),s("p",[t._v("链表有多种类型:")]),t._v(" "),s("ul",[s("li",[t._v("单链表")]),t._v(" "),s("li",[t._v("双链表")]),t._v(" "),s("li",[t._v("循环链表")])]),t._v(" "),s("h3",{attrs:{id:"单链表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#单链表"}},[t._v("#")]),t._v(" 单链表")]),t._v(" "),s("p",[t._v("单链表中的每个结点不仅包含数据值,还包含一个指针,指向其后继节点。通过这种方式,单链表将所有结点按顺序组织起来。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174829.png",alt:"img"}})]),t._v(" "),s("p",[t._v("与数组不同,我们无法在常量时间内访问单链表中的随机元素。 如果我们想要获得第 i 个元素,我们必须从头结点逐个遍历。 我们按 "),s("code",[t._v("索引")]),t._v(" 来 "),s("code",[t._v("访问元素")]),t._v(" 平均要花费 "),s("code",[t._v("O(N)")]),t._v(" 时间,其中 N 是链表的长度。")]),t._v(" "),s("h4",{attrs:{id:"单链表插入"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#单链表插入"}},[t._v("#")]),t._v(" 单链表插入")]),t._v(" "),s("p",[t._v("如果我们想在给定的结点 "),s("code",[t._v("prev")]),t._v(" 之后添加新值,我们应该:")]),t._v(" "),s("p",[t._v("(1)使用给定值初始化新结点 "),s("code",[t._v("cur")]),t._v(";")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174908.png",alt:"img"}})]),t._v(" "),s("p",[t._v("(2)将 "),s("code",[t._v("cur")]),t._v(" 的 "),s("code",[t._v("next")]),t._v(" 字段链接到 "),s("code",[t._v("prev")]),t._v(" 的下一个结点 "),s("code",[t._v("next")]),t._v(" ;")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174919.png",alt:"img"}})]),t._v(" "),s("p",[t._v("(3)将 "),s("code",[t._v("prev")]),t._v(" 中的 "),s("code",[t._v("next")]),t._v(" 字段链接到 "),s("code",[t._v("cur")]),t._v(" 。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174932.png",alt:"img"}})]),t._v(" "),s("p",[t._v("与数组不同,我们不需要将所有元素移动到插入元素之后。因此,您可以在 "),s("code",[t._v("O(1)")]),t._v(" 时间复杂度中将新结点插入到链表中,这非常高效。")]),t._v(" "),s("h4",{attrs:{id:"单链表删除"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#单链表删除"}},[t._v("#")]),t._v(" 单链表删除")]),t._v(" "),s("p",[t._v("如果我们想从单链表中删除现有结点 "),s("code",[t._v("cur")]),t._v(",可以分两步完成:")]),t._v(" "),s("p",[t._v("(1)找到 "),s("code",[t._v("cur")]),t._v(" 的上一个结点 "),s("code",[t._v("prev")]),t._v(" 及其下一个结点 "),s("code",[t._v("next")]),t._v(" ;")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174953.png",alt:"img"}})]),t._v(" "),s("p",[t._v("(2)接下来链接 "),s("code",[t._v("prev")]),t._v(" 到 "),s("code",[t._v("cur")]),t._v(" 的下一个节点 "),s("code",[t._v("next")]),t._v(" 。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320175006.png",alt:"img"}})]),t._v(" "),s("p",[t._v("在我们的第一步中,我们需要找出 "),s("code",[t._v("prev")]),t._v(" 和 "),s("code",[t._v("next")]),t._v("。使用 "),s("code",[t._v("cur")]),t._v(" 的参考字段很容易找出 "),s("code",[t._v("next")]),t._v(",但是,我们必须从头结点遍历链表,以找出 "),s("code",[t._v("prev")]),t._v(",它的平均时间是 "),s("code",[t._v("O(N)")]),t._v(",其中 "),s("code",[t._v("N")]),t._v(" 是链表的长度。因此,删除结点的时间复杂度将是 "),s("code",[t._v("O(N)")]),t._v("。")]),t._v(" "),s("p",[t._v("空间复杂度为 "),s("code",[t._v("O(1)")]),t._v(",因为我们只需要常量空间来存储指针。")]),t._v(" "),s("h3",{attrs:{id:"双链表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#双链表"}},[t._v("#")]),t._v(" 双链表")]),t._v(" "),s("p",[t._v("双链表中的每个结点不仅包含数据值,还包含两个指针,分别指向指向其前驱节点和后继节点。")]),t._v(" "),s("p",[t._v("单链表的访问是单向的,而双链表的访问是双向的。显然,双链表比单链表操作更灵活,但是空间开销也更大。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181150.png",alt:"img"}})]),t._v(" "),s("p",[t._v("双链表以类似的方式工作,但"),s("code",[t._v("还有一个引用字段")]),t._v(",称为"),s("code",[t._v("“prev”")]),t._v("字段。有了这个额外的字段,您就能够知道当前结点的前一个结点。")]),t._v(" "),s("h4",{attrs:{id:"双链表插入"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#双链表插入"}},[t._v("#")]),t._v(" 双链表插入")]),t._v(" "),s("p",[t._v("如果我们想在给定的结点 "),s("code",[t._v("prev")]),t._v(" 之后添加新值,我们应该:")]),t._v(" "),s("p",[t._v("(1)使用给定值初始化新结点 "),s("code",[t._v("cur")]),t._v(";")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181208.png",alt:"img"}})]),t._v(" "),s("p",[t._v("(2)链接 "),s("code",[t._v("cur")]),t._v(" 与 "),s("code",[t._v("prev")]),t._v(" 和 "),s("code",[t._v("next")]),t._v(",其中 "),s("code",[t._v("next")]),t._v(" 是 "),s("code",[t._v("prev")]),t._v(" 原始的下一个节点;")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181303.png",alt:"img"}})]),t._v(" "),s("p",[t._v("(3)用 "),s("code",[t._v("cur")]),t._v(" 重新链接 "),s("code",[t._v("prev")]),t._v(" 和 "),s("code",[t._v("next")]),t._v("。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181504.png",alt:"img"}})]),t._v(" "),s("p",[t._v("与单链表类似,添加操作的时间和空间复杂度都是 "),s("code",[t._v("O(1)")]),t._v("。")]),t._v(" "),s("h4",{attrs:{id:"双链表删除"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#双链表删除"}},[t._v("#")]),t._v(" 双链表删除")]),t._v(" "),s("p",[t._v("如果我们想从双链表中删除一个现有的结点 "),s("code",[t._v("cur")]),t._v(",我们可以简单地将它的前一个结点 "),s("code",[t._v("prev")]),t._v(" 与下一个结点 "),s("code",[t._v("next")]),t._v(" 链接起来。")]),t._v(" "),s("p",[t._v("与单链表不同,使用 "),s("code",[t._v("prev")]),t._v(" 字段可以很容易地在常量时间内获得前一个结点。")]),t._v(" "),s("p",[t._v("因为我们不再需要遍历链表来获取前一个结点,所以时间和空间复杂度都是 "),s("code",[t._v("O(1)")]),t._v("。")]),t._v(" "),s("h3",{attrs:{id:"循环链表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#循环链表"}},[t._v("#")]),t._v(" 循环链表")]),t._v(" "),s("h4",{attrs:{id:"循环单链表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#循环单链表"}},[t._v("#")]),t._v(" 循环单链表")]),t._v(" "),s("p",[s("strong",[t._v("循环单链表是一种特殊的单链表")]),t._v("。它和单链表唯一的区别就在最后结点。")]),t._v(" "),s("ul",[s("li",[t._v("单链表的最后一个结点的后继指针 "),s("code",[t._v("next")]),t._v(" 指向空地址。")]),t._v(" "),s("li",[t._v("循环链表的最后一个结点的后继指针 "),s("code",[t._v("next")]),t._v(" 指向第一个节点(如果有头节点,就指向头节点)。")])]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220322190534.png",alt:"img"}})]),t._v(" "),s("h4",{attrs:{id:"循环双链表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#循环双链表"}},[t._v("#")]),t._v(" 循环双链表")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220322190423.png",alt:"img"}})]),t._v(" "),s("h2",{attrs:{id:"数组-vs-链表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数组-vs-链表"}},[t._v("#")]),t._v(" 数组 vs. 链表")]),t._v(" "),s("ul",[s("li",[s("strong",[t._v("存储方式")]),t._v(" "),s("ul",[s("li",[t._v("数组用 "),s("strong",[t._v("连续")]),t._v(" 的内存空间来存储数据。")]),t._v(" "),s("li",[t._v("链表用 "),s("strong",[t._v("不连续")]),t._v(" 的内存空间来存储数据;并通过一个指针按顺序将这些空间串起来,形成一条链。")])])]),t._v(" "),s("li",[s("strong",[t._v("访问方式")]),t._v(" "),s("ul",[s("li",[t._v("数组"),s("strong",[t._v("支持随机访问")]),t._v("。根据下标随机访问的时间复杂度为 "),s("code",[t._v("O(1)")])]),t._v(" "),s("li",[t._v("链表"),s("strong",[t._v("不支持随机访问")]),t._v(",只能顺序访问,时间复杂度为 "),s("code",[t._v("O(n)")]),t._v("。")])])]),t._v(" "),s("li",[s("strong",[t._v("空间大小")]),t._v(" "),s("ul",[s("li",[t._v("数组空间"),s("strong",[t._v("大小固定")]),t._v(",扩容只能采用复制数组的方式。")]),t._v(" "),s("li",[t._v("链表空间"),s("strong",[t._v("大小不固定")]),t._v(",扩容灵活。")])])]),t._v(" "),s("li",[s("strong",[t._v("效率比较")]),t._v(" "),s("ul",[s("li",[t._v("数组的 "),s("strong",[t._v("查找")]),t._v(" 效率高于链表。")]),t._v(" "),s("li",[t._v("链表的 "),s("strong",[t._v("添加")]),t._v("、"),s("strong",[t._v("删除")]),t._v(" 效率高于数组。")])])])]),t._v(" "),s("h2",{attrs:{id:"数组和链表的基本操作示例"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数组和链表的基本操作示例"}},[t._v("#")]),t._v(" 数组和链表的基本操作示例")]),t._v(" "),s("p",[t._v("关于数组和链表的基本操作,网上和各种书籍、教程中已经有大量的示例,感兴趣可以自行搜索。本文只是简单展示一下数组和链表的基本操作。")]),t._v(" "),s("h3",{attrs:{id:"一维数组的基本操作"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#一维数组的基本操作"}},[t._v("#")]),t._v(" 一维数组的基本操作")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Main")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 1. Initialize")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" a0 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" a1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 2. Get Length")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"The size of a1 is: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" a1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 3. Access Element")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"The first element is: "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" a1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 4. Iterate all Elements")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"[Version 1] The contents of a1 are:"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" a1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" a1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"[Version 2] The contents of a1 are:"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" item"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" a1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" "')]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" item"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 5. Modify Element")]),t._v("\n a1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("4")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 6. Sort")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Arrays")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("sort")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"二维数组的基本操作"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#二维数组的基本操作"}},[t._v("#")]),t._v(" 二维数组的基本操作")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TwoDimensionArray")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" a"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" a"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" a"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" a"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" a"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" "')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Example I:"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" a "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("a"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Example II:"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" b "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("b"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Example III:"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n b"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n b"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printArray")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("b"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"单链表的基本操作"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#单链表的基本操作"}},[t._v("#")]),t._v(" 单链表的基本操作")]),t._v(" "),s("p",[t._v("单链表节点的数据结构")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 指向后继节点")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("SingleLinkList")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 头节点")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("(1)从头部添加节点(即头插法)")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("addHead")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" newNode "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("(2)从尾部添加节点(即尾插法)")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("addTail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// init new node")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" newNode "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// find the last node")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// add new node to tail")]),t._v("\n node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("(3)删除节点")]),t._v(" "),s("p",[t._v("找到要删除元素的前驱节点,将前驱节点的 next 指针指向下一个节点。")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("remove")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" curr "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("curr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("equals")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" curr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("break")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("(4)查找节点")]),t._v(" "),s("p",[t._v("从头开始查找,一旦发现有数值与查找值相等的节点,直接返回此节点。如果遍历结束,表明未找到节点,返回 null。")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("equals")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h3",{attrs:{id:"双链表的基本操作"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#双链表的基本操作"}},[t._v("#")]),t._v(" 双链表的基本操作")]),t._v(" "),s("p",[t._v("双链表节点的数据结构:")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 指向前驱节点")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 指向后继节点")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DoubleLinkList")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/** 头节点 */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/** 尾节点 */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" tail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("(1)从头部添加节点")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("addHead")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" newNode "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("(2)从尾部添加节点")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("addTail")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" newNode "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("tail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("tail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("tail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n newNode"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("tail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("(3)删除节点")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("remove")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("tail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" curr "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("curr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("equals")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" curr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n curr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n curr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n curr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("break")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n prev "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" prev"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[t._v("(4)查找节点")]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("find")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),t._v(" value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("DListNode")]),s("span",{pre:!0,attrs:{class:"token generics"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("E")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("head"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("tail"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("equals")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n node "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" node"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("next"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("h2",{attrs:{id:"练习"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#练习"}},[t._v("#")]),t._v(" 练习")]),t._v(" "),s("ul",[s("li",[t._v("数组\n"),s("ul",[s("li",[t._v("[x] "),s("a",{attrs:{href:"https://leetcode-cn.com/problems/find-pivot-index/",target:"_blank",rel:"noopener noreferrer"}},[t._v("724. 寻找数组的中心下标"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[x] "),s("a",{attrs:{href:"https://leetcode-cn.com/problems/search-insert-position/",target:"_blank",rel:"noopener noreferrer"}},[t._v("35. 搜索插入位置"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[x] "),s("a",{attrs:{href:"https://leetcode-cn.com/problems/merge-intervals/",target:"_blank",rel:"noopener noreferrer"}},[t._v("56. 合并区间"),s("OutboundLink")],1)])])]),t._v(" "),s("li",[t._v("链表\n"),s("ul",[s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/jy291/",target:"_blank",rel:"noopener noreferrer"}},[t._v("设计链表"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/jbex5/",target:"_blank",rel:"noopener noreferrer"}},[t._v("环形链表"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/jjhf6/",target:"_blank",rel:"noopener noreferrer"}},[t._v("环形链表 II"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/jjbj2/",target:"_blank",rel:"noopener noreferrer"}},[t._v("相交链表"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/jf1cc/",target:"_blank",rel:"noopener noreferrer"}},[t._v("删除链表的倒数第 N 个节点"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/f58sg/",target:"_blank",rel:"noopener noreferrer"}},[t._v("反转链表"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/f9izv/",target:"_blank",rel:"noopener noreferrer"}},[t._v("移除链表元素"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/fe0kj/",target:"_blank",rel:"noopener noreferrer"}},[t._v("奇偶链表"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/fov6t/",target:"_blank",rel:"noopener noreferrer"}},[t._v("回文链表"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/fnzd1/",target:"_blank",rel:"noopener noreferrer"}},[t._v("合并两个有序链表"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/fv6w7/",target:"_blank",rel:"noopener noreferrer"}},[t._v("两数相加"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/fw8v5/",target:"_blank",rel:"noopener noreferrer"}},[t._v("扁平化多级双向链表"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/fdi26/",target:"_blank",rel:"noopener noreferrer"}},[t._v("复制带随机指针的链表"),s("OutboundLink")],1)]),t._v(" "),s("li",[t._v("[ ] "),s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/read/linked-list/f00a2/",target:"_blank",rel:"noopener noreferrer"}},[t._v("旋转链表"),s("OutboundLink")],1)])])])]),t._v(" "),s("h2",{attrs:{id:"参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),s("ul",[s("li",[s("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法之美"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://item.jd.com/12407475.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构(C 语言版)"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://book.douban.com/subject/25859528/",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构(C++语言版)"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://leetcode-cn.com/leetbook/detail/array-and-string/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Leetcode:数组和字符串"),s("OutboundLink")],1)]),t._v(" "),s("li",[s("a",{attrs:{href:"https://leetcode-cn.com/tag/linked-list/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Leetcode:链表"),s("OutboundLink")],1)])])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/assets/js/8.9cac7dfa.js b/assets/js/8.9cac7dfa.js new file mode 100644 index 0000000..1615160 --- /dev/null +++ b/assets/js/8.9cac7dfa.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{371:function(t,_,v){"use strict";v.r(_);var s=v(15),r=Object(s.a)({},(function(){var t=this,_=t._self._c;return _("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[_("h1",{attrs:{id:"栈和队列"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#栈和队列"}},[t._v("#")]),t._v(" 栈和队列")]),t._v(" "),_("blockquote",[_("p",[_("strong",[t._v("队列")]),t._v("和"),_("strong",[t._v("栈")]),t._v("都是"),_("strong",[t._v("操作受限")]),t._v("的"),_("strong",[t._v("线性表")]),t._v(":前者先进先出,后者先进后出。")])]),t._v(" "),_("h2",{attrs:{id:"栈"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#栈"}},[t._v("#")]),t._v(" 栈")]),t._v(" "),_("h3",{attrs:{id:"栈是什么"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#栈是什么"}},[t._v("#")]),t._v(" 栈是什么")]),t._v(" "),_("p",[t._v("在 "),_("strong",[t._v("LIFO(后进先出)")]),t._v(" 数据结构中,将首先处理添加到队列中的最新元素。")]),t._v(" "),_("p",[_("strong",[t._v("栈是一个 LIFO(后进先出) 数据结构")]),t._v("。"),_("strong",[t._v("栈是一种“操作受限”的线性表")]),t._v(",只允许在一端插入和删除数据。通常,插入操作在栈中被称作入栈 push 。与队列类似,总是在堆栈的末尾添加一个新元素。但是,删除操作,退栈 pop ,将始终删除队列中相对于它的最后一个元素。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320200148.png",alt:"img"}})]),t._v(" "),_("p",[_("strong",[t._v("当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出、先进后出的特性,我们就应该首选“栈”这种数据结构")]),t._v("。")]),t._v(" "),_("p",[t._v("从栈的定义可以看出,栈只支持两个基本操作:"),_("strong",[t._v("入栈 "),_("code",[t._v("push()")])]),t._v(" 和 "),_("strong",[t._v("出栈 "),_("code",[t._v("pop()")])]),t._v(" ,也就是在栈顶插入一个数据和从栈顶删除一个数据。在入栈和出栈过程中,只需要一两个临时变量存储空间,所以空间复杂度是 "),_("code",[t._v("O(1)")]),t._v("。")]),t._v(" "),_("p",[t._v("栈既可以用数组来实现,也可以用链表来实现。用数组实现的栈,我们叫作"),_("strong",[t._v("顺序栈")]),t._v(",用链表实现的栈,我们叫作"),_("strong",[t._v("链式栈")]),t._v("。")]),t._v(" "),_("h3",{attrs:{id:"为什么需要栈"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#为什么需要栈"}},[t._v("#")]),t._v(" 为什么需要栈")]),t._v(" "),_("p",[t._v("相比数组和链表,栈只是对操作进行了限制,似乎并没有任何优势。为什么不直接使用数组或者链表?为什么还要用这个“操作受限”的“栈”呢?")]),t._v(" "),_("p",[t._v("特定的数据结构是对特定场景的抽象,而且,数组或链表暴露了太多的操作接口,操作上的确灵活自由,但使用时就比较不可控,自然也就更容易出错。")]),t._v(" "),_("h3",{attrs:{id:"栈的应用场景"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#栈的应用场景"}},[t._v("#")]),t._v(" 栈的应用场景")]),t._v(" "),_("p",[t._v("(1)"),_("strong",[t._v("函数调用栈")])]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310091000.jpg",alt:"img"}})]),t._v(" "),_("p",[t._v("(2)"),_("strong",[t._v("表达式求值")])]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310091100.jpg",alt:"img"}})]),t._v(" "),_("p",[t._v("(3)"),_("strong",[t._v("表达式匹配")])]),t._v(" "),_("p",[t._v("可以借助栈来检查表达式中的括号是否匹配")]),t._v(" "),_("h2",{attrs:{id:"队列"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#队列"}},[t._v("#")]),t._v(" 队列")]),t._v(" "),_("p",[t._v("在 FIFO 数据结构中,将首先处理添加到队列中的第一个元素。")]),t._v(" "),_("p",[t._v("队列是典型的 FIFO 数据结构。插入(insert)操作也称作入队(enqueue),新元素始终被添加在队列的末尾。 删除(delete)操作也被称为出队(dequeue)。 你只能移除第一个元素。")]),t._v(" "),_("h3",{attrs:{id:"什么是队列"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#什么是队列"}},[t._v("#")]),t._v(" 什么是队列")]),t._v(" "),_("p",[_("strong",[t._v("队列:先进先出的线性表")]),t._v("。")]),t._v(" "),_("p",[_("strong",[t._v("队列是一种“操作受限”的线性表")]),t._v(",只允许在一端插入数据,在另一端删除数据。")]),t._v(" "),_("p",[t._v("队列的最基本操作:"),_("strong",[t._v("入队 "),_("code",[t._v("enqueue()")])]),t._v(",放一个数据到队列尾部;"),_("strong",[t._v("出队 "),_("code",[t._v("dequeue()")])]),t._v(",从队列头部取一个元素。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220320200213.png",alt:"img"}})]),t._v(" "),_("p",[t._v("队列可以用数组来实现,也可以用链表来实现。用数组实现的队列叫作"),_("strong",[t._v("顺序队列")]),t._v(",用链表实现的队列叫作"),_("strong",[t._v("链式队列")]),t._v("。")]),t._v(" "),_("p",[t._v("队满的判断条件是 "),_("code",[t._v("tail == n")]),t._v(",队空的判断条件是 "),_("code",[t._v("head == tail")]),t._v("。")]),t._v(" "),_("h3",{attrs:{id:"循环队列"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#循环队列"}},[t._v("#")]),t._v(" 循环队列")]),t._v(" "),_("p",[t._v("循环队列是一种较为特殊的队列。")]),t._v(" "),_("p",[t._v("循环队列的要点是确定好 "),_("strong",[t._v("队空和队满的判定条件")]),t._v("。")]),t._v(" "),_("p",[t._v("在用数组实现的非循环队列中,队满的判断条件是 "),_("code",[t._v("(tail+1) % n == head")]),t._v(",队空的判断条件是 "),_("code",[t._v("head == tail")]),t._v("。")]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220322214822.png",alt:"img"}})]),t._v(" "),_("h3",{attrs:{id:"为什么需要队列"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#为什么需要队列"}},[t._v("#")]),t._v(" 为什么需要队列")]),t._v(" "),_("p",[t._v("为什么需要队列和为什么需要栈,是同样的道理,参考 为什么需要栈")]),t._v(" "),_("h3",{attrs:{id:"队列的应用场景"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#队列的应用场景"}},[t._v("#")]),t._v(" 队列的应用场景")]),t._v(" "),_("p",[t._v("(1)"),_("strong",[t._v("阻塞队列")])]),t._v(" "),_("p",[_("strong",[t._v("阻塞队列")]),t._v("其实就是在队列基础上增加了阻塞操作。简单来说,就是:")]),t._v(" "),_("ul",[_("li",[t._v("在队列为空的时候,从队头取数据会被阻塞。因为此时还没有数据可取,直到队列中有了数据才能返回;")]),t._v(" "),_("li",[t._v("如果队列已经满了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后再返回。")])]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310092908.jpg",alt:"img"}})]),t._v(" "),_("p",[_("img",{attrs:{src:"https://raw.githubusercontent.com/dunwu/images/master/snap/20220310093026.jpg",alt:"img"}})]),t._v(" "),_("p",[t._v("(2)"),_("strong",[t._v("并发队列")])]),t._v(" "),_("p",[t._v("线程安全的队列我们叫作"),_("strong",[t._v("并发队列")]),t._v("。最简单直接的实现方式是直接在 enqueue()、dequeue() 方法上加锁,但是锁粒度大并发度会比较低,同一时刻仅允许一个存或者取操作。实际上,基于数组的循环队列,利用 CAS 原子操作,可以实现非常高效的并发队列。这也是循环队列比链式队列应用更加广泛的原因。")]),t._v(" "),_("h2",{attrs:{id:"参考资料"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")]),t._v(" "),_("ul",[_("li",[_("a",{attrs:{href:"https://time.geekbang.org/column/intro/100017301",target:"_blank",rel:"noopener noreferrer"}},[t._v("数据结构与算法之美"),_("OutboundLink")],1)]),t._v(" "),_("li",[_("a",{attrs:{href:"https://leetcode-cn.com/leetbook/detail/queue-stack/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Leetcode:栈和队列"),_("OutboundLink")],1)])])])}),[],!1,null,null,null);_.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/9.b60f667a.js b/assets/js/9.b60f667a.js new file mode 100644 index 0000000..f9225bb --- /dev/null +++ b/assets/js/9.b60f667a.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{372:function(t,s,a){"use strict";a.r(s);var n=a(15),p=Object(n.a)({},(function(){var t=this,s=t._self._c;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h1",{attrs:{id:"线性表的查找"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#线性表的查找"}},[t._v("#")]),t._v(" 线性表的查找")]),t._v(" "),s("h2",{attrs:{id:"查找简介"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#查找简介"}},[t._v("#")]),t._v(" 查找简介")]),t._v(" "),s("h3",{attrs:{id:"什么是查找"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#什么是查找"}},[t._v("#")]),t._v(" 什么是查找?")]),t._v(" "),s("p",[s("strong",[t._v("查找")]),t._v("是根据给定的某个值,在表中确定一个关键字的值等于给定值的记录或数据元素。")]),t._v(" "),s("h3",{attrs:{id:"查找算法的分类"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#查找算法的分类"}},[t._v("#")]),t._v(" 查找算法的分类")]),t._v(" "),s("p",[t._v("若在查找的同时对表记录做修改操作(如插入和删除),则相应的表称之为"),s("strong",[t._v("动态查找表")]),t._v(";")]),t._v(" "),s("p",[t._v("否则,称之为"),s("strong",[t._v("静态查找表")]),t._v("。")]),t._v(" "),s("p",[t._v("此外,如果查找的全过程都在内存中进行,称之为"),s("strong",[t._v("内查找")]),t._v(";")]),t._v(" "),s("p",[t._v("反之,如果查找过程中需要访问外存,称之为"),s("strong",[t._v("外查找")]),t._v("。")]),t._v(" "),s("h3",{attrs:{id:"查找算法性能比较的标准"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#查找算法性能比较的标准"}},[t._v("#")]),t._v(" 查找算法性能比较的标准")]),t._v(" "),s("p",[s("strong",[t._v("——平均查找长度 ASL(Average Search Length)")])]),t._v(" "),s("p",[t._v("由于查找算法的主要运算是关键字的比较过程,所以通常把查找过程中对关键字需要执行的"),s("strong",[t._v("平均比较长度")]),t._v("(也称为"),s("strong",[t._v("平均比较次数")]),t._v(")作为衡量一个查找算法效率优劣的比较标准。")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://upload-images.jianshu.io/upload_images/3101171-a38f84148d091364.gif?imageMogr2/auto-orient/strip",alt:"img"}})]),t._v(" "),s("p",[s("strong",[t._v("选取查找算法的因素")])]),t._v(" "),s("p",[t._v("(1) 使用什么数据存储结构(如线性表、树形表等)。")]),t._v(" "),s("p",[t._v("(2) 表中的次序,即对无序表还是有序表进行查找。")]),t._v(" "),s("h2",{attrs:{id:"顺序查找"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#顺序查找"}},[t._v("#")]),t._v(" 顺序查找")]),t._v(" "),s("p",[s("strong",[t._v("要点")])]),t._v(" "),s("p",[t._v("它是一种最简单的查找算法,效率也很低下。")]),t._v(" "),s("p",[s("strong",[t._v("存储结构")])]),t._v(" "),s("p",[t._v("没有存储结构要求,可以无序,也可以有序。")]),t._v(" "),s("p",[s("strong",[t._v("基本思想")])]),t._v(" "),s("p",[t._v("从数据结构线形表的"),s("strong",[t._v("一端")]),t._v("开始,"),s("strong",[t._v("顺序扫描")]),t._v(","),s("strong",[t._v("依次")]),t._v("将扫描到的结点关键字与给定值 k 相"),s("strong",[t._v("比较")]),t._v(",若相等则表示查找成功;")]),t._v(" "),s("p",[t._v("若扫描结束仍没有找到关键字等于 k 的结点,表示查找失败。")]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("orderSearch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 从前往后扫描list数组,如果有元素的值与key相等,直接返回其位置")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 如果扫描完,说明没有元素的值匹配key,返回-1,表示查找失败")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[s("strong",[t._v("算法分析")])]),t._v(" "),s("p",[t._v("顺序查找算法"),s("strong",[t._v("最好的情况")]),t._v("是,第一个记录即匹配关键字,则需要比较 "),s("strong",[t._v("1")]),t._v(" 次;")]),t._v(" "),s("p",[s("strong",[t._v("最坏的情况")]),t._v("是,最后一个记录匹配关键字,则需要比较 "),s("strong",[t._v("N")]),t._v(" 次。")]),t._v(" "),s("p",[t._v("所以,顺序查找算法的平均查找长度为")]),t._v(" "),s("p",[t._v("ASL = (N + N-1 + ... + 2 + 1) / N = (N+1) / 2")]),t._v(" "),s("p",[t._v("顺序查找的"),s("strong",[t._v("平均时间复杂度")]),t._v("为"),s("strong",[t._v("O(N)")]),t._v("。")]),t._v(" "),s("h2",{attrs:{id:"二分查找"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#二分查找"}},[t._v("#")]),t._v(" 二分查找")]),t._v(" "),s("blockquote",[s("p",[s("strong",[t._v("二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0")]),t._v("。")])]),t._v(" "),s("p",[s("strong",[t._v("存储结构")])]),t._v(" "),s("p",[t._v("使用二分查找需要两个前提:")]),t._v(" "),s("p",[t._v("(1) 必须是"),s("strong",[t._v("顺序")]),t._v("存储结构。")]),t._v(" "),s("p",[t._v("(2) 必须是"),s("strong",[t._v("有序")]),t._v("的表。")]),t._v(" "),s("p",[s("strong",[t._v("基本思想")])]),t._v(" "),s("p",[t._v("首先,将表"),s("strong",[t._v("中间位置")]),t._v("记录的关键字与查找关键字比较,如果两者相等,则查找成功;")]),t._v(" "),s("p",[t._v("否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。\n重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。")]),t._v(" "),s("p",[s("strong",[t._v("核心代码")])]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("binarySearch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" high "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" length "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" high"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" high"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("mid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" mid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 查找成功,直接返回位置")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("mid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 关键字大于中间位置的值,则在大值区间[mid+1, high]继续查找")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n high "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 关键字小于中间位置的值,则在小值区间[low, mid-1]继续查找")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[s("strong",[t._v("算法分析")])]),t._v(" "),s("p",[s("strong",[t._v("二分查找的过程可看成一个二叉树")]),t._v("。")]),t._v(" "),s("p",[t._v("把查找区间的中间位置视为树的根,左区间和右区间视为根的左子树和右子树。")]),t._v(" "),s("p",[t._v("由此得到的二叉树,称为二分查找的判定树或比较树。")]),t._v(" "),s("p",[t._v("由此可知,二分查找的"),s("strong",[t._v("平均查找长度")]),t._v("实际上就是树的高度"),s("strong",[t._v("O(log"),s("sub",[t._v("2")]),t._v("N)")]),t._v("。")]),t._v(" "),s("p",[s("strong",[t._v("二分查找的局限性")])]),t._v(" "),s("ul",[s("li",[t._v("二分查找依赖的是顺序表结构,简单点说就是数组")]),t._v(" "),s("li",[t._v("二分查找针对的是有序数据")]),t._v(" "),s("li",[t._v("数据量太小不适合二分查找")]),t._v(" "),s("li",[t._v("数据量太大也不适合二分查找")])]),t._v(" "),s("h2",{attrs:{id:"分块查找"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#分块查找"}},[t._v("#")]),t._v(" 分块查找")]),t._v(" "),s("p",[s("strong",[t._v("要点")])]),t._v(" "),s("p",[t._v("分块查找(Blocking Search)又称"),s("strong",[t._v("索引顺序查找")]),t._v("。它是一种性能介于顺序查找和二分查找之间的查找方法。")]),t._v(" "),s("p",[t._v("分块查找由于只要求索引表是有序的,对块内节点没有排序要求,因此特别适合于节点动态变化的情况。")]),t._v(" "),s("p",[s("strong",[t._v("存储结构")])]),t._v(" "),s("p",[t._v("分块查找表是由**“分块有序”的线性表"),s("strong",[t._v("和")]),t._v("索引表**两部分构成的。")]),t._v(" "),s("p",[t._v("所谓**“分块有序”的线性表**,是指:")]),t._v(" "),s("p",[t._v("假设要排序的表为 R[0...N-1],"),s("strong",[t._v("将表均匀分成 b 块")]),t._v(",前 b-1 块中记录个数为 s=N/b,最后一块记录数小于等于 s;")]),t._v(" "),s("p",[t._v("每一块中的关键字不一定有序,但"),s("strong",[t._v("前一块中的最大关键字必须小于后一块中的最小关键字")]),t._v("。")]),t._v(" "),s("p",[s("strong",[s("em",[t._v("注:这是使用分块查找的前提条件。")])])]),t._v(" "),s("p",[t._v("如上将表均匀分成 b 块后,抽取各块中的"),s("strong",[t._v("最大关键字")]),t._v("和"),s("strong",[t._v("起始位置")]),t._v("构成一个索引表 IDX[0...b-1]。")]),t._v(" "),s("p",[t._v("由于表 R 是分块有序的,所以"),s("strong",[t._v("索引表是一个递增有序表")]),t._v("。")]),t._v(" "),s("p",[t._v("下图就是一个分块查找表的存储结构示意图")]),t._v(" "),s("p",[s("img",{attrs:{src:"https://upload-images.jianshu.io/upload_images/3101171-b7ad44c68d0c3c75.png",alt:"img"}})]),t._v(" "),s("p",[s("strong",[t._v("基本思想")])]),t._v(" "),s("p",[t._v("分块查找算法有两个处理步骤:")]),t._v(" "),s("p",[s("strong",[t._v("(1) 首先查找索引表")])]),t._v(" "),s("p",[t._v("因为分块查找表是“分块有序”的,所以我们可以通过索引表来锁定关键字所在的区间。")]),t._v(" "),s("p",[t._v("又因为索引表是递增有序的,所以查找索引可以使用顺序查找或二分查找。")]),t._v(" "),s("p",[s("strong",[t._v("(2) 然后在已确定的块中进行顺序查找")])]),t._v(" "),s("p",[t._v("因为块中不一定是有序的,所以只能使用顺序查找。")]),t._v(" "),s("p",[s("strong",[t._v("代码范例")])]),t._v(" "),s("p",[s("img",{attrs:{src:"http://upload-images.jianshu.io/upload_images/3101171-2737612c781e66e8.gif?imageMogr2/auto-orient/strip",alt:"img"}})]),t._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockSearch")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IndexType")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 分块中的最大值")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" link"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 分块的起始位置")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 建立索引方法,n 是线性表最大长度,gap是分块的最大长度")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IndexType")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("createIndex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" max "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" num "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IndexType")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" idxGroup "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IndexType")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("num"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 根据步长数分配索引数组大小")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" num"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IndexType")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("link "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 确定当前索引组的第一个元素位置")]),t._v("\n max "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 每次假设当前组的第一个数为最大值")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 遍历这个分块,找到最大值")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("j "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("max "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n max "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" j"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n j"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" max"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 分块查找算法")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("blockSearch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IndexType")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" m"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" high "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" m "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" gap "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" m"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 分块大小等于线性表长度除以组数")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 先在索引表中进行二分查找,找到的位置存放在 low 中")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("while")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<=")]),t._v(" high"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" high"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("/")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("mid"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">=")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n high "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" mid "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 在索引表中查找成功后,再在线性表的指定块中进行顺序查找")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("low "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" m"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("low"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("link"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),t._v(" idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("low"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("link "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" gap"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" i"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 打印完整序列")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printAll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" value "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("value "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('" "')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 打印索引表")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printIDX")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IndexType")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"构造索引表如下:"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("for")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IndexType")]),t._v(" elem "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" list"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"key = %d, link = %d\\n"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" elem"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" elem"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("link"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" key "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("85")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("8")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("14")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("6")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("9")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("34")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("18")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("19")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("31")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("40")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("38")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("54")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("66")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("46")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("71")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("78")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("68")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("85")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockSearch")]),t._v(" search "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BlockSearch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("print")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"线性表: "')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n search"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printAll")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IndexType")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" idxGroup "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" search"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("createIndex")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n search"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("printIDX")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("int")]),t._v(" pos "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" search"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("blockSearch")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" idxGroup"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n array2"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" pos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"查找key = %d失败"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("format")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"查找key = %d成功,位置为%d"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" key"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" pos"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),s("p",[s("strong",[t._v("运行结果")])]),t._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[t._v("线性表: 8 14 6 9 10 22 34 18 19 31 40 38 54 66 46 71 78 68 80 85\n构造索引表如下:\nkey = 14, link = 0\nkey = 34, link = 5\nkey = 66, link = 10\nkey = 85, link = 15\n\n查找key = 85成功,位置为19\n")])])]),s("p",[s("strong",[t._v("算法分析")])]),t._v(" "),s("p",[t._v("因为分块查找实际上是两次查找过程之和。若以二分查找来确定块,显然它的查找效率介于顺序查找和二分查找之间。")]),t._v(" "),s("h2",{attrs:{id:"三种线性查找的-pk"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#三种线性查找的-pk"}},[t._v("#")]),t._v(" 三种线性查找的 PK")]),t._v(" "),s("p",[t._v("(1) 以平均查找长度而言,二分查找 > 分块查找 > 顺序查找。")]),t._v(" "),s("p",[t._v("(2) 从适用性而言,顺序查找无限制条件,二分查找仅适用于有序表,分块查找要求“分块有序”。")]),t._v(" "),s("p",[t._v("(3) 从存储结构而言,顺序查找和分块查找既可用于顺序表也可用于链表;而二分查找只适用于顺序表。")]),t._v(" "),s("p",[t._v("(4) 分块查找综合了顺序查找和二分查找的优点,既可以较为快速,也能使用动态变化的要求。")]),t._v(" "),s("h2",{attrs:{id:"参考资料"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#参考资料"}},[t._v("#")]),t._v(" 参考资料")])])}),[],!1,null,null,null);s.default=p.exports}}]); \ No newline at end of file diff --git a/assets/js/app.fe785b0c.js b/assets/js/app.fe785b0c.js new file mode 100644 index 0000000..7185af4 --- /dev/null +++ b/assets/js/app.fe785b0c.js @@ -0,0 +1,10 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(n){function e(e){for(var r,a,s=e[0],l=e[1],c=e[2],d=0,p=[];dfunction n(e,t,r,i=1){if("string"==typeof e)return f(t,e,r);if(Array.isArray(e))return Object.assign(f(t,e[0],r),{title:e[1]});{i>3&&console.error("[vuepress] detected a too deep nested sidebar group.");const o=e.children||[];return 0===o.length&&e.path?Object.assign(f(t,e.path,r),{title:e.title}):{type:"group",path:e.path,title:e.title,sidebarDepth:e.sidebarDepth,initialOpenGroupIndex:e.initialOpenGroupIndex,children:o.map(e=>n(e,t,r,i+1)),collapsable:!1!==e.collapsable}}}(n,i,t)):[]}return[]}function v(n){const e=m(n.headers||[]);return[{type:"group",collapsable:!1,title:n.title,path:null,children:e.map(e=>({type:"auto",title:e.title,basePath:n.path,path:n.path+"#"+e.slug,children:e.children||[]}))}]}function m(n){let e;return(n=n.map(n=>Object.assign({},n))).forEach(n=>{2===n.level?e=n:e&&(e.children||(e.children=[])).push(n)}),n.filter(n=>2===n.level)}function g(n){return Object.assign(n,{type:n.items&&n.items.length?"links":"link"})}function y(n){return Object.prototype.toString.call(n).match(/\[object (.*?)\]/)[1].toLowerCase()}function b(n){let e=n.frontmatter.date||n.lastUpdated||new Date,t=new Date(e);return"Invalid Date"==t&&e&&(t=new Date(e.replace(/-/g,"/"))),t.getTime()}function x(n,e){return b(e)-b(n)}},function(n,e,t){"use strict";var r=t(10),i=t(6),o=t(11),a=t(5),s=t(28),l=t(93),c=t(94),u=t(12),d=t(95),p=t(29),f=t(26),h=!f&&!d("map",(function(){})),v=!f&&!h&&p("map",TypeError),m=f||h||v,g=l((function(){var n=this.iterator,e=a(i(this.next,n));if(!(this.done=!!e.done))return c(n,this.mapper,[e.value,this.counter++],!0)}));r({target:"Iterator",proto:!0,real:!0,forced:m},{map:function(n){a(this);try{o(n)}catch(n){u(this,"throw",n)}return v?i(v,this,n):new g(s(this),{mapper:n})}})},function(n,e){n.exports=function(n){return null!=n&&"object"==typeof n}},function(n,e,t){"use strict";var r=t(2),i=r({}.toString),o=r("".slice);n.exports=function(n){return o(i(n),8,-1)}},function(n,e,t){"use strict";var r=t(3),i=t(1),o=function(n){return i(n)?n:void 0};n.exports=function(n,e){return arguments.length<2?o(r[n]):r[n]&&r[n][e]}},function(n,e,t){"use strict";n.exports=!1},function(n,e,t){"use strict";var r=t(7),i=t(19),o=t(36);n.exports=r?function(n,e,t){return i.f(n,e,o(1,t))}:function(n,e,t){return n[e]=t,n}},function(n,e,t){"use strict";n.exports=function(n){return{iterator:n,next:n.next,done:!1}}},function(n,e,t){"use strict";var r=t(3);n.exports=function(n,e){var t=r.Iterator,i=t&&t.prototype,o=i&&i[n],a=!1;if(o)try{o.call({next:function(){return{done:!0}},return:function(){a=!0}},-1)}catch(n){n instanceof e||(a=!1)}if(!a)return o}},function(n,e,t){"use strict";var r=t(146);n.exports=function(n){return r(n.length)}},function(n,e,t){var r=t(32),i=t(187),o=t(188),a=r?r.toStringTag:void 0;n.exports=function(n){return null==n?void 0===n?"[object Undefined]":"[object Null]":a&&a in Object(n)?i(n):o(n)}},function(n,e,t){var r=t(14).Symbol;n.exports=r},function(n,e,t){"use strict";var r=t(10),i=t(34),o=t(30),a=t(179),s=t(180);r({target:"Array",proto:!0,arity:1,forced:t(0)((function(){return 4294967297!==[].push.call({length:4294967296},1)}))||!function(){try{Object.defineProperty([],"length",{writable:!1}).push()}catch(n){return n instanceof TypeError}}()},{push:function(n){var e=i(this),t=o(e),r=arguments.length;s(t+r);for(var l=0;l
'};function i(n,e,t){return nt?t:n}function o(n){return 100*(-1+n)}t.configure=function(n){var e,t;for(e in n)void 0!==(t=n[e])&&n.hasOwnProperty(e)&&(r[e]=t);return this},t.status=null,t.set=function(n){var e=t.isStarted();n=i(n,r.minimum,1),t.status=1===n?null:n;var l=t.render(!e),c=l.querySelector(r.barSelector),u=r.speed,d=r.easing;return l.offsetWidth,a((function(e){""===r.positionUsing&&(r.positionUsing=t.getPositioningCSS()),s(c,function(n,e,t){var i;return(i="translate3d"===r.positionUsing?{transform:"translate3d("+o(n)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+o(n)+"%,0)"}:{"margin-left":o(n)+"%"}).transition="all "+e+"ms "+t,i}(n,u,d)),1===n?(s(l,{transition:"none",opacity:1}),l.offsetWidth,setTimeout((function(){s(l,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){t.remove(),e()}),u)}),u)):setTimeout(e,u)})),this},t.isStarted=function(){return"number"==typeof t.status},t.start=function(){t.status||t.set(0);var n=function(){setTimeout((function(){t.status&&(t.trickle(),n())}),r.trickleSpeed)};return r.trickle&&n(),this},t.done=function(n){return n||t.status?t.inc(.3+.5*Math.random()).set(1):this},t.inc=function(n){var e=t.status;return e?("number"!=typeof n&&(n=(1-e)*i(Math.random()*e,.1,.95)),e=i(e+n,0,.994),t.set(e)):t.start()},t.trickle=function(){return t.inc(Math.random()*r.trickleRate)},n=0,e=0,t.promise=function(r){return r&&"resolved"!==r.state()?(0===e&&t.start(),n++,e++,r.always((function(){0==--e?(n=0,t.done()):t.set((n-e)/n)})),this):this},t.render=function(n){if(t.isRendered())return document.getElementById("nprogress");c(document.documentElement,"nprogress-busy");var e=document.createElement("div");e.id="nprogress",e.innerHTML=r.template;var i,a=e.querySelector(r.barSelector),l=n?"-100":o(t.status||0),u=document.querySelector(r.parent);return s(a,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(i=e.querySelector(r.spinnerSelector))&&p(i),u!=document.body&&c(u,"nprogress-custom-parent"),u.appendChild(e),e},t.remove=function(){u(document.documentElement,"nprogress-busy"),u(document.querySelector(r.parent),"nprogress-custom-parent");var n=document.getElementById("nprogress");n&&p(n)},t.isRendered=function(){return!!document.getElementById("nprogress")},t.getPositioningCSS=function(){var n=document.body.style,e="WebkitTransform"in n?"Webkit":"MozTransform"in n?"Moz":"msTransform"in n?"ms":"OTransform"in n?"O":"";return e+"Perspective"in n?"translate3d":e+"Transform"in n?"translate":"margin"};var a=function(){var n=[];function e(){var t=n.shift();t&&t(e)}return function(t){n.push(t),1==n.length&&e()}}(),s=function(){var n=["Webkit","O","Moz","ms"],e={};function t(t){return t=t.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(n,e){return e.toUpperCase()})),e[t]||(e[t]=function(e){var t=document.body.style;if(e in t)return e;for(var r,i=n.length,o=e.charAt(0).toUpperCase()+e.slice(1);i--;)if((r=n[i]+o)in t)return r;return e}(t))}function r(n,e,r){e=t(e),n.style[e]=r}return function(n,e){var t,i,o=arguments;if(2==o.length)for(t in e)void 0!==(i=e[t])&&e.hasOwnProperty(t)&&r(n,t,i);else r(n,o[1],o[2])}}();function l(n,e){return("string"==typeof n?n:d(n)).indexOf(" "+e+" ")>=0}function c(n,e){var t=d(n),r=t+e;l(t,e)||(n.className=r.substring(1))}function u(n,e){var t,r=d(n);l(n,e)&&(t=r.replace(" "+e+" "," "),n.className=t.substring(1,t.length-1))}function d(n){return(" "+(n.className||"")+" ").replace(/\s+/gi," ")}function p(n){n&&n.parentNode&&n.parentNode.removeChild(n)}return t})?r.call(e,t,e,n):r)||(n.exports=i)},function(n,e,t){"use strict";var r=t(1),i=t(19),o=t(86),a=t(55);n.exports=function(n,e,t,s){s||(s={});var l=s.enumerable,c=void 0!==s.name?s.name:e;if(r(t)&&o(t,c,s),s.global)l?n[e]=t:a(e,t);else{try{s.unsafe?n[e]&&(l=!0):delete n[e]}catch(n){}l?n[e]=t:i.f(n,e,{value:t,enumerable:!1,configurable:!s.nonConfigurable,writable:!s.nonWritable})}return n}},function(n,e,t){"use strict";var r=t(132),i=t(6),o=t(5),a=t(53),s=t(163),l=t(30),c=t(38),u=t(164),d=t(97),p=t(12),f=TypeError,h=function(n,e){this.stopped=n,this.result=e},v=h.prototype;n.exports=function(n,e,t){var m,g,y,b,x,_,w,k=t&&t.that,E=!(!t||!t.AS_ENTRIES),T=!(!t||!t.IS_RECORD),O=!(!t||!t.IS_ITERATOR),j=!(!t||!t.INTERRUPTED),S=r(e,k),C=function(n){return m&&p(m,"normal"),new h(!0,n)},I=function(n){return E?(o(n),j?S(n[0],n[1],C):S(n[0],n[1])):j?S(n,C):S(n)};if(T)m=n.iterator;else if(O)m=n;else{if(!(g=d(n)))throw new f(a(n)+" is not iterable");if(s(g)){for(y=0,b=l(n);b>y;y++)if((x=I(n[y]))&&c(v,x))return x;return new h(!1)}m=u(n,g)}for(_=T?n.next:m.next;!(w=i(_,m)).done;){try{x=I(w.value)}catch(n){p(m,"throw",n)}if("object"==typeof x&&x&&c(v,x))return x}return new h(!1)}},function(n,e,t){"use strict";var r=t(98),i=String;n.exports=function(n){if("Symbol"===r(n))throw new TypeError("Cannot convert a Symbol value to a string");return i(n)}},function(n,e,t){"use strict";var r=t(51),i=TypeError;n.exports=function(n){if(r(n))throw new i("Can't call method on "+n);return n}},function(n,e,t){"use strict";n.exports=function(n){return null==n}},function(n,e,t){"use strict";var r=t(25),i=t(1),o=t(38),a=t(79),s=Object;n.exports=a?function(n){return"symbol"==typeof n}:function(n){var e=r("Symbol");return i(e)&&o(e.prototype,s(n))}},function(n,e,t){"use strict";var r=String;n.exports=function(n){try{return r(n)}catch(n){return"Object"}}},function(n,e,t){"use strict";var r=t(26),i=t(3),o=t(55),a=n.exports=i["__core-js_shared__"]||o("__core-js_shared__",{});(a.versions||(a.versions=[])).push({version:"3.47.0",mode:r?"pure":"global",copyright:"© 2014-2025 Denis Pushkarev (zloirock.ru), 2025 CoreJS Company (core-js.io)",license:"https://github.com/zloirock/core-js/blob/v3.47.0/LICENSE",source:"https://github.com/zloirock/core-js"})},function(n,e,t){"use strict";var r=t(3),i=Object.defineProperty;n.exports=function(n,e){try{i(r,n,{value:e,configurable:!0,writable:!0})}catch(t){r[n]=e}return e}},function(n,e,t){"use strict";var r=t(2),i=0,o=Math.random(),a=r(1.1.toString);n.exports=function(n){return"Symbol("+(void 0===n?"":n)+")_"+a(++i+o,36)}},function(n,e,t){"use strict";var r,i,o,a=t(140),s=t(3),l=t(8),c=t(27),u=t(9),d=t(54),p=t(58),f=t(59),h=s.TypeError,v=s.WeakMap;if(a||d.state){var m=d.state||(d.state=new v);m.get=m.get,m.has=m.has,m.set=m.set,r=function(n,e){if(m.has(n))throw new h("Object already initialized");return e.facade=n,m.set(n,e),e},i=function(n){return m.get(n)||{}},o=function(n){return m.has(n)}}else{var g=p("state");f[g]=!0,r=function(n,e){if(u(n,g))throw new h("Object already initialized");return e.facade=n,c(n,g,e),e},i=function(n){return u(n,g)?n[g]:{}},o=function(n){return u(n,g)}}n.exports={set:r,get:i,has:o,enforce:function(n){return o(n)?i(n):r(n,{})},getterFor:function(n){return function(e){var t;if(!l(e)||(t=i(e)).type!==n)throw new h("Incompatible receiver, "+n+" required");return t}}}},function(n,e,t){"use strict";var r=t(82),i=t(56),o=r("keys");n.exports=function(n){return o[n]||(o[n]=i(n))}},function(n,e,t){"use strict";n.exports={}},function(n,e,t){"use strict";n.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(n,e,t){"use strict";var r=t(35),i=Function.prototype,o=i.apply,a=i.call;n.exports="object"==typeof Reflect&&Reflect.apply||(r?a.bind(o):function(){return a.apply(o,arguments)})},function(n,e,t){"use strict";var r=t(24);n.exports=Array.isArray||function(n){return"Array"===r(n)}},function(n,e,t){var r=t(186),i=t(23),o=Object.prototype,a=o.hasOwnProperty,s=o.propertyIsEnumerable,l=r(function(){return arguments}())?r:function(n){return i(n)&&a.call(n,"callee")&&!s.call(n,"callee")};n.exports=l},function(n,e,t){var r=t(20)(t(14),"Map");n.exports=r},function(n,e){n.exports=function(n){var e=typeof n;return null!=n&&("object"==e||"function"==e)}},function(n,e,t){var r=t(206),i=t(213),o=t(215),a=t(216),s=t(217);function l(n){var e=-1,t=null==n?0:n.length;for(this.clear();++e-1&&n%1==0&&n<=9007199254740991}},function(n,e,t){var r=t(13),i=t(70),o=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,a=/^\w*$/;n.exports=function(n,e){if(r(n))return!1;var t=typeof n;return!("number"!=t&&"symbol"!=t&&"boolean"!=t&&null!=n&&!i(n))||(a.test(n)||!o.test(n)||null!=e&&n in Object(e))}},function(n,e,t){var r=t(31),i=t(23);n.exports=function(n){return"symbol"==typeof n||i(n)&&"[object Symbol]"==r(n)}},function(n,e){n.exports=function(n){return n}},function(n,e,t){"use strict";var r=t(10),i=t(6),o=t(48),a=t(11),s=t(5),l=t(28),c=t(12),u=t(29)("some",TypeError);r({target:"Iterator",proto:!0,real:!0,forced:u},{some:function(n){s(this);try{a(n)}catch(n){c(this,"throw",n)}if(u)return i(u,this,n);var e=l(this),t=0;return o(e,(function(e,r){if(n(e,t++))return r()}),{IS_RECORD:!0,INTERRUPTED:!0}).stopped}})},function(n,e,t){"use strict";var r=t(2),i=t(0),o=t(24),a=Object,s=r("".split);n.exports=i((function(){return!a("z").propertyIsEnumerable(0)}))?function(n){return"String"===o(n)?s(n,""):a(n)}:a},function(n,e,t){"use strict";var r,i=t(5),o=t(151),a=t(60),s=t(59),l=t(153),c=t(84),u=t(58),d=u("IE_PROTO"),p=function(){},f=function(n){return" + + diff --git a/codes/algorithm/pom.xml b/codes/algorithm/pom.xml deleted file mode 100644 index 307f4bd..0000000 --- a/codes/algorithm/pom.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - 4.0.0 - - io.github.dunwu.algorithm - algorithm - 1.0.0 - jar - 算法示例 - 数据示例源码 - - - UTF-8 - 1.8 - ${java.version} - ${java.version} - - - - - cn.hutool - hutool-all - 5.8.29 - - - org.projectlombok - lombok - 1.18.36 - provided - - - ch.qos.logback - logback-classic - 1.2.9 - - - org.junit.jupiter - junit-jupiter - 5.8.2 - - - org.assertj - assertj-core - 3.26.3 - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - none - - - - - diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" deleted file mode 100644 index 7e1cb56..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\260.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.array.base; - -import org.junit.jupiter.api.Assertions; - -/** - * 485. 最大连续 1 的个数 - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 最大连续1的个数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.findMaxConsecutiveOnes(new int[] { 1, 1, 0, 1, 1, 1 })); - Assertions.assertEquals(2, s.findMaxConsecutiveOnes(new int[] { 1, 0, 1, 1, 0, 1 })); - } - - static class Solution { - - public int findMaxConsecutiveOnes(int[] nums) { - int max = 0; - int cnt = 0; - for (int num : nums) { - if (num == 1) { - cnt++; - max = Math.max(max, cnt); - } else { - cnt = 0; - } - } - return max; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" deleted file mode 100644 index cd5ceb9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/base/\350\207\263\345\260\221\346\230\257\345\205\266\344\273\226\346\225\260\345\255\227\344\270\244\345\200\215\347\232\204\346\234\200\345\244\247\346\225\260.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.array.base; - -import org.junit.jupiter.api.Assertions; - -/** - * 747. 至少是其他数字两倍的最大数 - * - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 至少是其他数字两倍的最大数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(1, s.dominantIndex(new int[] { 3, 6, 1, 0 })); - Assertions.assertEquals(-1, s.dominantIndex(new int[] { 1, 2, 3, 4 })); - Assertions.assertEquals(0, s.dominantIndex(new int[] { 1, 0 })); - } - - static class Solution { - - public int dominantIndex(int[] nums) { - int second = -1, max = 0; - for (int i = 1; i < nums.length; i++) { - if (nums[i] > nums[max]) { - second = max; - max = i; - } else if (second == -1 || nums[i] > nums[second]) { - second = i; - } - } - return nums[max] >= 2 * nums[second] ? max : -1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" deleted file mode 100644 index 1a47983..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\344\272\214\345\210\206\346\237\245\346\211\276.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.array.bsearch; - -import org.junit.jupiter.api.Assertions; - -/** - * 704. 二分查找 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 二分查找 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.search(new int[] { -1, 0, 3, 5, 9, 12 }, 9)); - Assertions.assertEquals(-1, s.search(new int[] { -1, 0, 3, 5, 9, 12 }, 2)); - } - - static class Solution { - - public int search(int[] nums, int target) { - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] == target) { - return mid; - } else if (nums[mid] < target) { - left = mid + 1; - } else { - right = mid - 1; - } - } - return -1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" deleted file mode 100644 index 0c3678b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\210\206\345\211\262\346\225\260\347\273\204\347\232\204\346\234\200\345\244\247\345\200\274.java" +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.array.bsearch; - -import org.junit.jupiter.api.Assertions; - -/** - * 410. 分割数组的最大值 - * - * @author Zhang Peng - * @date 2025-10-16 - */ -public class 分割数组的最大值 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(18, s.splitArray(new int[] { 7, 2, 5, 10, 8 }, 2)); - Assertions.assertEquals(9, s.splitArray(new int[] { 1, 2, 3, 4, 5 }, 2)); - Assertions.assertEquals(4, s.splitArray(new int[] { 1, 4, 4 }, 3)); - } - - static class Solution { - - public int splitArray(int[] nums, int k) { - return shipWithinDays(nums, k); - } - - public int shipWithinDays(int[] weights, int days) { - int max = 0, sum = 0; - for (int weight : weights) { - max = Math.max(max, weight); - sum += weight; - } - - int left = max, right = sum; - while (left <= right) { - int mid = left + (right - left) / 2; - if (f(weights, mid) <= days) { - // 需要让 f(x) 的返回值大一些 - right = mid - 1; - } else if (f(weights, mid) > days) { - // 需要让 f(x) 的返回值小一些 - left = mid + 1; - } - } - return left; - } - - // 定义:当运载能力为 x 时,需要 f(x) 天运完所有货物 - // f(x) 随着 x 的增加单调递减 - int f(int[] weights, int x) { - int days = 0; - for (int i = 0; i < weights.length; ) { - // 尽可能多装货物 - int cap = x; - while (i < weights.length) { - if (cap < weights[i]) break; - else cap -= weights[i]; - i++; - } - days++; - } - return days; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" deleted file mode 100644 index 04d948d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250D\345\244\251\345\206\205\351\200\201\350\276\276\345\214\205\350\243\271\347\232\204\350\203\275\345\212\233.java" +++ /dev/null @@ -1,62 +0,0 @@ -package io.github.dunwu.algorithm.array.bsearch; - -import org.junit.jupiter.api.Assertions; - -/** - * 1011. 在 D 天内送达包裹的能力 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 在D天内送达包裹的能力 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(15, s.shipWithinDays(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 5)); - Assertions.assertEquals(6, s.shipWithinDays(new int[] { 3, 2, 2, 4, 1, 4 }, 3)); - Assertions.assertEquals(3, s.shipWithinDays(new int[] { 1, 2, 3, 1, 1 }, 4)); - } - - static class Solution { - - public int shipWithinDays(int[] weights, int days) { - int max = 0, sum = 0; - for (int weight : weights) { - max = Math.max(max, weight); - sum += weight; - } - - int left = max, right = sum; - while (left <= right) { - int mid = left + (right - left) / 2; - if (f(weights, mid) <= days) { - // 需要让 f(x) 的返回值大一些 - right = mid - 1; - } else if (f(weights, mid) > days) { - // 需要让 f(x) 的返回值小一些 - left = mid + 1; - } - } - return left; - } - - // 定义:当运载能力为 x 时,需要 f(x) 天运完所有货物 - // f(x) 随着 x 的增加单调递减 - int f(int[] weights, int x) { - int days = 0; - for (int i = 0; i < weights.length; ) { - // 尽可能多装货物 - int cap = x; - while (i < weights.length) { - if (cap < weights[i]) break; - else cap -= weights[i]; - i++; - } - days++; - } - return days; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" deleted file mode 100644 index fb14865..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\345\234\250\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\346\237\245\346\211\276\345\205\203\347\264\240\347\232\204\347\254\254\344\270\200\344\270\252\345\222\214\346\234\200\345\220\216\344\270\200\344\270\252\344\275\215\347\275\256.java" +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.array.bsearch; - -import org.junit.jupiter.api.Assertions; - -/** - * 34.在排序数组中查找元素的第一个和最后一个位置 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 在排序数组中查找元素的第一个和最后一个位置 { - - public static void main(String[] args) { - Solution s = new Solution(); - - Assertions.assertEquals(-1, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 3)); - Assertions.assertEquals(0, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 5)); - Assertions.assertEquals(5, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 10)); - Assertions.assertEquals(-1, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 12)); - Assertions.assertEquals(1, s.searchLeft(new int[] { 5, 7, 7, 8, 8, 10 }, 7)); - - Assertions.assertEquals(-1, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 3)); - Assertions.assertEquals(0, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 5)); - Assertions.assertEquals(5, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 10)); - Assertions.assertEquals(-1, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 12)); - Assertions.assertEquals(2, s.searchRight(new int[] { 5, 7, 7, 8, 8, 10 }, 7)); - - Assertions.assertArrayEquals(new int[] { 3, 4 }, s.searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 8)); - Assertions.assertArrayEquals(new int[] { -1, -1 }, s.searchRange(new int[] { 5, 7, 7, 8, 8, 10 }, 6)); - Assertions.assertArrayEquals(new int[] { -1, -1 }, s.searchRange(new int[] {}, 0)); - Assertions.assertArrayEquals(new int[] { 0, 0 }, s.searchRange(new int[] { 1 }, 1)); - } - - static class Solution { - - public int[] searchRange(int[] nums, int target) { - int left = searchLeft(nums, target); - int right = searchRight(nums, target); - return new int[] { left, right }; - } - - public int searchLeft(int[] nums, int target) { - int res = -1; - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { - right = mid - 1; - } else if (nums[mid] == target) { - res = mid; - right = mid - 1; - } - } - return res; - } - - public int searchRight(int[] nums, int target) { - int res = -1; - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] > target) { - right = mid - 1; - } else if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] == target) { - res = mid; - left = mid + 1; - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" deleted file mode 100644 index bdc2bb9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.array.bsearch; - -import org.junit.jupiter.api.Assertions; - -/** - * 35. 搜索插入位置 - * - * @author Zhang Peng - * @since 2020-07-29 - */ -public class 搜索插入位置 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(0, s.searchInsert(new int[] { 1 }, 1)); - Assertions.assertEquals(2, s.searchInsert(new int[] { 1, 3, 5, 6 }, 5)); - Assertions.assertEquals(1, s.searchInsert(new int[] { 1, 3, 5, 6 }, 2)); - Assertions.assertEquals(4, s.searchInsert(new int[] { 1, 3, 5, 6 }, 7)); - Assertions.assertEquals(0, s.searchInsert(new int[] { 1, 3, 5, 6 }, 0)); - } - - static class Solution { - - public int searchInsert(int[] nums, int target) { - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] == target) { - return mid; - } else if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { - right = mid - 1; - } - } - return left; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" deleted file mode 100644 index c7b5f17..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\210\261\345\220\203\351\246\231\350\225\211\347\232\204\347\217\202\347\217\202.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.array.bsearch; - -import org.junit.jupiter.api.Assertions; - -/** - * 875. 爱吃香蕉的珂珂 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 爱吃香蕉的珂珂 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.minEatingSpeed(new int[] { 3, 6, 7, 11 }, 8)); - Assertions.assertEquals(30, s.minEatingSpeed(new int[] { 30, 11, 23, 4, 20 }, 5)); - Assertions.assertEquals(23, s.minEatingSpeed(new int[] { 30, 11, 23, 4, 20 }, 6)); - Assertions.assertEquals(2, s.minEatingSpeed(new int[] { 312884470 }, 312884469)); - Assertions.assertEquals(3, s.minEatingSpeed(new int[] { 805306368, 805306368, 805306368 }, 1000000000)); - Assertions.assertEquals(14, s.minEatingSpeed( - new int[] { 332484035, 524908576, 855865114, 632922376, 222257295, 690155293, 112677673, 679580077, - 337406589, 290818316, 877337160, 901728858, 679284947, 688210097, 692137887, 718203285, 629455728, - 941802184 }, 823855818)); - } - - static class Solution { - - public int minEatingSpeed(int[] piles, int h) { - int left = 1, right = 1_000_000_000; - - // right 是闭区间,所以这里改成 <= - while (left <= right) { - int mid = left + (right - left) / 2; - if (f(piles, mid) <= h) { - // right 是闭区间,所以这里用 mid - 1 - right = mid - 1; - } else if (f(piles, mid) > h) { - left = mid + 1; - } - } - return left; - } - - long f(int[] nums, int x) { - long h = 0; - for (int num : nums) { - h += num / x; - if (num % x > 0) { h++; } - } - return h; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" deleted file mode 100644 index c0266ae..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/bsearch/\347\273\237\350\256\241\347\233\256\346\240\207\346\210\220\347\273\251\347\232\204\345\207\272\347\216\260\346\254\241\346\225\260.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.array.bsearch; - -import org.junit.jupiter.api.Assertions; - -/** - * LCR 172. 统计目标成绩的出现次数 - * - * @author Zhang Peng - * @date 2025-10-15 - */ -public class 统计目标成绩的出现次数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.countTarget(new int[] { 2, 2, 3, 4, 4, 4, 5, 6, 6, 8 }, 4)); - Assertions.assertEquals(0, s.countTarget(new int[] { 1, 2, 3, 5, 7, 9 }, 6)); - } - - static class Solution { - - public int countTarget(int[] scores, int target) { - int leftBound = searchLeft(scores, target); - if (leftBound == -1) { return 0; } - int cnt = 1; - for (int i = leftBound + 1; i < scores.length; i++) { - if (scores[i] == target) { - cnt++; - } - } - return cnt; - } - - public int searchLeft(int[] nums, int target) { - int res = -1; - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { - right = mid - 1; - } else if (nums[mid] == target) { - right = mid - 1; - res = mid; - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList1.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList1.java" deleted file mode 100644 index 1787652..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/demo/\346\250\241\346\213\237ArrayList1.java" +++ /dev/null @@ -1,104 +0,0 @@ -package io.github.dunwu.algorithm.array.demo; - -import java.util.Arrays; - -/** - * 1) 数组的插入、删除、按照下标随机访问操作; 2)数组中的数据是int类型的; - *

- * Author: Zheng modify: xing, Gsealy - */ -public class 模拟ArrayList1 { - - //定义整型数据data保存数据 - public int data[]; - //定义数组长度 - private int n; - //定义中实际个数 - private int count; - - //构造方法,定义数组大小 - public 模拟ArrayList1(int capacity) { - this.data = new int[capacity]; - this.n = capacity; - this.count = 0;//一开始一个数都没有存所以为0 - } - - //根据索引,找到数据中的元素并返回 - public int find(int index) { - if (index < 0 || index >= count) return -1; - return data[index]; - } - - //插入元素:头部插入,尾部插入 - public boolean insert(int index, int value) { - //数组中无元素 - - //if (index == count && count == 0) { - // data[index] = value; - // ++count; - // return true; - //} - - // 数组空间已满 - if (count == n) { - System.out.println("动态扩容"); - data = Arrays.copyOf(data, n << 1); - } - // 如果count还没满,那么就可以插入数据到数组中 - // 位置不合法 - if (index < 0 || index > count) { - System.out.println("位置不合法"); - return false; - } - // 位置合法 - for (int i = count; i > index; --i) { - data[i] = data[i - 1]; - } - data[index] = value; - ++count; - return true; - } - - //根据索引,删除数组中元素 - public boolean delete(int index) { - if (index < 0 || index >= count) return false; - //从删除位置开始,将后面的元素向前移动一位 - for (int i = index + 1; i < count; ++i) { - data[i - 1] = data[i]; - } - //删除数组末尾元素 这段代码不需要也可以 - /*int[] arr = new int[count-1]; - for (int i=0; i { - - private T[] data; - private int size; - - // 根据传入容量,构造Array - public 模拟ArrayList2(int capacity) { - data = (T[]) new Object[capacity]; - size = 0; - } - - // 无参构造方法,默认数组容量为10 - public 模拟ArrayList2() { - this(10); - } - - // 获取数组容量 - public int getCapacity() { - return data.length; - } - - // 获取当前元素个数 - public int count() { - return size; - } - - // 判断数组是否为空 - public boolean isEmpty() { - return size == 0; - } - - // 修改 index 位置的元素 - public void set(int index, T e) { - checkIndex(index); - data[index] = e; - } - - // 获取对应 index 位置的元素 - public T get(int index) { - checkIndex(index); - return data[index]; - } - - // 查看数组是否包含元素e - public boolean contains(T e) { - for (int i = 0; i < size; i++) { - if (data[i].equals(e)) { - return true; - } - } - return false; - } - - // 获取对应元素的下标, 未找到,返回 -1 - public int find(T e) { - for (int i = 0; i < size; i++) { - if (data[i].equals(e)) { - return i; - } - } - return -1; - } - - // 在 index 位置,插入元素e, 时间复杂度 O(m+n) - public void add(int index, T e) { - checkIndexForAdd(index); - // 如果当前元素个数等于数组容量,则将数组扩容为原来的2倍 - if (size == data.length) { - resize(2 * data.length); - } - - for (int i = size - 1; i >= index; i--) { - data[i + 1] = data[i]; - } - data[index] = e; - size++; - } - - // 向数组头插入元素 - public void addFirst(T e) { - add(0, e); - } - - // 向数组尾插入元素 - public void addLast(T e) { - add(size, e); - } - - // 删除 index 位置的元素,并返回 - public T remove(int index) { - checkIndex(index); - - T ret = data[index]; - for (int i = index + 1; i < size; i++) { - data[i - 1] = data[i]; - } - size--; - data[size] = null; - - // 缩容 - if (size == data.length / 4 && data.length / 2 != 0) { - resize(data.length / 2); - } - - return ret; - } - - // 删除第一个元素 - public T removeFirst() { - return remove(0); - } - - // 删除末尾元素 - public T removeLast() { - return remove(size - 1); - } - - // 从数组中删除指定元素 - public void removeElement(T e) { - int index = find(e); - if (index != -1) { - remove(index); - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length)); - builder.append('['); - for (int i = 0; i < size; i++) { - builder.append(data[i]); - if (i != size - 1) { - builder.append(", "); - } - } - builder.append(']'); - return builder.toString(); - } - - // 扩容方法,时间复杂度 O(n) - private void resize(int capacity) { - T[] newData = (T[]) new Object[capacity]; - - for (int i = 0; i < size; i++) { - newData[i] = data[i]; - } - data = newData; - } - - private void checkIndex(int index) { - if (index < 0 || index >= size) { - throw new IllegalArgumentException("Add failed! Require index >=0 and index < size."); - } - } - - private void checkIndexForAdd(int index) { - if (index < 0 || index > size) { - throw new IllegalArgumentException("remove failed! Require index >=0 and index <= size."); - } - } - - public void printAll() { - for (int i = 0; i < this.size; ++i) { - System.out.print(data[i] + " "); - } - System.out.println(); - } - - public static void main(String[] args) { - 模拟ArrayList2 array = new 模拟ArrayList2<>(5); - array.printAll(); - array.add(0, 3); - array.printAll(); - array.add(0, 4); - array.printAll(); - array.add(1, 5); - array.printAll(); - array.add(3, 9); - array.printAll(); - array.add(3, 10); - array.printAll(); - // array.add(0, 3); - // array.printAll(); - array.resize(10); - array.add(0, 3); - array.printAll(); - array.remove(array.count() - 1); - array.printAll(); - array.remove(0); - array.printAll(); - array.removeElement(4); - array.printAll(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" deleted file mode 100644 index 2a10b4a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215.java" +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.dunwu.algorithm.array.matrix; - -import org.junit.jupiter.api.Assertions; - -/** - * 151. 反转字符串中的单词 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 反转字符串中的单词 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals("blue is sky the", s.reverseWords("the sky is blue")); - Assertions.assertEquals("world hello", s.reverseWords(" hello world ")); - Assertions.assertEquals("example good a", s.reverseWords("a good example")); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals("blue is sky the", s2.reverseWords("the sky is blue")); - Assertions.assertEquals("world hello", s2.reverseWords(" hello world ")); - Assertions.assertEquals("example good a", s2.reverseWords("a good example")); - } - - // 利用库函数 - static class Solution { - - public String reverseWords(String s) { - String[] arr = s.trim().split(" "); - StringBuilder sb = new StringBuilder(); - for (int i = arr.length - 1; i >= 0; i--) { - if (arr[i].equals("")) { - continue; - } - sb.append(arr[i]).append(" "); - } - return sb.toString().trim(); - } - - } - - // 双指针 - static class Solution2 { - - public String reverseWords(String s) { - // 删除首尾空格 - s = s.trim(); - int l = s.length() - 1, r = l; - StringBuilder res = new StringBuilder(); - while (l >= 0) { - // 左指针偏移,直到遇到空格 - while (l >= 0 && s.charAt(l) != ' ') { l--; } - // 添加单词 - res.append(s.substring(l + 1, r + 1)).append(' '); - // 左指针偏移,直到遇到非空格 - while (l >= 0 && s.charAt(l) == ' ') { l--; } - // 右指针对齐左指针 - r = l; - } - return res.toString().trim(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" deleted file mode 100644 index 9d3c672..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\345\257\271\350\247\222\347\272\277\351\201\215\345\216\206.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.array.matrix; - -import org.junit.jupiter.api.Assertions; - -/** - * 498. 对角线遍历 - * - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 对角线遍历 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[][] input = { { 1, 2 }, { 3, 4 } }; - int[] expect = { 1, 2, 3, 4 }; - - int[][] input2 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - int[] expect2 = { 1, 2, 4, 7, 5, 3, 6, 8, 9 }; - - int[][] input3 = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 16 } }; - int[] expect3 = { 1, 2, 5, 9, 6, 3, 4, 7, 10, 13, 14, 11, 8, 12, 15, 16 }; - - Assertions.assertArrayEquals(expect, s.findDiagonalOrder(input)); - Assertions.assertArrayEquals(expect2, s.findDiagonalOrder(input2)); - Assertions.assertArrayEquals(expect3, s.findDiagonalOrder(input3)); - } - - static class Solution { - - // 1. 同一对角线上的元素,满足 i + j = k - // 2. k 的大小,满足递增,从 0 到 m + n - 2 - // 3. 由于,i + j = k -> i = k - j - // i = m - 1 时最大,j 最小;而 k - (m - 1) 必须大于 0 => minJ = max(0, k - (m - 1)) - // i = 0 时最小,j 最大,但不能超过 n - 1 => maxJ = Math.max(k, n -1) - public int[] findDiagonalOrder(int[][] mat) { - - // base case - if (mat == null || mat.length == 0) { return new int[0]; } - - int idx = 0; - int m = mat.length, n = mat[0].length; - int[] res = new int[m * n]; - for (int k = 0; k < m + n - 1; k++) { - int minJ = Math.max(k - (m - 1), 0); - int maxJ = Math.min(k, n - 1); - if (k % 2 == 0) { - for (int j = minJ; j <= maxJ; j++) { - res[idx++] = mat[k - j][j]; - } - } else { - for (int j = maxJ; j >= minJ; j--) { - res[idx++] = mat[k - j][j]; - } - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\346\227\213\350\275\254\345\233\276\345\203\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\346\227\213\350\275\254\345\233\276\345\203\217.java" deleted file mode 100644 index b4bdd6d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\346\227\213\350\275\254\345\233\276\345\203\217.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.array.matrix; - -import cn.hutool.core.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -/** - * LCR 006. 两数之和 II - 输入有序数组 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 旋转图像 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - s.rotate(matrix); - int[][] expect = { { 7, 4, 1 }, { 8, 5, 2 }, { 9, 6, 3 } }; - Assertions.assertTrue(ArrayUtil.equals(expect, matrix)); - - int[][] matrix2 = { { 5, 1, 9, 11 }, { 2, 4, 8, 10 }, { 13, 3, 6, 7 }, { 15, 14, 12, 16 } }; - s.rotate(matrix2); - int[][] expect2 = { { 15, 13, 2, 5 }, { 14, 3, 4, 1 }, { 12, 6, 8, 9 }, { 16, 7, 10, 11 } }; - Assertions.assertTrue(ArrayUtil.equals(expect2, matrix2)); - } - - static class Solution { - - public void rotate(int[][] matrix) { - if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return; } - int n = matrix.length; - // 沿对角线置换 - for (int i = 0; i < n; i++) { - for (int j = 0; j < i; j++) { - int temp = matrix[i][j]; - matrix[i][j] = matrix[j][i]; - matrix[j][i] = temp; - } - } - - for (int i = 0; i < n; i++) { - int left = 0, right = n - 1; - while (left < right) { - int temp = matrix[i][left]; - matrix[i][left] = matrix[i][right]; - matrix[i][right] = temp; - left++; - right--; - } - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" deleted file mode 100644 index e0085df..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\265.java" +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.dunwu.algorithm.array.matrix; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 54. 螺旋矩阵 - * - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 螺旋矩阵 { - - public static void main(String[] args) { - Solution s = new Solution(); - List output = s.spiralOrder(new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 6, 9, 8, 7, 4, 5 }, output.toArray()); - List output2 = s.spiralOrder(new int[][] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7 }, output2.toArray()); - } - - static class Solution { - - public List spiralOrder(int[][] matrix) { - if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) { - return new LinkedList<>(); - } - - int m = matrix.length, n = matrix[0].length; - int up = 0, down = m - 1, left = 0, right = n - 1; - List res = new LinkedList<>(); - while (res.size() < m * n) { - // 向右 - if (up <= down) { - for (int i = left; i <= right; i++) { - res.add(matrix[up][i]); - } - up++; - } - // System.out.printf("\t [right] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); - // 向下 - if (left <= right) { - for (int i = up; i <= down; i++) { - res.add(matrix[i][right]); - } - right--; - } - // System.out.printf("\t [down] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); - // 向左 - if (up <= down) { - for (int i = right; i >= left; i--) { - res.add(matrix[down][i]); - } - down--; - } - // System.out.printf("\t [left] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); - // 向上 - if (left <= right) { - for (int i = down; i >= up; i--) { - res.add(matrix[i][left]); - } - left++; - } - // System.out.printf("\t [up] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); - // System.out.printf("res: %s\n", JSONUtil.toJsonStr(res)); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" deleted file mode 100644 index 785f236..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\347\237\251\351\230\2652.java" +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.array.matrix; - -import org.junit.jupiter.api.Assertions; - -/** - * 54. 螺旋矩阵 - * - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 螺旋矩阵2 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] output = s.generateMatrix(3); - Assertions.assertArrayEquals(new int[][] { { 1, 2, 3 }, { 8, 9, 4 }, { 7, 6, 5 } }, output); - int[][] output2 = s.generateMatrix(1); - Assertions.assertArrayEquals(new int[][] { { 1 } }, output2); - } - - static class Solution { - - public int[][] generateMatrix(int n) { - int cnt = 0; - int[][] res = new int[n][n]; - int left = 0, right = n - 1, top = 0, bottom = n - 1; - while (cnt < n * n) { - - // 向右 - if (top <= bottom) { - for (int i = left; i <= right; i++) { - res[top][i] = ++cnt; - } - top++; - } - - // 向下 - if (left <= right) { - for (int i = top; i <= bottom; i++) { - res[i][right] = ++cnt; - } - right--; - } - - // 向左 - if (top <= bottom) { - for (int i = right; i >= left; i--) { - res[bottom][i] = ++cnt; - } - bottom--; - } - - // 向上 - if (left <= right) { - for (int i = bottom; i >= top; i--) { - res[i][left] = ++cnt; - } - left++; - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\351\201\215\345\216\206\344\272\214\347\273\264\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\351\201\215\345\216\206\344\272\214\347\273\264\346\225\260\347\273\204.java" deleted file mode 100644 index c39ed1a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\350\236\272\346\227\213\351\201\215\345\216\206\344\272\214\347\273\264\346\225\260\347\273\204.java" +++ /dev/null @@ -1,84 +0,0 @@ -package io.github.dunwu.algorithm.array.matrix; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 54. 螺旋矩阵 - * - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 螺旋遍历二维数组 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[] output = s.spiralArray(new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }); - Assertions.assertArrayEquals(new int[] { 1, 2, 3, 6, 9, 8, 7, 4, 5 }, output); - int[] output2 = s.spiralArray(new int[][] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }); - Assertions.assertArrayEquals(new int[] { 1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7 }, output2); - } - - static class Solution { - - public int[] spiralArray(int[][] array) { - List list = spiralOrder(array); - int[] res = new int[list.size()]; - for (int i = 0; i < list.size(); i++) { - res[i] = list.get(i); - } - return res; - } - - public List spiralOrder(int[][] matrix) { - if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) { - return new LinkedList<>(); - } - - int m = matrix.length, n = matrix[0].length; - int up = 0, down = m - 1; - int left = 0, right = n - 1; - List res = new LinkedList<>(); - while (res.size() < m * n) { - // 向右 - if (up <= down) { - for (int i = left; i <= right; i++) { - res.add(matrix[up][i]); - } - up++; - } - // System.out.printf("\t [right] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); - // 向下 - if (left <= right) { - for (int i = up; i <= down; i++) { - res.add(matrix[i][right]); - } - right--; - } - // System.out.printf("\t [down] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); - // 向左 - if (up <= down) { - for (int i = right; i >= left; i--) { - res.add(matrix[down][i]); - } - down--; - } - // System.out.printf("\t [left] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); - // 向上 - if (left <= right) { - for (int i = down; i >= up; i--) { - res.add(matrix[i][left]); - } - left++; - } - // System.out.printf("\t [up] up: %d, down: %d, left: %d, right: %d\n", up, down, left, right); - // System.out.printf("res: %s\n", JSONUtil.toJsonStr(res)); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\351\233\266\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\351\233\266\347\237\251\351\230\265.java" deleted file mode 100644 index 6c7d535..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/matrix/\351\233\266\347\237\251\351\230\265.java" +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.dunwu.algorithm.array.matrix; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 08. 零矩阵 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 零矩阵 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] input = { - { 1, 1, 1 }, - { 1, 0, 1 }, - { 1, 1, 1 } - }; - int[][] expect = { - { 1, 0, 1 }, - { 0, 0, 0 }, - { 1, 0, 1 } - }; - s.setZeroes(input); - Assertions.assertArrayEquals(expect, input); - } - - static class Solution { - - public void setZeroes(int[][] matrix) { - int m = matrix.length, n = matrix[0].length; - LinkedList queue = new LinkedList<>(); - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (matrix[i][j] == 0) { - queue.offer(new int[] { i, j }); - } - } - } - - while (!queue.isEmpty()) { - int[] point = queue.poll(); - int x = point[0], y = point[1]; - for (int i = 0; i < n; i++) { matrix[x][i] = 0; } - for (int i = 0; i < m; i++) { matrix[i][y] = 0; } - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" deleted file mode 100644 index 61ece6f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\344\272\214\347\273\264\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\347\237\251\351\230\265\344\270\215\345\217\257\345\217\230.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.array.range; - -import org.junit.jupiter.api.Assertions; - -/** - * 303. 区域和检索 - 数组不可变 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 二维区域和检索_矩阵不可变 { - - public static void main(String[] args) { - NumMatrix numMatrix = new NumMatrix(new int[][] { - { 3, 0, 1, 4, 2 }, - { 5, 6, 3, 2, 1 }, - { 1, 2, 0, 1, 5 }, - { 4, 1, 0, 1, 7 }, - { 1, 0, 3, 0, 5 } - }); - Assertions.assertEquals(8, numMatrix.sumRegion(2, 1, 4, 3)); - Assertions.assertEquals(11, numMatrix.sumRegion(1, 1, 2, 2)); - Assertions.assertEquals(12, numMatrix.sumRegion(1, 2, 2, 4)); - } - - static class NumMatrix { - - // preSum[i][j] 记录矩阵 [0, 0, i-1, j-1] 的元素和 - private int[][] preSum; - - public NumMatrix(int[][] matrix) { - int m = matrix.length, n = matrix[0].length; - if (m == 0 || n == 0) return; - // 构造前缀和矩阵 - preSum = new int[m + 1][n + 1]; - for (int i = 1; i <= m; i++) { - for (int j = 1; j <= n; j++) { - // 计算每个矩阵 [0, 0, i, j] 的元素和 - preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + matrix[i - 1][j - 1] - preSum[i - 1][j - 1]; - } - } - } - - // 计算子矩阵 [x1, y1, x2, y2] 的元素和 - public int sumRegion(int x1, int y1, int x2, int y2) { - // 目标矩阵之和由四个相邻矩阵运算获得 - return preSum[x2 + 1][y2 + 1] - preSum[x1][y2 + 1] - preSum[x2 + 1][y1] + preSum[x1][y1]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" deleted file mode 100644 index 276664c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\214\272\345\237\237\345\222\214\346\243\200\347\264\242_\346\225\260\347\273\204\344\270\215\345\217\257\345\217\230.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.array.range; - -import org.junit.jupiter.api.Assertions; - -/** - * 303. 区域和检索 - 数组不可变 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 区域和检索_数组不可变 { - - public static void main(String[] args) { - NumArray numArray = new NumArray(new int[] { -2, 0, 3, -5, 2, -1 }); - Assertions.assertEquals(1, numArray.sumRange(0, 2)); - Assertions.assertEquals(-1, numArray.sumRange(2, 5)); - Assertions.assertEquals(-3, numArray.sumRange(0, 5)); - } - - static class NumArray { - - private int[] preSum; - - public NumArray(int[] nums) { - preSum = new int[nums.length + 1]; - for (int i = 1; i <= nums.length; i++) { - preSum[i] = preSum[i - 1] + nums[i - 1]; - } - } - - public int sumRange(int left, int right) { - return preSum[right + 1] - preSum[left]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" deleted file mode 100644 index c7d8c6b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\257\273\346\211\276\346\225\260\347\273\204\347\232\204\344\270\255\345\277\203\347\264\242\345\274\225.java" +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.array.range; - -import org.junit.jupiter.api.Assertions; - -/** - * 724. 寻找数组的中心索引 - * - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 寻找数组的中心索引 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.pivotIndex(new int[] { 1, 7, 3, 6, 5, 6 })); - Assertions.assertEquals(-1, s.pivotIndex(new int[] { 1, 2, 3 })); - Assertions.assertEquals(0, s.pivotIndex(new int[] { 2, 1, -1 })); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(3, s2.pivotIndex(new int[] { 1, 7, 3, 6, 5, 6 })); - Assertions.assertEquals(-1, s2.pivotIndex(new int[] { 1, 2, 3 })); - Assertions.assertEquals(0, s2.pivotIndex(new int[] { 2, 1, -1 })); - } - - static class Solution { - - public int pivotIndex(int[] nums) { - for (int mid = 0; mid < nums.length; mid++) { - int leftSum = 0, rightSum = 0; - for (int i = 0; i < mid; i++) { - leftSum += nums[i]; - } - for (int i = mid + 1; i < nums.length; i++) { - rightSum += nums[i]; - } - if (leftSum == rightSum) { - return mid; - } - } - return -1; - } - - } - - static class Solution2 { - - public int pivotIndex(int[] nums) { - int total = 0; - for (int num : nums) { - total += num; - } - - int leftSum = 0; - for (int i = 0; i < nums.length; i++) { - int rightSum = total - leftSum - nums[i]; - if (leftSum == rightSum) { - return i; - } - leftSum += nums[i]; - } - return -1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" deleted file mode 100644 index 43dca82..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\345\260\206\346\225\260\347\273\204\345\210\206\346\210\220\345\222\214\347\233\270\347\255\211\347\232\204\344\270\211\344\270\252\351\203\250\345\210\206.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.array.range; - -import org.junit.jupiter.api.Assertions; - -/** - * 1013.将数组分成和相等的三个部分 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 将数组分成和相等的三个部分 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.canThreePartsEqualSum(new int[] { 0, 2, 1, -6, 6, -7, 9, 1, 2, 0, 1 })); - Assertions.assertTrue(s.canThreePartsEqualSum(new int[] { 3, 3, 6, 5, -2, 2, 5, 1, -9, 4 })); - Assertions.assertFalse(s.canThreePartsEqualSum(new int[] { 0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1 })); - } - - static class Solution { - - public boolean canThreePartsEqualSum(int[] arr) { - int n = arr.length; - NumArray preSum = new NumArray(arr); - for (int i = 1; i < n; i++) { - for (int j = i + 1; j < n; j++) { - int leftSum = preSum.sumRange(0, i - 1); - int midSum = preSum.sumRange(i, j - 1); - int rightSum = preSum.sumRange(j, n - 1); - if (leftSum == midSum && midSum == rightSum) { - return true; - } - } - } - return false; - } - - static class NumArray { - - private final int[] preSum; - - public NumArray(int[] arr) { - preSum = new int[arr.length + 1]; - preSum[0] = 0; - for (int i = 1; i <= arr.length; i++) { - preSum[i] = preSum[i - 1] + arr[i - 1]; - } - } - - public int sumRange(int left, int right) { - return preSum[right + 1] - preSum[left]; - } - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" deleted file mode 100644 index 6ea1646..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\346\213\274\350\275\246.java" +++ /dev/null @@ -1,94 +0,0 @@ -package io.github.dunwu.algorithm.array.range; - -import org.junit.jupiter.api.Assertions; - -/** - * 1094. 屁车 - * - * @author Zhang Peng - * @date 2025-10-17 - */ -public class 拼车 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] input = { { 2, 1, 5 }, { 3, 3, 7 } }; - Assertions.assertFalse(s.carPooling(input, 3)); - int[][] input2 = { { 1, 2, 10 }, { 2, 2, 15 } }; - Assertions.assertTrue(s.carPooling(input2, 5)); - int[][] input3 = { { 2, 1, 5 }, { 3, 5, 7 } }; - Assertions.assertTrue(s.carPooling(input3, 3)); - } - - static class Solution { - - public boolean carPooling(int[][] trips, int capacity) { - // 最多有 1000 个车站 - int[] nums = new int[1001]; - // 构造差分解法 - Difference df = new Difference(nums); - - for (int[] trip : trips) { - // 乘客数量 - int val = trip[0]; - // 第 trip[1] 站乘客上车 - int i = trip[1]; - // 第 trip[2] 站乘客已经下车, - // 即乘客在车上的区间是 [trip[1], trip[2] - 1] - int j = trip[2] - 1; - // 进行区间操作 - df.increment(i, j, val); - } - - int[] res = df.result(); - - // 客车自始至终都不应该超载 - for (int i = 0; i < res.length; i++) { - if (capacity < res[i]) { - return false; - } - } - return true; - } - - // 差分数组工具类 - class Difference { - - // 差分数组 - private int[] diff; - - // 输入一个初始数组,区间操作将在这个数组上进行 - public Difference(int[] nums) { - assert nums.length > 0; - diff = new int[nums.length]; - // 根据初始数组构造差分数组 - diff[0] = nums[0]; - for (int i = 1; i < nums.length; i++) { - diff[i] = nums[i] - nums[i - 1]; - } - } - - // 给闭区间 [i, j] 增加 val(可以是负数) - public void increment(int i, int j, int val) { - diff[i] += val; - if (j + 1 < diff.length) { - diff[j + 1] -= val; - } - } - - // 返回结果数组 - public int[] result() { - int[] res = new int[diff.length]; - // 根据差分数组构造结果数组 - res[0] = diff[0]; - for (int i = 1; i < diff.length; i++) { - res[i] = res[i - 1] + diff[i]; - } - return res; - } - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" deleted file mode 100644 index bb51080..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/range/\350\210\252\347\217\255\351\242\204\350\256\242\347\273\237\350\256\241.java" +++ /dev/null @@ -1,76 +0,0 @@ -package io.github.dunwu.algorithm.array.range; - -import org.junit.jupiter.api.Assertions; - -/** - * 1109. 航班预订统计 - * - * @author Zhang Peng - * @date 2025-10-17 - */ -public class 航班预订统计 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[][] bookings = { { 1, 2, 10 }, { 2, 3, 20 }, { 2, 5, 25 } }; - Assertions.assertArrayEquals(new int[] { 10, 55, 45, 25, 25 }, s.corpFlightBookings(bookings, 5)); - - int[][] bookings2 = { { 1, 2, 10 }, { 2, 2, 15 } }; - Assertions.assertArrayEquals(new int[] { 10, 25 }, s.corpFlightBookings(bookings2, 2)); - } - - static class Solution { - - public int[] corpFlightBookings(int[][] bookings, int n) { - int[] nums = new int[n]; - Difference df = new Difference(nums); - for (int[] booking : bookings) { - int first = booking[0], last = booking[1], seat = booking[2]; - df.increment(first - 1, last - 1, seat); - } - return df.result(); - } - - // 差分数组工具类 - static class Difference { - - // 差分数组 - private final int[] diff; - - // 输入一个初始数组,区间操作将在这个数组上进行 - public Difference(int[] nums) { - assert nums.length > 0; - diff = new int[nums.length]; - // 根据初始数组构造差分数组 - diff[0] = nums[0]; - for (int i = 1; i < nums.length; i++) { - diff[i] = nums[i] - nums[i - 1]; - } - } - - // 给闭区间 [i, j] 增加 val(可以是负数) - public void increment(int i, int j, int val) { - diff[i] += val; - if (j + 1 < diff.length) { - diff[j + 1] -= val; - } - } - - // 返回结果数组 - public int[] result() { - int[] res = new int[diff.length]; - // 根据差分数组构造结果数组 - res[0] = diff[0]; - for (int i = 1; i < diff.length; i++) { - res[i] = res[i - 1] + diff[i]; - } - return res; - } - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\344\272\214\345\210\206\346\237\245\346\211\276\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\344\272\214\345\210\206\346\237\245\346\211\276\346\250\241\346\235\277.java" deleted file mode 100644 index 7f21032..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\344\272\214\345\210\206\346\237\245\346\211\276\346\250\241\346\235\277.java" +++ /dev/null @@ -1,70 +0,0 @@ -package io.github.dunwu.algorithm.array.template; - -/** - * 二分查找模板 - * - * @author Zhang Peng - * @date 2025-12-08 - */ -public class 二分查找模板 { - - int binary_search(int[] nums, int target) { - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { - right = mid - 1; - } else if (nums[mid] == target) { - // 直接返回 - return mid; - } - } - // 直接返回 - return -1; - } - - int left_bound(int[] nums, int target) { - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { - right = mid - 1; - } else if (nums[mid] == target) { - // 别返回,锁定左侧边界 - right = mid - 1; - } - } - // 判断 target 是否存在于 nums 中 - if (left < 0 || left >= nums.length) { - return -1; - } - // 判断一下 nums[left] 是不是 target - return nums[left] == target ? left : -1; - } - - int right_bound(int[] nums, int target) { - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - if (nums[mid] < target) { - left = mid + 1; - } else if (nums[mid] > target) { - right = mid - 1; - } else if (nums[mid] == target) { - // 别返回,锁定右侧边界 - left = mid + 1; - } - } - // 由于 while 的结束条件是 right == left - 1,且现在在求右边界 - // 所以用 right 替代 left - 1 更好记 - if (right < 0 || right >= nums.length) { - return -1; - } - return nums[right] == target ? right : -1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" deleted file mode 100644 index 7c37f55..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\211\215\347\274\200\345\222\214\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.dunwu.algorithm.array.template; - -/** - * 前缀和数组代码模板 - * - * @author Zhang Peng - * @date 2025-10-20 - */ -public class 前缀和数组代码模板 { - - /** - * 一维前缀和 - */ - static class NumArray { - - // 前缀和数组 - private final int[] preSum; - - // 输入一个数组,构造前缀和 - public NumArray(int[] nums) { - // preSum[0] = 0,便于计算累加和 - preSum = new int[nums.length + 1]; - // 计算 nums 的累加和 - for (int i = 1; i < preSum.length; i++) { - preSum[i] = preSum[i - 1] + nums[i - 1]; - } - } - - // 查询闭区间 [left, right] 的累加和 - public int sumRange(int left, int right) { - return preSum[right + 1] - preSum[left]; - } - - } - - /** - * 二维前缀和 - */ - static class NumMatrix { - - // preSum[i][j] 记录矩阵 [0, 0, i-1, j-1] 的元素和 - private int[][] preSum; - - public NumMatrix(int[][] matrix) { - int m = matrix.length, n = matrix[0].length; - if (m == 0 || n == 0) return; - // 构造前缀和矩阵 - preSum = new int[m + 1][n + 1]; - for (int i = 1; i <= m; i++) { - for (int j = 1; j <= n; j++) { - // 计算每个矩阵 [0, 0, i, j] 的元素和 - preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + matrix[i - 1][j - 1] - preSum[i - 1][j - 1]; - } - } - } - - // 计算子矩阵 [x1, y1, x2, y2] 的元素和 - public int sumRegion(int x1, int y1, int x2, int y2) { - // 目标矩阵之和由四个相邻矩阵运算获得 - return preSum[x2 + 1][y2 + 1] - preSum[x1][y2 + 1] - preSum[x2 + 1][y1] + preSum[x1][y1]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" deleted file mode 100644 index bb6a01c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\345\267\256\345\210\206\346\225\260\347\273\204\344\273\243\347\240\201\346\250\241\346\235\277.java" +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.dunwu.algorithm.array.template; - -/** - * 差分数组代码模板 - * - * @author Zhang Peng - * @date 2025-10-20 - */ -public class 差分数组代码模板 { - - // 差分数组工具类 - static class Difference { - - // 差分数组 - private final int[] diff; - - // 输入一个初始数组,区间操作将在这个数组上进行 - public Difference(int[] nums) { - assert nums.length > 0; - diff = new int[nums.length]; - // 根据初始数组构造差分数组 - diff[0] = nums[0]; - for (int i = 1; i < nums.length; i++) { - diff[i] = nums[i] - nums[i - 1]; - } - } - - // 给闭区间 [i, j] 增加 val(可以是负数) - public void increment(int i, int j, int val) { - diff[i] += val; - if (j + 1 < diff.length) { - diff[j + 1] -= val; - } - } - - // 返回结果数组 - public int[] result() { - int[] res = new int[diff.length]; - // 根据差分数组构造结果数组 - res[0] = diff[0]; - for (int i = 1; i < diff.length; i++) { - res[i] = res[i - 1] + diff[i]; - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\346\273\221\345\212\250\347\252\227\345\217\243\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\346\273\221\345\212\250\347\252\227\345\217\243\346\250\241\346\235\277.java" deleted file mode 100644 index 66a46d4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/template/\346\273\221\345\212\250\347\252\227\345\217\243\346\250\241\346\235\277.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.array.template; - -/** - * 滑动窗口模板 - * - * @author Zhang Peng - * @date 2025-11-20 - */ -public class 滑动窗口模板 { - - // 滑动窗口算法伪码框架 - // void slidingWindow(String s) { - // // 用合适的数据结构记录窗口中的数据,根据具体场景变通 - // // 比如说,我想记录窗口中元素出现的次数,就用 map - // // 如果我想记录窗口中的元素和,就可以只用一个 int - // Object window = ... - // - // int left = 0, right = 0; - // while (right < s.length()) { - // // c 是将移入窗口的字符 - // char c = s[right]; - // window.add(c) - // // 增大窗口 - // right++; - // // 进行窗口内数据的一系列更新 - // // ... - // - // // *** debug 输出的位置 *** - // // 注意在最终的解法代码中不要 print - // // 因为 IO 操作很耗时,可能导致超时 - // printf("window: [%d, %d)\n", left, right); - // // *********************** - // - // // 判断左侧窗口是否要收缩 - // while (left < right && window needs shrink){ - // // d 是将移出窗口的字符 - // char d = s[left]; - // window.remove(d) - // // 缩小窗口 - // left++; - // // 进行窗口内数据的一系列更新 - // ... - // } - // } - // } -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" deleted file mode 100644 index bb147b7..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\211\346\225\260\344\271\213\345\222\214.java" +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * - * 三数之和 - * - * @author Zhang Peng - * @since 2020-01-18 - */ -public class 三数之和 { - - public static void main(String[] args) { - Solution s = new Solution(); - List> input = s.threeSum(new int[] { -1, 0, 1, 2, -1, -4 }); - List> expect = new ArrayList<>(); - expect.add(Arrays.asList(-1, -1, 2)); - expect.add(Arrays.asList(-1, 0, 1)); - Assertions.assertArrayEquals(expect.toArray(), input.toArray()); - } - - static class Solution { - - public List> threeSum(int[] nums) { - if (nums == null || nums.length < 3) { return new ArrayList<>(); } - - // 数组排序 - Arrays.sort(nums); - - List> res = new ArrayList<>(); - for (int i = 0; i < nums.length; i++) { - - // 跳过重复元素 - if (i > 0 && nums[i] == nums[i - 1]) { continue; } - - // 双指针,目标是找到 nums[l] + nums[r] = -nums[i] - int target = -nums[i]; - int l = i + 1, r = nums.length - 1; - - while (l < r) { - int sum = nums[l] + nums[r]; - if (sum == target) { - res.add(Arrays.asList(nums[i], nums[l], nums[r])); - l++; - r--; - // 跳过重复元素 - while (l < r && nums[l] == nums[l - 1]) l++; - while (l < r && nums[r] == nums[r + 1]) r--; - } else if (sum > target) { - r--; - } else if (sum < target) { - l++; - } - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\214.java" deleted file mode 100644 index 27e751f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\214.java" +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 1. 两数之和 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 两数之和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 0, 1 }, s.twoSum(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, s.twoSum(new int[] { 3, 2, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 0, 1 }, s.twoSum(new int[] { 3, 3 }, 6)); - - Solution2 s2 = new Solution2(); - Assertions.assertArrayEquals(new int[] { 0, 1 }, s2.twoSum(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, s2.twoSum(new int[] { 3, 2, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 0, 1 }, s2.twoSum(new int[] { 3, 3 }, 6)); - } - - /** - * 两次 for 循环暴力求解,时间复杂度 o(n^2) - */ - static class Solution { - - public int[] twoSum(int[] nums, int target) { - int n = nums.length; - for (int i = 0; i < n; i++) { - for (int j = i + 1; j < n; j++) { - if (nums[i] + nums[j] == target) { - return new int[] { i, j }; - } - } - } - return new int[0]; - } - - } - - /** - * Hash 存值、下标,一次 for 循环,每次判断 map 中是否有值和当前下标的值凑成 target - */ - static class Solution2 { - - public int[] twoSum(int[] nums, int target) { - Map map = new HashMap<>(nums.length); - for (int i = 0; i < nums.length; i++) { - int diff = target - nums[i]; - if (map.containsKey(diff)) { - return new int[] { map.get(diff), i }; - } else { - map.put(nums[i], i); - } - } - return new int[0]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\2142.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\2142.java" deleted file mode 100644 index 2585dda..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\270\244\346\225\260\344\271\213\345\222\2142.java" +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 167. 两数之和 II - 输入有序数组 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 两数之和2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 1, 2 }, s.twoSum(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 3 }, s.twoSum(new int[] { 2, 3, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, s.twoSum(new int[] { -1, 0 }, -1)); - - Solution2 s2 = new Solution2(); - Assertions.assertArrayEquals(new int[] { 1, 2 }, s2.twoSum(new int[] { 2, 7, 11, 15 }, 9)); - Assertions.assertArrayEquals(new int[] { 1, 3 }, s2.twoSum(new int[] { 2, 3, 4 }, 6)); - Assertions.assertArrayEquals(new int[] { 1, 2 }, s2.twoSum(new int[] { -1, 0 }, -1)); - } - - /** - * Hash 存值、下标,一次 for 循环,每次判断 map 中是否有值和当前下标的值凑成 target - */ - static class Solution { - - public int[] twoSum(int[] nums, int target) { - Map map = new HashMap<>(nums.length); - for (int i = 0; i < nums.length; i++) { - int diff = target - nums[i]; - if (map.containsKey(diff)) { - return new int[] { map.get(diff), i + 1 }; - } else { - map.put(nums[i], i + 1); - } - } - return new int[0]; - } - - } - - /** - * 双指针 - */ - static class Solution2 { - - public int[] twoSum(int[] nums, int target) { - int left = 0, right = nums.length - 1; - while (left < right) { - if (nums[left] + nums[right] == target) { - return new int[] { left + 1, right + 1 }; - } else if (nums[left] + nums[right] < target) { - left++; - } else { - right--; - } - } - return new int[0]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" deleted file mode 100644 index 1e7c9e1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\347\273\264\347\275\221\346\240\274\350\277\201\347\247\273.java" +++ /dev/null @@ -1,92 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 1260. 二维网格迁移 - * - * @author Zhang Peng - * @date 2025-10-14 - */ -public class 二维网格迁移 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[][] grid1 = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - List> res1 = s.shiftGrid(grid1, 1); - Assertions.assertNotNull(res1); - Assertions.assertArrayEquals(new Integer[] { 9, 1, 2 }, res1.get(0).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 3, 4, 5 }, res1.get(1).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 6, 7, 8 }, res1.get(2).toArray(new Integer[0])); - - int[][] grid2 = new int[][] { { 3, 8, 1, 9 }, { 19, 7, 2, 5 }, { 4, 6, 11, 10 }, { 12, 0, 21, 13 } }; - List> res2 = s.shiftGrid(grid2, 4); - Assertions.assertNotNull(res2); - Assertions.assertArrayEquals(new Integer[] { 12, 0, 21, 13 }, res2.get(0).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 3, 8, 1, 9 }, res2.get(1).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 19, 7, 2, 5 }, res2.get(2).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 4, 6, 11, 10 }, res2.get(3).toArray(new Integer[0])); - - int[][] grid3 = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - List> res3 = s.shiftGrid(grid3, 9); - Assertions.assertNotNull(res3); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, res3.get(0).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 4, 5, 6 }, res3.get(1).toArray(new Integer[0])); - Assertions.assertArrayEquals(new Integer[] { 7, 8, 9 }, res3.get(2).toArray(new Integer[0])); - - int[][] grid4 = new int[][] { { 1 }, { 2 }, { 3 }, { 4 }, { 7 }, { 6 }, { 5 } }; - List> res4 = s.shiftGrid(grid4, 23); - Assertions.assertNotNull(res4); - } - - static class Solution { - - public List> shiftGrid(int[][] grid, int k) { - for (int i = 0; i < k; i++) { - shift(grid); - } - - int m = grid.length, n = grid[0].length; - List> res = new ArrayList<>(); - for (int i = 0; i < m; i++) { - List list = new ArrayList<>(); - res.add(list); - for (int j = 0; j < n; j++) { - list.add(grid[i][j]); - } - } - return res; - } - - public void shift(int[][] grid) { - int m = grid.length, n = grid[0].length; - int last = get(grid, m * n - 1); - for (int i = m * n - 1; i > 0; i--) { - int prev = get(grid, i - 1); - set(grid, i, prev); - } - set(grid, 0, last); - } - - public int get(int[][] grid, int index) { - int n = grid[0].length; - int i = index / n; - int j = index % n; - return grid[i][j]; - } - - public void set(int[][] grid, int index, int val) { - int n = grid[0].length; - int i = index / n; - int j = index % n; - grid[i][j] = val; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" deleted file mode 100644 index 812604b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\344\272\214\350\277\233\345\210\266\346\261\202\345\222\214.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 67. 二进制求和 - * - * @author Zhang Peng - * @date 2025-01-21 - */ -public class 二进制求和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals("100", s.addBinary("11", "1")); - Assertions.assertEquals("10101", s.addBinary("1010", "1011")); - } - - static class Solution { - - public String addBinary(String a, String b) { - int i = a.length() - 1; - int j = b.length() - 1; - int carry = 0; - StringBuilder sb = new StringBuilder(); - while (i >= 0 || j >= 0) { - int numA = i < 0 ? 0 : a.charAt(i--) - '0'; - int numB = j < 0 ? 0 : b.charAt(j--) - '0'; - int sum = numA + numB + carry; - if (sum > 1) { - carry = 1; - sb.append(sum % 2); - } else { - carry = 0; - sb.append(sum); - } - } - if (carry > 0) { - sb.append(carry); - } - return sb.reverse().toString(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" deleted file mode 100644 index ce195a8..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 26. 删除有序数组中的重复项 - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 删除排序数组中的重复项 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.removeDuplicates(new int[] { 1, 1, 2 })); - Assertions.assertEquals(5, s.removeDuplicates(new int[] { 0, 0, 1, 1, 1, 2, 2, 3, 3, 4 })); - Assertions.assertEquals(2, s.removeDuplicates(new int[] { 1, 2 })); - Assertions.assertEquals(1, s.removeDuplicates(new int[] { 2, 2 })); - } - - static class Solution { - - public int removeDuplicates(int[] nums) { - int slow = 0, fast = 1; - while (fast < nums.length) { - if (nums[fast] != nums[slow]) { - slow++; - nums[slow] = nums[fast]; - } - fast++; - } - return slow + 1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\2712.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\2712.java" deleted file mode 100644 index ad47707..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\2712.java" +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 80. 删除有序数组中的重复项 II - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 删除排序数组中的重复项2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(5, s.removeDuplicates(new int[] { 1, 1, 1, 2, 2, 3 })); - Assertions.assertEquals(7, s.removeDuplicates(new int[] { 0, 0, 1, 1, 1, 1, 2, 3, 3 })); - } - - static class Solution { - - public int removeDuplicates(int[] nums) { - int slow = 0, fast = 1; - int cnt = 1; - while (fast < nums.length) { - if (nums[fast] != nums[slow]) { - cnt = 1; - slow++; - nums[slow] = nums[fast]; - } else { - if (cnt < 2) { - slow++; - nums[slow] = nums[fast]; - } - cnt++; - } - fast++; - } - // System.out.printf("slow: %d, fast: %d, nums: %s\n", slow, fast, - // JSONUtil.toJsonStr(ArrayUtil.sub(nums, 0, slow + 1))); - return slow + 1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" deleted file mode 100644 index 75e2bc1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 344. 反转字符串 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 反转字符串 { - - public static void main(String[] args) { - Solution s = new Solution(); - char[] arr1 = new char[] { 'h', 'e', 'l', 'l', 'o' }; - s.reverseString(arr1); - Assertions.assertArrayEquals(new char[] { 'o', 'l', 'l', 'e', 'h' }, arr1); - - char[] arr2 = new char[] { 'H', 'a', 'n', 'n', 'a', 'h' }; - s.reverseString(arr2); - Assertions.assertArrayEquals(new char[] { 'h', 'a', 'n', 'n', 'a', 'H' }, arr2); - } - - static class Solution { - - public void reverseString(char[] s) { - int left = 0, right = s.length - 1; - while (left < right) { - char temp = s[left]; - s[left] = s[right]; - s[right] = temp; - left++; - right--; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" deleted file mode 100644 index 7465ea6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204.java" +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 88. 合并两个有序数组 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 合并两个有序数组 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[] nums1 = new int[] { 1, 2, 3, 0, 0, 0 }; - int[] nums2 = new int[] { 2, 5, 6 }; - s.merge(nums1, 3, nums2, 3); - Assertions.assertArrayEquals(new int[] { 1, 2, 2, 3, 5, 6 }, nums1); - - int[] nums3 = new int[] { 1 }; - int[] nums4 = new int[] {}; - s.merge(nums3, 1, nums4, 0); - Assertions.assertArrayEquals(new int[] { 1 }, nums3); - - int[] nums5 = new int[] { 0 }; - int[] nums6 = new int[] { 1 }; - s.merge(nums5, 0, nums6, 1); - Assertions.assertArrayEquals(new int[] { 1 }, nums5); - - int[] nums7 = new int[] { 4, 5, 6, 0, 0, 0 }; - int[] nums8 = new int[] { 1, 2, 3 }; - s.merge(nums7, 3, nums8, 3); - Assertions.assertArrayEquals(new int[] { 1, 2, 3, 4, 5, 6 }, nums7); - } - - static class Solution { - - public void merge(int[] nums1, int m, int[] nums2, int n) { - // 两个指针分别初始化在两个数组的最后一个元素(类似拉链两端的锯齿) - int i = m - 1, j = n - 1; - // 生成排序的结果(类似拉链的拉锁) - int p = nums1.length - 1; - // 从后向前生成结果数组,类似合并两个有序链表的逻辑 - while (i >= 0 && j >= 0) { - if (nums1[i] >= nums2[j]) { - nums1[p] = nums1[i]; - i--; - } else { - nums1[p] = nums2[j]; - j--; - } - p--; - } - // 可能其中一个数组的指针走到尽头了,而另一个还没走完 - while (i >= 0) { - nums1[p--] = nums1[i--]; - } - while (j >= 0) { - nums1[p--] = nums2[j--]; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\345\214\272\351\227\264.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\345\214\272\351\227\264.java" deleted file mode 100644 index d424a3e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\220\210\345\271\266\345\214\272\351\227\264.java" +++ /dev/null @@ -1,62 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * 56. 合并区间 - * - * @author Zhang Peng - * @since 2020-07-29 - */ -public class 合并区间 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[][] input = new int[][] { { 1, 4 }, { 2, 3 } }; - int[][] expect = new int[][] { { 1, 4 } }; - Assertions.assertArrayEquals(expect, s.merge(input)); - - int[][] input2 = new int[][] { { 1, 3 }, { 2, 6 }, { 8, 10 }, { 15, 18 } }; - int[][] expect2 = new int[][] { { 1, 6 }, { 8, 10 }, { 15, 18 } }; - Assertions.assertArrayEquals(expect2, s.merge(input2)); - - int[][] input3 = new int[][] { { 1, 4 }, { 4, 5 } }; - int[][] expect3 = new int[][] { { 1, 5 } }; - Assertions.assertArrayEquals(expect3, s.merge(input3)); - } - - static class Solution { - - public int[][] merge(int[][] intervals) { - - // base case - if (intervals == null || intervals.length <= 1) { return intervals; } - - // 先按区间下限排序 - Arrays.sort(intervals, (a, b) -> a[0] - b[0]); - - // 设置双指针,扫描 intervals - List merged = new ArrayList<>(); - for (int[] interval : intervals) { - int l = interval[0], r = interval[1]; - int last = merged.size() - 1; - if (last == -1 || merged.get(last)[1] < l) { - merged.add(new int[] { l, r }); - } else { - l = merged.get(last)[0]; - r = Math.max(merged.get(last)[1], r); - merged.set(last, new int[] { l, r }); - } - } - return merged.toArray(new int[merged.size()][2]); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" deleted file mode 100644 index cabacab..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\345\260\206\347\237\251\351\230\265\346\214\211\345\257\271\350\247\222\347\272\277\346\216\222\345\272\217.java" +++ /dev/null @@ -1,70 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.PriorityQueue; - -/** - * 1329. 将矩阵按对角线排序 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 将矩阵按对角线排序 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[][] input1 = { { 3, 3, 1, 1 }, { 2, 2, 1, 2 }, { 1, 1, 1, 2 } }; - int[][] expected1 = { { 1, 1, 1, 1 }, { 1, 2, 2, 2 }, { 1, 2, 3, 3 } }; - int[][] output1 = s.diagonalSort(input1); - Assertions.assertArrayEquals(expected1, output1); - - int[][] input2 = { { 11, 25, 66, 1, 69, 7 }, { 23, 55, 17, 45, 15, 52 }, { 75, 31, 36, 44, 58, 8 }, - { 22, 27, 33, 25, 68, 4 }, { 84, 28, 14, 11, 5, 50 } }; - int[][] expected2 = { { 5, 17, 4, 1, 52, 7 }, { 11, 11, 25, 45, 8, 69 }, { 14, 23, 25, 44, 58, 15 }, - { 22, 27, 31, 36, 50, 66 }, { 84, 28, 75, 33, 55, 68 } }; - int[][] output2 = s.diagonalSort(input2); - Assertions.assertArrayEquals(expected2, output2); - } - - static class Solution { - - public int[][] diagonalSort(int[][] mat) { - - int m = mat.length, n = mat[0].length; - - // 在同一个对角线上的元素,其横纵坐标之差是相同的 - // 存储所有对角线的元素列表,利用 PriorityQueue 自动对对角线元素排序 - Map> map = new HashMap<>(); - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - // 横纵坐标之差可以作为一条对角线的 ID - int diff = i - j; - if (!map.containsKey(diff)) { - map.put(diff, new PriorityQueue<>(Comparator.comparingInt(a -> mat[a[0]][a[1]]))); - } - map.get(diff).add(new int[] { i, j }); - } - } - - // 把排序结果回填二维矩阵 - int[][] res = new int[m][n]; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - int diff = i - j; - PriorityQueue queue = map.get(diff); - int[] point = queue.poll(); - res[i][j] = mat[point[0]][point[1]]; - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" deleted file mode 100644 index 008fb47..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 14. 最长公共前缀 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 最长公共前缀 { - - public static void main(String[] args) { - - Solution s = new Solution(); - String[] input1 = { "flower", "flow", "flight" }; - String expect1 = "fl"; - String output1 = s.longestCommonPrefix(input1); - Assertions.assertEquals(expect1, output1); - - String[] input2 = { "dog", "racecar", "car" }; - String expect2 = ""; - String output2 = s.longestCommonPrefix(input2); - Assertions.assertEquals(expect2, output2); - } - - static class Solution { - - public String longestCommonPrefix(String[] strs) { - int m = strs.length; - // 以第一行的列数为基准 - int n = strs[0].length(); - for (int col = 0; col < n; col++) { - for (int row = 1; row < m; row++) { - String cur = strs[row], prev = strs[row - 1]; - // 判断每个字符串的 col 索引是否都相同 - if (col >= cur.length() || col >= prev.length() || - cur.charAt(col) != prev.charAt(col)) { - // 发现不匹配的字符,只有 strs[row][0..col-1] 是公共前缀 - return strs[row].substring(0, col); - } - } - } - return strs[0]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" deleted file mode 100644 index c42a437..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262.java" +++ /dev/null @@ -1,84 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 5. 最长回文子串 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最长回文子串 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals("bab", s.longestPalindrome("babad")); - Assertions.assertEquals("bb", s.longestPalindrome("cbbd")); - Assertions.assertEquals("a", s.longestPalindrome("a")); - Assertions.assertEquals("bb", s.longestPalindrome("bb")); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals("aba", s2.longestPalindrome("babad")); - Assertions.assertEquals("bb", s2.longestPalindrome("cbbd")); - Assertions.assertEquals("a", s2.longestPalindrome("a")); - Assertions.assertEquals("bb", s2.longestPalindrome("bb")); - } - - /** - * 双指针判断回文串 + 暴力解决,时间复杂度 o(n^2) - */ - static class Solution { - - public String longestPalindrome(String s) { - String res = s.substring(0, 1); - for (int i = 0; i < s.length(); i++) { - for (int j = i + 1; j < s.length(); j++) { - if (isPalindrome(s, i, j)) { - int len = j - i + 1; - if (len > res.length()) { - res = s.substring(i, j + 1); - } - } - } - } - return res; - } - - public boolean isPalindrome(String s, int left, int right) { - while (left < right) { - if (s.charAt(left) != s.charAt(right)) { - return false; - } - left++; - right--; - } - return true; - } - - } - - static class Solution2 { - - public String longestPalindrome(String s) { - String res = ""; - for (int i = 0; i < s.length(); i++) { - String s1 = palindrome(s, i, i); - String s2 = palindrome(s, i, i + 1); - res = res.length() > s1.length() ? res : s1; - res = res.length() > s2.length() ? res : s2; - } - return res; - } - - public String palindrome(String s, int l, int r) { - while (l >= 0 && r < s.length() - && s.charAt(l) == s.charAt(r)) { - l--; - r++; - } - return s.substring(l + 1, r); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" deleted file mode 100644 index e9324ca..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\346\225\260\347\273\204\347\232\204\345\271\263\346\226\271.java" +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 977. 有序数组的平方 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 有序数组的平方 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[] input1 = { -4, -1, 0, 3, 10 }; - int[] expect1 = { 0, 1, 9, 16, 100 }; - int[] output1 = s.sortedSquares(input1); - Assertions.assertArrayEquals(expect1, output1); - - int[] input2 = { -7, -3, 2, 3, 11 }; - int[] expect2 = { 4, 9, 9, 49, 121 }; - int[] output2 = s.sortedSquares(input2); - Assertions.assertArrayEquals(expect2, output2); - } - - public static class Solution { - - public int[] sortedSquares(int[] nums) { - int p = nums.length - 1; - int i = 0, j = nums.length - 1; - int[] res = new int[nums.length]; - while (i <= j) { - if (Math.abs(nums[i]) > Math.abs(nums[j])) { - res[p] = nums[i] * nums[i]; - i++; - } else { - res[p] = nums[j] * nums[j]; - j--; - } - p--; - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" deleted file mode 100644 index 59232f3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -import java.util.PriorityQueue; - -/** - * 378. 有序矩阵中第 K 小的元素 - * - * @author Zhang Peng - * @date 2025-01-21 - */ -public class 有序矩阵中第K小的元素 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[][] matrix = { { 1, 5, 9 }, { 10, 11, 13 }, { 12, 13, 15 } }; - Assertions.assertEquals(13, s.kthSmallest(matrix, 8)); - - int[][] matrix2 = { { -5 } }; - Assertions.assertEquals(-5, s.kthSmallest(matrix2, 1)); - - int[][] matrix3 = { { 1, 2 }, { 1, 3 } }; - Assertions.assertEquals(1, s.kthSmallest(matrix3, 2)); - - int[][] matrix4 = { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } }; - Assertions.assertEquals(3, s.kthSmallest(matrix4, 8)); - } - - static class Solution { - - public int kthSmallest(int[][] matrix, int k) { - // 存储二元组 (matrix[i][j], i, j) - // i, j 记录当前元素的索引位置,用于生成下一个节点 - PriorityQueue pq = new PriorityQueue<>((a, b) -> { - // 按照元素大小升序排序 - return a[0] - b[0]; - }); - - // 初始化优先级队列,把每一行的第一个元素装进去 - for (int i = 0; i < matrix.length; i++) { - pq.offer(new int[] { matrix[i][0], i, 0 }); - } - - int res = -1; - while (!pq.isEmpty() && k > 0) { - int[] cur = pq.poll(); - res = cur[0]; - k--; - - // 链表中的下一个节点加入优先级队列 - int i = cur[1], j = cur[2]; - if (j + 1 < matrix[i].length) { - pq.add(new int[] { matrix[i][j + 1], i, j + 1 }); - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" deleted file mode 100644 index 89cfd6a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\345\222\214\346\234\200\345\260\217\347\232\204K\345\257\271\346\225\260\345\255\227.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import cn.hutool.json.JSONUtil; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.PriorityQueue; - -/** - * 373. 查找和最小的 K 对数字 - * - * @author Zhang Peng - * @date 2025-01-21 - */ -public class 查找和最小的K对数字 { - - public static void main(String[] args) { - Solution s = new Solution(); - List> expectList1 = new ArrayList<>(); - expectList1.add(Arrays.asList(1, 2)); - expectList1.add(Arrays.asList(1, 4)); - expectList1.add(Arrays.asList(1, 6)); - List> list1 = s.kSmallestPairs(new int[] { 1, 7, 11 }, new int[] { 2, 4, 6 }, 3); - System.out.println(JSONUtil.toJsonStr(list1)); - - List> list2 = s.kSmallestPairs(new int[] { 1, 1, 2 }, new int[] { 1, 2, 3 }, 2); - System.out.println(JSONUtil.toJsonStr(list2)); - } - - static class Solution { - - public List> kSmallestPairs(int[] nums1, int[] nums2, int k) { - PriorityQueue queue = new PriorityQueue<>(Comparator.comparingInt(a -> (a[0] + a[1]))); - for (int i = 0; i < nums1.length; i++) { - for (int j = 0; j < nums2.length; j++) { - queue.offer(new int[] { nums1[i], nums2[j] }); - } - } - - List> res = new ArrayList<>(); - for (int i = 0; i < k; i++) { - int[] element = queue.poll(); - res.add(Arrays.asList(element[0], element[1])); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" deleted file mode 100644 index 626bd5b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\346\237\245\346\211\276\346\200\273\344\273\267\346\240\274\344\270\272\347\233\256\346\240\207\345\200\274\347\232\204\344\270\244\344\270\252\345\225\206\345\223\201.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashSet; -import java.util.Set; - -/** - * LCR 179. 查找总价格为目标值的两个商品 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 查找总价格为目标值的两个商品 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 3, 15 }, s.twoSum(new int[] { 3, 9, 12, 15 }, 18)); - Assertions.assertArrayEquals(new int[] { 27, 34 }, s.twoSum(new int[] { 8, 21, 27, 34, 52, 66 }, 61)); - } - - static class Solution { - - public int[] twoSum(int[] nums, int target) { - Set set = new HashSet<>(); - for (int num : nums) { - int diff = target - num; - if (set.contains(diff)) { - return new int[] { num, diff }; - } else { - set.add(num); - } - } - return new int[0]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\345\212\250\351\233\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\345\212\250\351\233\266.java" deleted file mode 100644 index b682999..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\345\212\250\351\233\266.java" +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 283. 移动零 - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 移动零 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[] arr1 = { 0, 1, 0, 3, 12 }; - s.moveZeroes(arr1); - Assertions.assertArrayEquals(new int[] { 1, 3, 12, 0, 0 }, arr1); - - int[] arr2 = { 0, 0, 1 }; - s.moveZeroes(arr2); - Assertions.assertArrayEquals(new int[] { 1, 0, 0 }, arr2); - - int[] arr3 = { 0 }; - s.moveZeroes(arr3); - Assertions.assertArrayEquals(new int[] { 0 }, arr3); - } - - public static class Solution { - - public void moveZeroes(int[] nums) { - // slow 指针维护所有不为 0 的元素 - int slow = 0, fast = 0; - while (fast < nums.length) { - if (nums[fast] != 0) { - nums[slow] = nums[fast]; - slow++; - } - fast++; - } - // 后续补零 - for (int i = slow; i < nums.length; i++) { - nums[i] = 0; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\351\231\244\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\351\231\244\345\205\203\347\264\240.java" deleted file mode 100644 index 52992a1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\347\247\273\351\231\244\345\205\203\347\264\240.java" +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 27. 移除元素 - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 移除元素 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[] arr1 = { 3, 2, 2, 3 }; - Assertions.assertEquals(2, s.removeElement(arr1, 3)); - - int[] arr2 = { 0, 1, 2, 2, 3, 0, 4, 2 }; - Assertions.assertEquals(5, s.removeElement(arr2, 2)); - - int[] arr3 = { 1 }; - Assertions.assertEquals(0, s.removeElement(arr3, 1)); - } - - static class Solution { - - public int removeElement(int[] nums, int val) { - int slow = 0, fast = 0; - while (fast < nums.length) { - if (nums[fast] != val) { - nums[slow] = nums[fast]; - slow++; - } - fast++; - } - return slow; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\350\275\254\347\275\256\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\350\275\254\347\275\256\347\237\251\351\230\265.java" deleted file mode 100644 index 92104fe..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\350\275\254\347\275\256\347\237\251\351\230\265.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 1329. 将矩阵按对角线排序 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 转置矩阵 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] input1 = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; - int[][] expect1 = { { 1, 4, 7 }, { 2, 5, 8 }, { 3, 6, 9 } }; - int[][] output1 = s.transpose(input1); - Assertions.assertArrayEquals(expect1, output1); - - int[][] input2 = { { 1, 2, 3 }, { 4, 5, 6 } }; - int[][] expect2 = { { 1, 4 }, { 2, 5 }, { 3, 6 } }; - int[][] output2 = s.transpose(input2); - Assertions.assertArrayEquals(expect2, output2); - } - - public static class Solution { - - public int[][] transpose(int[][] matrix) { - int m = matrix.length, n = matrix[0].length; - int[][] res = new int[n][m]; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - res[j][i] = matrix[i][j]; - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\242\234\350\211\262\345\210\206\347\261\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\242\234\350\211\262\345\210\206\347\261\273.java" deleted file mode 100644 index d8d6d83..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\242\234\350\211\262\345\210\206\347\261\273.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import cn.hutool.json.JSONUtil; -import org.junit.jupiter.api.Assertions; - -/** - * 75. 颜色分类 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 颜色分类 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[] nums1 = { 2, 0, 2, 1, 1, 0 }; - s.sortColors(nums1); - Assertions.assertArrayEquals(new int[] { 0, 0, 1, 1, 2, 2 }, nums1); - - int[] nums2 = { 2, 0, 1 }; - s.sortColors(nums2); - Assertions.assertArrayEquals(new int[] { 0, 1, 2 }, nums2); - } - - static class Solution { - - public void sortColors(int[] nums) { - moveToTail(nums, 1); - System.out.println("nums = " + JSONUtil.toJsonStr(nums)); - moveToTail(nums, 2); - System.out.println("nums = " + JSONUtil.toJsonStr(nums)); - } - - public void moveToTail(int[] nums, int val) { - if (nums == null || nums.length == 0) { return; } - int slow = 0, fast = 0; - while (fast < nums.length) { - if (nums[fast] != val) { - nums[slow] = nums[fast]; - slow++; - } - fast++; - } - for (int i = slow; i < nums.length; i++) { - nums[i] = val; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" deleted file mode 100644 index 4c1597e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/two_pointer/\351\252\214\350\257\201\345\233\236\346\226\207\344\270\262.java" +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.dunwu.algorithm.array.two_pointer; - -import org.junit.jupiter.api.Assertions; - -/** - * 125. 验证回文串 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 验证回文串 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isPalindrome("A man, a plan, a canal: Panama")); - Assertions.assertFalse(s.isPalindrome("race a car")); - Assertions.assertTrue(s.isPalindrome(" ")); - Assertions.assertTrue(s.isPalindrome("ab_a")); - - Solution2 s2 = new Solution2(); - Assertions.assertTrue(s2.isPalindrome("A man, a plan, a canal: Panama")); - Assertions.assertFalse(s2.isPalindrome("race a car")); - Assertions.assertTrue(s2.isPalindrome(" ")); - Assertions.assertTrue(s2.isPalindrome("ab_a")); - } - - static class Solution { - - public boolean isPalindrome(String s) { - String format = s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase(); - return isPalindrome(format, 0, format.length() - 1); - } - - public boolean isPalindrome(String s, int left, int right) { - while (left < right) { - if (s.charAt(left) != s.charAt(right)) { - return false; - } - left++; - right--; - } - return true; - } - - } - - static class Solution2 { - - public boolean isPalindrome(String s) { - int left = 0, right = s.length() - 1; - while (left < right) { - if (!Character.isLetterOrDigit(s.charAt(left))) { - left++; - continue; - } - if (!Character.isLetterOrDigit(s.charAt(right))) { - right--; - continue; - } - - char l = Character.toLowerCase(s.charAt(left)); - char r = Character.toLowerCase(s.charAt(right)); - if (l != r) { - return false; - } - left++; - right--; - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" deleted file mode 100644 index 6a6d857..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\344\271\230\347\247\257\345\260\217\344\272\216K\347\232\204\345\255\220\346\225\260\347\273\204.java" +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -/** - * 713. 乘积小于 K 的子数组 - * - * @author Zhang Peng - * @date 2025-10-14 - */ -public class 乘积小于K的子数组 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(8, s.numSubarrayProductLessThanK(new int[] { 10, 5, 2, 6 }, 100)); - Assertions.assertEquals(0, s.numSubarrayProductLessThanK(new int[] { 1, 2, 3 }, 0)); - } - - static class Solution { - - public int numSubarrayProductLessThanK(int[] nums, int k) { - int left = 0, right = 0; - // 滑动窗口,初始化为乘法单位元 - int windowProduct = 1; - // 记录符合条件的子数组个数 - int count = 0; - - while (right < nums.length) { - // 扩大窗口,并更新窗口数据 - windowProduct = windowProduct * nums[right]; - right++; - - while (left < right && windowProduct >= k) { - // 缩小窗口,并更新窗口数据 - windowProduct = windowProduct / nums[left]; - left++; - } - // 现在必然是一个合法的窗口,但注意思考这个窗口中的子数组个数怎么计算: - // 比方说 left = 1, right = 4 划定了 [1, 2, 3] 这个窗口(right 是开区间) - // 但不止 [left..right] 是合法的子数组,[left+1..right], [left+2..right] 等都是合法子数组 - // 所以我们需要把 [3], [2,3], [1,2,3] 这 right - left 个子数组都加上 - count += right - left; - } - - return count; - } - - } - -} \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" deleted file mode 100644 index 22f6ea9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.java" +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 567. 字符串的排列 - * - * @author Zhang Peng - * @since 2025-08-06 - */ -public class 字符串的排列 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.checkInclusion("ab", "eidbaooo")); - Assertions.assertFalse(s.checkInclusion("ab", "eidboaoo")); - } - - static class Solution { - - public boolean checkInclusion(String t, String s) { - Map need = new HashMap<>(); - Map window = new HashMap<>(); - for (char c : t.toCharArray()) need.put(c, need.getOrDefault(c, 0) + 1); - - int left = 0, right = 0; - int valid = 0; - while (right < s.length()) { - char c = s.charAt(right); - right++; - // 进行窗口内数据的一系列更新 - if (need.containsKey(c)) { - window.put(c, window.getOrDefault(c, 0) + 1); - if (window.get(c).equals(need.get(c))) { valid++; } - } - - // 判断左侧窗口是否要收缩 - while (right - left >= t.length()) { - // 在这里判断是否找到了合法的子串 - if (valid == need.size()) { return true; } - char d = s.charAt(left); - left++; - // 进行窗口内数据的一系列更新 - if (need.containsKey(d)) { - if (window.get(d).equals(need.get(d))) { valid--; } - window.put(d, window.get(d) - 1); - } - } - } - // 未找到符合条件的子串 - return false; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" deleted file mode 100644 index 8bf319d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashSet; -import java.util.Set; - -/** - * 217. 存在重复元素 - * - * @author Zhang Peng - * @since 2020-06-05 - */ -public class 存在重复元素 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.containsDuplicate(new int[] { 1, 2, 3, 1 })); - Assertions.assertFalse(s.containsDuplicate(new int[] { 1, 2, 3, 4 })); - Assertions.assertTrue(s.containsDuplicate(new int[] { 1, 1, 1, 3, 3, 4, 3, 2, 4, 2 })); - } - - static class Solution { - - public boolean containsDuplicate(int[] nums) { - Set set = new HashSet<>(); - for (int num : nums) { - if (set.contains(num)) { - return true; - } - set.add(num); - } - return false; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" deleted file mode 100644 index 2e6b279..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2402.java" +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashSet; - -/** - * 219. 存在重复元素 II - * - * @author Zhang Peng - * @date 2025-10-15 - */ -public class 存在重复元素2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.containsNearbyDuplicate(new int[] { 1, 2, 3, 1 }, 3)); - Assertions.assertTrue(s.containsNearbyDuplicate(new int[] { 1, 0, 1, 1 }, 1)); - Assertions.assertFalse(s.containsNearbyDuplicate(new int[] { 1, 2, 3, 1, 2, 3 }, 2)); - Assertions.assertTrue(s.containsNearbyDuplicate(new int[] { 99, 99 }, 2)); - } - - static class Solution { - - public boolean containsNearbyDuplicate(int[] nums, int k) { - - // base case - if (nums == null || nums.length < 2) { return false; } - - int left = 0, right = 0; - HashSet window = new HashSet<>(); - // 滑动窗口算法框架,维护一个大小为 k 的窗口 - while (right < nums.length) { - // 扩大窗口 - if (window.contains(nums[right])) { return true; } - window.add(nums[right]); - right++; - - if (right - left > k) { - // 当窗口的大小大于 k 时,缩小窗口 - window.remove(nums[left]); - left++; - } - } - return false; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2403.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2403.java" deleted file mode 100644 index 8265957..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\255\230\345\234\250\351\207\215\345\244\215\345\205\203\347\264\2403.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -import java.util.TreeSet; - -/** - * 220. 存在重复元素 III - * - * @author Zhang Peng - * @date 2025-10-15 - */ -public class 存在重复元素3 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.containsNearbyAlmostDuplicate(new int[] { 1, 2, 3, 1 }, 3, 0)); - Assertions.assertFalse(s.containsNearbyAlmostDuplicate(new int[] { 1, 5, 9, 1, 5, 9 }, 2, 3)); - Assertions.assertTrue(s.containsNearbyAlmostDuplicate(new int[] { 1, 2, 2, 3, 4, 5 }, 3, 0)); - } - - static class Solution { - - public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { - TreeSet window = new TreeSet<>(); - int left = 0, right = 0; - while (right < nums.length) { - // 为了防止 i == j,所以在扩大窗口之前先判断是否有符合题意的索引对 (i, j) - // 查找略大于 nums[right] 的那个元素 - Integer ceiling = window.ceiling(nums[right]); - if (ceiling != null && (long) ceiling - nums[right] <= t) { - return true; - } - // 查找略小于 nums[right] 的那个元素 - Integer floor = window.floor(nums[right]); - if (floor != null && (long) nums[right] - floor <= t) { - return true; - } - - // 扩大窗口 - window.add(nums[right]); - right++; - - if (right - left > k) { - // 缩小窗口 - window.remove(nums[left]); - left++; - } - } - return false; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" deleted file mode 100644 index d39d1c8..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\345\260\206x\345\207\217\345\210\2600\347\232\204\346\234\200\345\260\217\346\223\215\344\275\234\346\225\260.java" +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -/** - * 1658. 将 x 减到 0 的最小操作数 - * - * @author Zhang Peng - * @date 2025-10-14 - */ -public class 将x减到0的最小操作数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.minOperations(new int[] { 1, 1, 4, 2, 3 }, 5)); - Assertions.assertEquals(-1, s.minOperations(new int[] { 5, 6, 7, 8, 9 }, 4)); - Assertions.assertEquals(5, s.minOperations(new int[] { 3, 2, 20, 1, 1, 3 }, 10)); - Assertions.assertEquals(16, s.minOperations(new int[] { 8828, 9581, 49, 9818, 9974, 9869, 9991, - 10000, 10000, 10000, 9999, 9993, 9904, 8819, 1231, 6309 }, 134365)); - } - - static class Solution { - - // 【思路】 - // 从边缘删除掉和为 x 的元素,那剩下来的是什么?剩下来的是不是就是 nums 中的一个子数组? - // 让你尽可能少地从边缘删除元素说明什么?是不是就是说剩下来的这个子数组大小尽可能的大? - // 所以,这道题等价于让你寻找 nums 中元素和为 sum(nums) - x 的最长子数组。 - - // 1、当窗口内元素之和小于目标和 target 时,扩大窗口,让窗口内元素和增加。 - // 2、当窗口内元素之和大于目标和 target 时,缩小窗口,让窗口内元素和减小。 - // 3、当窗口内元素之和等于目标和 target 时,找到一个符合条件的子数组,我们想找的是最长的子数组长度。 - public int minOperations(int[] nums, int x) { - int n = nums.length, sum = 0; - for (int num : nums) { sum += num; } - // 滑动窗口需要寻找的子数组目标和 - int target = sum - x; - - int left = 0, right = 0; - // 记录窗口内所有元素和 - int windowSum = 0; - // 记录目标子数组的最大长度 - int maxLen = Integer.MIN_VALUE; - // 开始执行滑动窗口框架 - while (right < nums.length) { - // 扩大窗口 - windowSum += nums[right]; - right++; - - while (windowSum > target && left < right) { - // 缩小窗口 - windowSum -= nums[left]; - left++; - } - // 寻找目标子数组 - if (windowSum == target) { - maxLen = Math.max(maxLen, right - left); - } - } - // 目标子数组的最大长度可以推导出需要删除的字符数量 - return maxLen == Integer.MIN_VALUE ? -1 : n - maxLen; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" deleted file mode 100644 index 2a6bb20..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 438. 找到字符串中所有字母异位词 - * - * @author Zhang Peng - * @date 2025-10-14 - */ -public class 找到字符串中所有字母异位词 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new Integer[] { 0, 6 }, s.findAnagrams("cbaebabacd", "abc").toArray()); - Assertions.assertArrayEquals(new Integer[] { 0, 1, 2 }, s.findAnagrams("abab", "ab").toArray()); - } - - static class Solution { - - public List findAnagrams(String s, String t) { - Map need = new HashMap<>(); - Map window = new HashMap<>(); - for (char c : t.toCharArray()) { - need.put(c, need.getOrDefault(c, 0) + 1); - } - - int left = 0, right = 0; - int valid = 0; - // 记录结果 - List res = new ArrayList<>(); - while (right < s.length()) { - char c = s.charAt(right); - right++; - // 进行窗口内数据的一系列更新 - if (need.containsKey(c)) { - window.put(c, window.getOrDefault(c, 0) + 1); - if (window.get(c).equals(need.get(c))) { - valid++; - } - } - // 判断左侧窗口是否要收缩 - while (right - left >= t.length()) { - // 当窗口符合条件时,把起始索引加入 res - if (valid == need.size()) { - res.add(left); - } - char d = s.charAt(left); - left++; - // 进行窗口内数据的一系列更新 - if (need.containsKey(d)) { - if (window.get(d).equals(need.get(d))) { - valid--; - } - window.put(d, window.get(d) - 1); - } - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" deleted file mode 100644 index 52f0955..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 3. 无重复字符的最长子串 - * - * @author Zhang Peng - * @date 2025-10-14 - */ -public class 无重复字符的最长子串 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.lengthOfLongestSubstring("abcabcbb")); - Assertions.assertEquals(1, s.lengthOfLongestSubstring("bbbbb")); - Assertions.assertEquals(3, s.lengthOfLongestSubstring("pwwkew")); - Assertions.assertEquals(2, s.lengthOfLongestSubstring("aab")); - } - - static class Solution { - - public int lengthOfLongestSubstring(String s) { - Map window = new HashMap<>(); - - int left = 0, right = 0; - // 记录结果 - int res = 0; - while (right < s.length()) { - char c = s.charAt(right); - right++; - // 进行窗口内数据的一系列更新 - window.put(c, window.getOrDefault(c, 0) + 1); - // 判断左侧窗口是否要收缩 - while (window.get(c) > 1) { - char d = s.charAt(left); - left++; - // 进行窗口内数据的一系列更新 - window.put(d, window.get(d) - 1); - } - // 在这里更新答案 - res = Math.max(res, right - left); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" deleted file mode 100644 index 58f6ba0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\233\277\346\215\242\345\220\216\347\232\204\346\234\200\351\225\277\351\207\215\345\244\215\345\255\227\347\254\246.java" +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -/** - * 424. 替换后的最长重复字符 - * - * @author Zhang Peng - * @date 2025-10-15 - */ -public class 替换后的最长重复字符 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.characterReplacement("ABAB", 2)); - Assertions.assertEquals(4, s.characterReplacement("AABABBA", 1)); - Assertions.assertEquals(4, s.characterReplacement("AAAA", 2)); - } - - static class Solution { - - public int characterReplacement(String s, int k) { - int left = 0, right = 0; - // 统计窗口中每个字符的出现次数 - int[] windowCharCount = new int[26]; - // 记录窗口中字符的最多重复次数 - // 记录这个值的意义在于,最划算的替换方法肯定是把其他字符替换成出现次数最多的那个字符 - int windowMaxCount = 0; - // 记录结果长度 - int res = 0; - - // 开始滑动窗口模板 - while (right < s.length()) { - // 扩大窗口 - int c = s.charAt(right) - 'A'; - windowCharCount[c]++; - windowMaxCount = Math.max(windowMaxCount, windowCharCount[c]); - right++; - - // 这个 while 换成 if 也可以 - while (right - left - windowMaxCount > k) { - // 杂牌字符数量 right - left - windowMaxCount 多于 k - // 此时,k 次替换已经无法把窗口内的字符都替换成相同字符了 - // 必须缩小窗口 - windowCharCount[s.charAt(left) - 'A']--; - left++; - } - // 经过收缩后,此时一定是一个合法的窗口 - res = Math.max(res, right - left); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\2603.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\2603.java" deleted file mode 100644 index 531e688..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\244\247\350\277\236\347\273\2551\347\232\204\344\270\252\346\225\2603.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -/** - * 1004. 最大连续1的个数 III - * - * @author Zhang Peng - * @date 2025-10-14 - */ -public class 最大连续1的个数3 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(6, s.longestOnes(new int[] { 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0 }, 2)); - Assertions.assertEquals(10, - s.longestOnes(new int[] { 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1 }, 3)); - } - - static class Solution { - - public int longestOnes(int[] nums, int k) { - int cnt = 0, len = 0; - int left = 0, right = 0; - while (right < nums.length) { - if (nums[right] == 0) { cnt++; } - right++; - - while (cnt > k) { - if (nums[left] == 0) { cnt--; } - left++; - } - len = Math.max(len, right - left); - } - return len; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" deleted file mode 100644 index 81b42a2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.java" +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 76. 最小覆盖子串 - * - * @author Zhang Peng - * @date 2025-01-10 - */ -@Slf4j -public class 最小覆盖子串 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals("BANC", s.minWindow("ADOBECODEBANC", "ABC")); - Assertions.assertEquals("a", s.minWindow("a", "a")); - Assertions.assertEquals("", s.minWindow("a", "aa")); - } - - static class Solution { - - public String minWindow(String s, String t) { - Map need = new HashMap<>(); - Map window = new HashMap<>(); - for (char c : t.toCharArray()) { - need.put(c, need.getOrDefault(c, 0) + 1); - } - - int valid = 0; - int left = 0, right = 0; - // 记录最小覆盖子串的起始索引及长度 - int start = 0, len = Integer.MAX_VALUE; - while (right < s.length()) { - // c 是将移入窗口的字符 - char c = s.charAt(right); - // 扩大窗口 - right++; - // 进行窗口内数据的一系列更新 - if (need.containsKey(c)) { - window.put(c, window.getOrDefault(c, 0) + 1); - if (window.get(c).equals(need.get(c))) { valid++; } - } - - // 判断左侧窗口是否要收缩 - while (valid == need.size()) { - - // 在这里更新最小覆盖子串 - if (right - left < len) { - start = left; - len = right - left; - } - // d 是将移出窗口的字符 - char d = s.charAt(left); - // 缩小窗口 - left++; - // 进行窗口内数据的一系列更新 - if (need.containsKey(d)) { - if (window.get(d).equals(need.get(d))) { valid--; } - window.put(d, window.get(d) - 1); - } - } - } - // 返回最小覆盖子串 - return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" deleted file mode 100644 index 5a8994b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\350\207\263\345\260\221\346\234\211K\344\270\252\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262.java" +++ /dev/null @@ -1,86 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -/** - * 395. 至少有 K - * 个重复字符的最长子串 - * - * @author Zhang Peng - * @date 2025-10-15 - */ -public class 至少有K个重复字符的最长子串 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.longestSubstring("aaabb", 3)); - Assertions.assertEquals(5, s.longestSubstring("ababbc", 2)); - Assertions.assertEquals(6, s.longestSubstring("aaabbb", 3)); - } - - public static class Solution { - - public int longestSubstring(String s, int k) { - int len = 0; - for (int i = 1; i <= 26; i++) { - // 限制窗口中只能有 i 种不同字符 - len = Math.max(len, longestKLetterSubstring(s, k, i)); - } - return len; - } - - // 寻找 s 中含有 count 种字符,且每种字符出现次数都大于 k 的子串 - public int longestKLetterSubstring(String s, int k, int count) { - - // 记录答案 - int res = 0; - // 快慢指针维护滑动窗口,左闭右开区间 - int left = 0, right = 0; - // 题目说 s 中只有小写字母,所以用大小 26 的数组记录窗口中字符出现的次数 - int[] windowCount = new int[26]; - // 记录窗口中存在几种不同的字符(字符种类) - int windowUniqueCount = 0; - // 记录窗口中有几种字符的出现次数达标(大于等于 k) - int windowValidCount = 0; - // 滑动窗口代码模板 - while (right < s.length()) { - // 移入字符,扩大窗口 - int c = s.charAt(right) - 'a'; - if (windowCount[c] == 0) { - // 窗口中新增了一种字符 - windowUniqueCount++; - } - windowCount[c]++; - if (windowCount[c] == k) { - // 窗口中新增了一种达标的字符 - windowValidCount++; - } - right++; - - // 当窗口中字符种类大于 count 时,缩小窗口 - while (windowUniqueCount > count) { - // 移出字符,缩小窗口 - int d = s.charAt(left) - 'a'; - if (windowCount[d] == k) { - // 窗口中减少了一种达标的字符 - windowValidCount--; - } - windowCount[d]--; - if (windowCount[d] == 0) { - // 窗口中减少了一种字符 - windowUniqueCount--; - } - left++; - } - - // 当窗口中字符种类为 count 且每个字符出现次数都满足 k 时,更新答案 - if (windowValidCount == count) { - res = Math.max(res, right - left); - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" deleted file mode 100644 index b636134..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/window/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204.java" +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.array.window; - -import org.junit.jupiter.api.Assertions; - -/** - * 209. 长度最小的子数组 - * - * @author Zhang Peng - * @date 2025-10-15 - */ -public class 长度最小的子数组 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.minSubArrayLen(7, new int[] { 2, 3, 1, 2, 4, 3 })); - Assertions.assertEquals(1, s.minSubArrayLen(4, new int[] { 1, 4, 4 })); - Assertions.assertEquals(0, s.minSubArrayLen(11, new int[] { 1, 1, 1, 1, 1, 1, 1, 1 })); - } - - public static class Solution { - - public int minSubArrayLen(int target, int[] nums) { - int left = 0, right = 0; - // 维护窗口内元素之和 - int windowSum = 0; - int res = Integer.MAX_VALUE; - - while (right < nums.length) { - // 扩大窗口 - windowSum += nums[right]; - right++; - while (windowSum >= target && left < right) { - // 已经达到 target,缩小窗口,同时更新答案 - res = Math.min(res, right - left); - windowSum -= nums[left]; - left++; - } - } - return res == Integer.MAX_VALUE ? 0 : res; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/package-info.java deleted file mode 100644 index 04a66a6..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 通过 BFS 解最短路径类型问题 - * - * @author Zhang Peng - * @date 2025-12-15 - */ -package io.github.dunwu.algorithm.bfs; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/template/BFS\347\256\227\346\263\225\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/template/BFS\347\256\227\346\263\225\346\250\241\346\235\277.java" deleted file mode 100644 index 0448d03..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/template/BFS\347\256\227\346\263\225\346\250\241\346\235\277.java" +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.dunwu.algorithm.bfs.template; - -import io.github.dunwu.algorithm.graph.Edge; -import io.github.dunwu.algorithm.graph.Graph; - -import java.util.LinkedList; -import java.util.Queue; - -/** - * BFS 算法模板 - * - * @author Zhang Peng - * @date 2025-12-15 - */ -public class BFS算法模板 { - - private Graph graph; - - // 从 s 开始 BFS 遍历图的所有节点,且记录遍历的步数 - // 当走到目标节点 target 时,返回步数 - int bfs(int s, int target) { - boolean[] visited = new boolean[graph.size()]; - Queue q = new LinkedList<>(); - q.offer(s); - visited[s] = true; - // 记录从 s 开始走到当前节点的步数 - int step = 0; - while (!q.isEmpty()) { - int sz = q.size(); - for (int i = 0; i < sz; i++) { - int cur = q.poll(); - System.out.println("visit " + cur + " at step " + step); - // 判断是否到达终点 - if (cur == target) { - return step; - } - // 将邻居节点加入队列,向四周扩散搜索 - for (Edge e : graph.neighbors(cur)) { - if (!visited[e.to]) { - q.offer(e.to); - visited[e.to] = true; - } - } - } - step++; - } - // 如果走到这里,说明在图中没有找到目标节点 - return -1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204.java" deleted file mode 100644 index ca60ee9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\344\270\255\347\232\204\346\234\200\347\237\255\350\267\257\345\276\204.java" +++ /dev/null @@ -1,70 +0,0 @@ -package io.github.dunwu.algorithm.bfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 1091. 二进制矩阵中的最短路径 - * - * @author Zhang Peng - * @date 2025-12-15 - */ -public class 二进制矩阵中的最短路径 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.shortestPathBinaryMatrix(new int[][] { { 0, 1 }, { 1, 0 } })); - Assertions.assertEquals(4, s.shortestPathBinaryMatrix(new int[][] { { 0, 0, 0 }, { 1, 1, 0 }, { 1, 1, 0 } })); - Assertions.assertEquals(-1, s.shortestPathBinaryMatrix(new int[][] { { 1, 0, 0 }, { 1, 1, 0 }, { 1, 1, 0 } })); - } - - static class Solution { - - // 八个方向偏移量(上、下、左、右、左上、右下、左下、右上) - private final int[][] directions = { - { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 }, - { -1, -1 }, { 1, 1 }, { -1, 1 }, { 1, -1 } - }; - - public int shortestPathBinaryMatrix(int[][] grid) { - - int m = grid.length, n = grid[0].length; - if (grid[0][0] == 1 || grid[m - 1][n - 1] == 1) { - return -1; - } - - // 需要记录走过的路径,避免死循环 - boolean[][] visited = new boolean[m][n]; - LinkedList queue = new LinkedList<>(); - - // 初始化队列,从 (0, 0) 出发 - visited[0][0] = true; - queue.offer(new int[] { 0, 0 }); - - int step = 1; - while (!queue.isEmpty()) { - int size = queue.size(); - for (int i = 0; i < size; i++) { - int[] cur = queue.poll(); - int x = cur[0], y = cur[1]; - if (grid[x][y] != 0) { return -1; } - // 到达底部,返回步骤数 - if (x == m - 1 && y == n - 1) { return step; } - - for (int[] d : directions) { - int nextX = x + d[0], nextY = y + d[1]; - if (nextX < 0 || nextX >= m || nextY < 0 || nextY >= n) { continue; } - if (visited[nextX][nextY] || grid[nextX][nextY] != 0) { continue; } - visited[nextX][nextY] = true; - queue.offer(new int[] { nextX, nextY }); - } - } - step++; - } - return -1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" deleted file mode 100644 index 77990db..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" +++ /dev/null @@ -1,68 +0,0 @@ -package io.github.dunwu.algorithm.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 919. 完全二叉树插入器 - * - * @author Zhang Peng - * @date 2025-11-07 - */ -public class 完全二叉树插入器 { - - public static void main(String[] args) { - CBTInserter c = new CBTInserter(TreeNode.buildTree(1, 2)); - Assertions.assertEquals(1, c.insert(3)); - Assertions.assertEquals(2, c.insert(4)); - Assertions.assertEquals(TreeNode.buildTree(1, 2, 3, 4), c.get_root()); - } - - static class CBTInserter { - - private final TreeNode root; - // 这个队列只记录完全二叉树底部可以进行插入的节点 - private final LinkedList queue; - - public CBTInserter(TreeNode root) { - this.root = root; - this.queue = new LinkedList<>(); - LinkedList tmp = new LinkedList<>(); - tmp.offer(root); - while (!tmp.isEmpty()) { - int size = tmp.size(); - for (int i = 0; i < size; i++) { - TreeNode node = tmp.poll(); - if (node == null) { continue; } - if (node.left != null) { tmp.offer(node.left); } - if (node.right != null) { tmp.offer(node.right); } - if (node.left == null || node.right == null) { - // 找到完全二叉树底部可以进行插入的节点 - queue.offer(node); - } - } - } - } - - public int insert(int val) { - TreeNode node = new TreeNode(val); - TreeNode cur = queue.peek(); - queue.offer(node); - if (cur.left == null) { - cur.left = node; - } else if (cur.right == null) { - cur.right = node; - queue.poll(); - } - return cur.val; - } - - public TreeNode get_root() { - return this.root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" deleted file mode 100644 index 8a4c291..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\211\223\345\274\200\350\275\254\347\233\230\351\224\201.java" +++ /dev/null @@ -1,100 +0,0 @@ -package io.github.dunwu.algorithm.bfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -/** - * 297. 二叉树的序列化与反序列化 - * - * @author Zhang Peng - * @date 2025-11-06 - */ -public class 打开转盘锁 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - String[] deadends = new String[] { "0201", "0101", "0102", "1212", "2002" }; - Assertions.assertEquals(6, s.openLock(deadends, "0202")); - - String[] deadends2 = new String[] { "8888" }; - Assertions.assertEquals(1, s.openLock(deadends2, "0009")); - - String[] deadends3 = new String[] { "8887", "8889", "8878", "8898", "8788", "8988", "7888", "9888" }; - Assertions.assertEquals(-1, s.openLock(deadends3, "8888")); - } - - static class Solution { - - public int openLock(String[] deadends, String target) { - int step = 0; - - Set blackSet = new HashSet<>(); - Collections.addAll(blackSet, deadends); - - if (blackSet.contains("0000")) { return -1; } - - Set visited = new HashSet<>(); - LinkedList queue = new LinkedList<>(); - visited.add("0000"); - queue.offer("0000"); - - while (!queue.isEmpty()) { - int size = queue.size(); - for (int i = 0; i < size; i++) { - String cur = queue.poll(); - if (cur.equals(target)) { - return step; - } - - for (String neighbour : neighbours(cur)) { - if (!visited.contains(neighbour) && !blackSet.contains(neighbour)) { - visited.add(neighbour); - queue.offer(neighbour); - } - } - } - step++; - } - return -1; - } - - public String plus(String s, int i) { - char[] ch = s.toCharArray(); - if (ch[i] == '9') { - ch[i] = '0'; - } else { - ch[i] += 1; - } - return new String(ch); - } - - public String minus(String s, int i) { - char[] ch = s.toCharArray(); - if (ch[i] == '0') { - ch[i] = '9'; - } else { - ch[i] -= 1; - } - return new String(ch); - } - - public List neighbours(String s) { - List neighbours = new ArrayList<>(); - for (int i = 0; i < s.length(); i++) { - neighbours.add(plus(s, i)); - neighbours.add(minus(s, i)); - } - return neighbours; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" deleted file mode 100644 index c52c342..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\234\200\345\260\217\345\237\272\345\233\240\345\217\230\345\214\226.java" +++ /dev/null @@ -1,82 +0,0 @@ -package io.github.dunwu.algorithm.bfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -/** - * 433. 最小基因变化 - * - * @author Zhang Peng - * @date 2025-11-07 - */ -public class 最小基因变化 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(1, - s.minMutation("AACCGGTT", "AACCGGTA", new String[] { "AACCGGTA" })); - Assertions.assertEquals(2, - s.minMutation("AACCGGTT", "AAACGGTA", new String[] { "AACCGGTA", "AACCGCTA", "AAACGGTA" })); - Assertions.assertEquals(3, - s.minMutation("AAAAACCC", "AACCCCCC", new String[] { "AAAACCCC", "AAACCCCC", "AACCCCCC" })); - Assertions.assertEquals(-1, - s.minMutation("AACCGGTT", "AACCGGTA", new String[] {})); - Assertions.assertEquals(-1, - s.minMutation("AAAAAAAA", "CCCCCCCC", - new String[] { "AAAAAAAA", "AAAAAAAC", "AAAAAACC", "AAAAACCC", "AAAACCCC", "AACACCCC", "ACCACCCC", - "ACCCCCCC", "CCCCCCCA" })); - } - - static class Solution { - - final char[] AGCT = new char[] { 'A', 'C', 'G', 'T' }; - - public int minMutation(String startGene, String endGene, String[] bank) { - if (startGene.equals(endGene)) { return 0; } - - int step = 0; - Set banks = new HashSet<>(Arrays.asList(bank)); - Set visited = new HashSet<>(); - LinkedList queue = new LinkedList<>(); - queue.offer(startGene); - - while (!queue.isEmpty()) { - int size = queue.size(); - for (int i = 0; i < size; i++) { - String curGene = queue.poll(); - if (curGene.equals(endGene)) { return step; } - for (String newGene : neighbours(curGene)) { - if (!visited.contains(newGene) && banks.contains(newGene)) { - queue.offer(newGene); - visited.add(newGene); - } - } - } - step++; - } - return -1; - } - - // 当前基因的每个位置都可以变异为 A/G/C/T,穷举所有可能的结构 - public List neighbours(String gene) { - List res = new LinkedList<>(); - char[] ch = gene.toCharArray(); - for (int i = 0; i < ch.length; i++) { - char c = ch[i]; - for (char option : AGCT) { - ch[i] = option; - res.add(new String(ch)); - } - ch[i] = c; - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\260\264\345\243\266\351\227\256\351\242\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\260\264\345\243\266\351\227\256\351\242\230.java" deleted file mode 100644 index a70a284..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\346\260\264\345\243\266\351\227\256\351\242\230.java" +++ /dev/null @@ -1,83 +0,0 @@ -package io.github.dunwu.algorithm.bfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - -/** - * 365. 水壶问题 - * - * @author Zhang Peng - * @date 2025-12-15 - */ -public class 水壶问题 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.canMeasureWater(3, 5, 4)); - Assertions.assertFalse(s.canMeasureWater(2, 6, 5)); - Assertions.assertTrue(s.canMeasureWater(1, 2, 3)); - } - - static class Solution { - - public boolean canMeasureWater(int x, int y, int t) { - // BFS 算法的队列 - LinkedList q = new LinkedList<>(); - // 用来记录已经遍历过的状态,把元组转化成数字方便存储哈希集合 - // 转化方式是 (x, y) -> (x * (y + 1) + y),和二维数组坐标转一维坐标是一样的原理 - // 因为水桶 2 的取值是 [0, y],所以需要额外加一,请类比二维数组坐标转一维坐标 - // 且考虑到题目输入的数据规模较大,相乘可能导致 int 溢出,所以使用 long 类型 - HashSet visited = new HashSet<>(); - // 添加初始状态,两个桶都没有水 - q.offer(new int[] { 0, 0 }); - visited.add((long) 0 * (0 + 1) + 0); - - while (!q.isEmpty()) { - int[] curState = q.poll(); - if (curState[0] == t || curState[1] == t - || curState[0] + curState[1] == t) { - // 如果任意一个桶的水量等于目标水量,就返回 true - return true; - } - // 计算出所有可能的下一个状态 - List nextStates = new LinkedList<>(); - // 把 1 桶灌满 - nextStates.add(new int[] { x, curState[1] }); - // 把 2 桶灌满 - nextStates.add(new int[] { curState[0], y }); - // 把 1 桶倒空 - nextStates.add(new int[] { 0, curState[1] }); - // 把 2 桶倒空 - nextStates.add(new int[] { curState[0], 0 }); - // 把 1 桶的水灌进 2 桶,直到 1 桶空了或者 2 桶满了 - nextStates.add(new int[] { - curState[0] - Math.min(curState[0], y - curState[1]), - curState[1] + Math.min(curState[0], y - curState[1]) - }); - // 把 2 桶的水灌进 1 桶,直到 2 桶空了或者 1 桶满了 - nextStates.add(new int[] { - curState[0] + Math.min(curState[1], x - curState[0]), - curState[1] - Math.min(curState[1], x - curState[0]) - }); - - // 把所有可能的下一个状态都放进队列里 - for (int[] nextState : nextStates) { - // 把二维坐标转化为数字,方便去重 - long hash = (long) nextState[0] * (y + 1) + nextState[1]; - if (visited.contains(hash)) { - // 如果这个状态之前遍历过,就跳过,避免队列永远不空陷入死循环 - continue; - } - q.offer(nextState); - visited.add(hash); - } - } - return false; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" deleted file mode 100644 index 0b5751b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\205\220\347\203\202\347\232\204\346\251\230\345\255\220.java" +++ /dev/null @@ -1,93 +0,0 @@ -package io.github.dunwu.algorithm.bfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 994. 腐烂的橘子 - * - * @author Zhang Peng - * @date 2025-11-07 - */ -public class 腐烂的橘子 { - - public static void main(String[] args) { - Solution s = new Solution(); - - int[][] input1 = { { 2, 1, 1 }, { 1, 1, 0 }, { 0, 1, 1 } }; - Assertions.assertEquals(4, s.orangesRotting(input1)); - - int[][] input2 = { { 2, 1, 1 }, { 0, 1, 1 }, { 1, 0, 1 } }; - Assertions.assertEquals(-1, s.orangesRotting(input2)); - - int[][] input3 = { { 0, 2 } }; - Assertions.assertEquals(0, s.orangesRotting(input3)); - - int[][] input4 = { { 1 } }; - Assertions.assertEquals(-1, s.orangesRotting(input4)); - - int[][] input5 = { { 1, 2 } }; - Assertions.assertEquals(1, s.orangesRotting(input5)); - } - - static class Solution { - - // 四个方向偏移量(上、下、左、右) - private static final int[][] directions = { { 0, 1 }, { 0, -1 }, { -1, 0 }, { 1, 0 } }; - - public int orangesRotting(int[][] grid) { - - int m = grid.length, n = grid[0].length; - - int freshCount = 0; - boolean[][] visited = new boolean[m][n]; - LinkedList queue = new LinkedList<>(); - - // 把所有腐烂的橘子加入队列,作为 BFS 的起点 - for (int x = 0; x < m; x++) { - for (int y = 0; y < n; y++) { - if (grid[x][y] == 1) { - freshCount++; - } else if (grid[x][y] == 2) { - queue.offer(new int[] { x, y }); - visited[x][y] = true; - } - } - } - if (freshCount == 0) { return 0; } - if (queue.isEmpty()) { return -1; } - - int step = 1; - while (!queue.isEmpty()) { - int size = queue.size(); - for (int i = 0; i < size; i++) { - int[] point = queue.poll(); - int x = point[0], y = point[1]; - for (int[] d : directions) { - int nextX = x + d[0], nextY = y + d[1]; - // 超出边界,跳过 - if (nextX < 0 || nextX >= m || nextY < 0 || nextY >= n) { continue; } - // 已访问,跳过(避免死循环) - if (visited[nextX][nextY]) { continue; } - // 遇到空格,跳过 - if (grid[nextX][nextY] == 0) { continue; } - // 遇到新鲜橘子,被传播腐烂 - if (grid[nextX][nextY] == 1) { - grid[nextX][nextY] = 2; - freshCount--; - // 新鲜橘子数为 0,返回结果 - if (freshCount == 0) { return step; } - } - visited[nextX][nextY] = true; - queue.offer(new int[] { nextX, nextY }); - } - } - step++; - } - return -1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" deleted file mode 100644 index 3afee28..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\264\246\346\210\267\345\220\210\345\271\266.java" +++ /dev/null @@ -1,112 +0,0 @@ -package io.github.dunwu.algorithm.bfs; - -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - -/** - * 721. 账户合并 - * - * @author Zhang Peng - * @date 2025-11-07 - */ -public class 账户合并 { - - public static void main(String[] args) { - - Solution solution = new Solution(); - - String[][] input1 = { - { "John", "johnsmith@mail.com", "john00@mail.com" }, - { "John", "johnnybravo@mail.com" }, - { "John", "johnsmith@mail.com", "john_newyork@mail.com" }, - { "Mary", "mary@mail.com" } - }; - String[][] expect1 = { - { "John", "johnnybravo@mail.com" }, - { "John", "john00@mail.com", "john_newyork@mail.com", "johnsmith@mail.com" }, - { "Mary", "mary@mail.com" } - }; - List> output1 = solution.accountsMerge(ArrayUtil.toStringMatrixList(input1)); - Assertions.assertArrayEquals(expect1, ArrayUtil.toStringMatrixArray(output1)); - - String[][] input2 = { - { "Gabe", "Gabe0@m.co", "Gabe3@m.co", "Gabe1@m.co" }, - { "Kevin", "Kevin3@m.co", "Kevin5@m.co", "Kevin0@m.co" }, - { "Ethan", "Ethan5@m.co", "Ethan4@m.co", "Ethan0@m.co" }, - { "Hanzo", "Hanzo3@m.co", "Hanzo1@m.co", "Hanzo0@m.co" }, - { "Fern", "Fern5@m.co", "Fern1@m.co", "Fern0@m.co" } - }; - String[][] expect2 = { - { "Hanzo", "Hanzo0@m.co", "Hanzo1@m.co", "Hanzo3@m.co" }, - { "Fern", "Fern0@m.co", "Fern1@m.co", "Fern5@m.co" }, - { "Gabe", "Gabe0@m.co", "Gabe1@m.co", "Gabe3@m.co" }, - { "Kevin", "Kevin0@m.co", "Kevin3@m.co", "Kevin5@m.co" }, - { "Ethan", "Ethan0@m.co", "Ethan4@m.co", "Ethan5@m.co" } - }; - List> output2 = solution.accountsMerge(ArrayUtil.toStringMatrixList(input2)); - Assertions.assertArrayEquals(expect2, ArrayUtil.toStringMatrixArray(output2)); - } - - static class Solution { - - public List> accountsMerge(List> accounts) { - // key: email, value: 出现该 email 的 account 的索引列表 - HashMap> emailToIdx = new HashMap<>(); - for (int i = 0; i < accounts.size(); i++) { - List account = accounts.get(i); - for (int j = 1; j < account.size(); j++) { - String email = account.get(j); - List indexes = emailToIdx.getOrDefault(email, new ArrayList<>()); - indexes.add(i); - emailToIdx.put(email, indexes); - } - } - - // 计算合并后的账户 - List> res = new ArrayList<>(); - HashSet visitedEmails = new HashSet<>(); - - for (String email : emailToIdx.keySet()) { - if (visitedEmails.contains(email)) { - continue; - } - // 合并账户,用 BFS 算法穷举所有和 email 相关联的邮箱 - LinkedList mergedEmail = new LinkedList<>(); - LinkedList queue = new LinkedList<>(); - queue.offer(email); - visitedEmails.add(email); - // BFS 算法框架 - while (!queue.isEmpty()) { - String curEmail = queue.poll(); - mergedEmail.addLast(curEmail); - List indexes = emailToIdx.get(curEmail); - for (int index : indexes) { - List account = accounts.get(index); - for (int j = 1; j < account.size(); j++) { - String nextEmail = account.get(j); - if (!visitedEmails.contains(nextEmail)) { - queue.offer(nextEmail); - visitedEmails.add(nextEmail); - } - } - } - } - String userName = accounts.get(emailToIdx.get(email).get(0)).get(0); - // mergedEmail 是 userName 的所有邮箱 - Collections.sort(mergedEmail); - mergedEmail.addFirst(userName); - res.add(mergedEmail); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" deleted file mode 100644 index 4782ed7..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\350\277\267\345\256\253\344\270\255\347\246\273\345\205\245\345\217\243\346\234\200\350\277\221\347\232\204\345\207\272\345\217\243.java" +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.bfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 1926. 迷宫中离入口最近的出口 - * - * @author Zhang Peng - * @date 2025-11-07 - */ -public class 迷宫中离入口最近的出口 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - char[][] maze1 = { { '+', '+', '.', '+' }, { '.', '.', '.', '+' }, { '+', '+', '+', '.' } }; - int[] entrance1 = { 1, 2 }; - Assertions.assertEquals(1, s.nearestExit(maze1, entrance1)); - - char[][] maze2 = { { '+', '+', '+' }, { '.', '.', '.' }, { '+', '+', '+' } }; - int[] entrance2 = { 1, 0 }; - Assertions.assertEquals(2, s.nearestExit(maze2, entrance2)); - - char[][] maze3 = { { '.', '+' } }; - int[] entrance3 = { 0, 0 }; - Assertions.assertEquals(-1, s.nearestExit(maze3, entrance3)); - - char[][] maze4 = { - { '+', '.', '+', '+', '+', '+', '+' }, - { '+', '.', '+', '.', '.', '.', '+' }, - { '+', '.', '+', '.', '+', '.', '+' }, - { '+', '.', '.', '.', '+', '.', '+' }, - { '+', '+', '+', '+', '+', '+', '.' } - }; - int[] entrance4 = { 0, 1 }; - Assertions.assertEquals(-1, s.nearestExit(maze4, entrance4)); - } - - static class Solution { - - public int nearestExit(char[][] maze, int[] entrance) { - - int m = maze.length, n = maze[0].length; - final int[][] directions = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } }; - - // BFS 算法的队列和 visited 数组 - LinkedList queue = new LinkedList<>(); - boolean[][] visited = new boolean[m][n]; - queue.offer(entrance); - visited[entrance[0]][entrance[1]] = true; - // 启动 BFS 算法从 entrance 开始像四周扩散 - int step = 0; - while (!queue.isEmpty()) { - int size = queue.size(); - step++; - // 扩散当前队列中的所有节点 - for (int i = 0; i < size; i++) { - int[] point = queue.poll(); - // 每个节点都会尝试向上下左右四个方向扩展一步 - for (int[] d : directions) { - int x = point[0] + d[0], y = point[1] + d[1]; - if (x < 0 || x >= m || y < 0 || y >= n) { continue; } - if (visited[x][y] || maze[x][y] == '+') { continue; } - // 走到边界(出口) - if (x == 0 || x == m - 1 || y == 0 || y == n - 1) { return step; } - visited[x][y] = true; - queue.offer(new int[] { x, y }); - } - } - } - return -1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" deleted file mode 100644 index 3464b06..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/bfs/\351\222\245\345\214\231\345\222\214\346\210\277\351\227\264.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.bfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -/** - * 841. 钥匙和房间 - * - * @author Zhang Peng - * @date 2025-11-07 - */ -public class 钥匙和房间 { - - public static void main(String[] args) { - Solution s = new Solution(); - - List> input1 = new LinkedList<>(); - input1.add(Collections.singletonList(1)); - input1.add(Collections.singletonList(2)); - input1.add(Collections.singletonList(3)); - input1.add(new LinkedList<>()); - Assertions.assertTrue(s.canVisitAllRooms(input1)); - } - - static class Solution { - - public boolean canVisitAllRooms(List> rooms) { - // base case - if (rooms == null || rooms.size() == 0) { return true; } - - // 记录访问过的房间 - Set visited = new HashSet<>(); - LinkedList queue = new LinkedList<>(); - // 在队列中加入起点,启动 BFS - queue.offer(0); - while (!queue.isEmpty()) { - int size = queue.size(); - for (int i = 0; i < size; i++) { - Integer cur = queue.poll(); - if (!visited.contains(cur)) { - visited.add(cur); - for (int room : rooms.get(cur)) { - queue.offer(room); - } - } - } - } - return visited.size() == rooms.size(); - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IHeap.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IHeap.java deleted file mode 100644 index 259df53..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IHeap.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.github.dunwu.algorithm.common; - -/** - * In computer science, a heap is a specialized tree-based data structure that satisfies the heap property: If A is a - * parent node of B then key(A) is ordered with respect to key(B) with the same ordering applying across the heap. - * Either the keys of parent nodes are always greater than or equal to those of the children and the highest key is in - * the root node (this kind of heap is called max heap) or the keys of parent nodes are less than or equal to those of - * the children (min heap). - *

- * - * @author Justin Wetherell - * @see Heap (Wikipedia)
- */ -public interface IHeap { - - /** - * Add value to the heap. - * - * @param value to add to the heap. - * @return True if added to the heap. - */ - boolean add(T value); - - /** - * Get the value of the head node from the heap. - * - * @return value of the head node. - */ - T getHeadValue(); - - /** - * Remove the head node from the heap. - * - * @return value of the head node. - */ - T removeHead(); - - /** - * Remove the value from the heap. - * - * @param value to remove from heap. - * @return True if value was removed form the heap; - */ - T remove(T value); - - /** - * Clear the entire heap. - */ - void clear(); - - /** - * Does the value exist in the heap. Warning this is a O(n) operation. - * - * @param value to locate in the heap. - * @return True if the value is in heap. - */ - boolean contains(T value); - - /** - * Get size of the heap. - * - * @return size of the heap. - */ - int size(); - - /** - * Validate the heap according to the invariants. - * - * @return True if the heap is valid. - */ - boolean validate(); - - /** - * Get this Heap as a Java compatible Collection - * - * @return Java compatible Collection - */ - java.util.Collection toCollection(); - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IList.java deleted file mode 100644 index 6869238..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IList.java +++ /dev/null @@ -1,70 +0,0 @@ -package io.github.dunwu.algorithm.common; - -/** - * A list or sequence is an abstract data type that implements an ordered collection of values, where the same value may - * occur more than once. - *

- * - * @author Justin Wetherell - * @see List (Wikipedia)
- */ -public interface IList { - - /** - * Add value to list. - * - * @param value to add. - * @return True if added. - */ - boolean add(T value); - - /** - * Remove value from list. - * - * @param value to remove. - * @return True if removed. - */ - boolean remove(T value); - - /** - * Clear the entire list. - */ - void clear(); - - /** - * Does the list contain value. - * - * @param value to search list for. - * @return True if list contains value. - */ - boolean contains(T value); - - /** - * Size of the list. - * - * @return size of the list. - */ - int size(); - - /** - * Validate the list according to the invariants. - * - * @return True if the list is valid. - */ - boolean validate(); - - /** - * Get this List as a Java compatible List - * - * @return Java compatible List - */ - java.util.List toList(); - - /** - * Get this List as a Java compatible Collection - * - * @return Java compatible Collection - */ - java.util.Collection toCollection(); - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IMap.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IMap.java deleted file mode 100644 index 3860756..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IMap.java +++ /dev/null @@ -1,73 +0,0 @@ -package io.github.dunwu.algorithm.common; - -/** - * In computer science, an associative array, map, or dictionary is an abstract data type composed of a collection of - * (key, value) pairs, such that each possible key appears at most once in the collection. - *

- * - * @author Justin Wetherell - * @see Associative Array - * (Wikipedia)
- */ -public interface IMap { - - /** - * Put key->value pair in the map. - * - * @param key to be inserted. - * @param value to be inserted. - * @return V previous value or null if none. - */ - V put(K key, V value); - - /** - * Get value for key. - * - * @param key to get value for. - * @return value mapped to key. - */ - V get(K key); - - /** - * Remove key and value from map. - * - * @param key to remove from the map. - * @return True if removed or False if not found. - */ - V remove(K key); - - /** - * Clear the entire map. - */ - void clear(); - - /** - * Does the map contain the key. - * - * @param key to locate in the map. - * @return True if key is in the map. - */ - boolean contains(K key); - - /** - * Number of key/value pairs in the hash map. - * - * @return number of key/value pairs. - */ - int size(); - - /** - * Validate the map according to the invariants. - * - * @return True if the map is valid. - */ - boolean validate(); - - /** - * Wraps this map in a Java compatible Map - * - * @return Java compatible Map - */ - java.util.Map toMap(); - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IQueue.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IQueue.java deleted file mode 100644 index 0a5c724..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IQueue.java +++ /dev/null @@ -1,87 +0,0 @@ -package io.github.dunwu.algorithm.common; - -/** - * A queue is a particular kind of abstract data type or collection in which the entities in the collection are kept in - * order and the principal (or only) operations on the collection are the addition of entities to the rear terminal - * position and removal of entities from the front terminal position. This makes the queue a First-In-First-Out (FIFO) - * data structure. In a FIFO data structure, the first element added to the queue will be the first one to be removed. - *

- * - * @author Justin Wetherell - * @see Queue - * (Wikipedia)
- */ -public interface IQueue { - - /** - * Add a value to the beginning of the queue. - * - * @param value to add to queue. - * @return True if added to queue. - */ - boolean offer(T value); - - /** - * Remove a value from the tail of the queue. - * - * @return value from the tail of the queue. - */ - T poll(); - - /** - * Get but do not remove tail of the queue. - * - * @return value from the tail of the queue. - */ - T peek(); - - /** - * Remove the value from the queue. - * - * @param value to remove from the queue. - * @return True if the value was removed from the queue. - */ - boolean remove(T value); - - /** - * Clear the entire queue. - */ - void clear(); - - /** - * Does the queue contain the value. - * - * @param value to find in the queue. - * @return True if the queue contains the value. - */ - boolean contains(T value); - - /** - * Get the size of the queue. - * - * @return size of the queue. - */ - int size(); - - /** - * Validate the queue according to the invariants. - * - * @return True if the queue is valid. - */ - boolean validate(); - - /** - * Get this Queue as a Java compatible Queue - * - * @return Java compatible Queue - */ - java.util.Queue toQueue(); - - /** - * Get this Queue as a Java compatible Collection - * - * @return Java compatible Collection - */ - java.util.Collection toCollection(); - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ISet.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ISet.java deleted file mode 100644 index 550d0a8..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ISet.java +++ /dev/null @@ -1,73 +0,0 @@ -package io.github.dunwu.algorithm.common; - -/** - * In computer science, a set is an abstract data structure that can store certain values, without any particular order, - * and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most - * other collection types, rather than retrieving a specific element from a set, one typically tests a value for - * membership in a set. - *

- * - * @author Justin Wetherell - * @see Set - * (Wikipedia)
- */ -public interface ISet { - - /** - * Add value to set. - * - * @param value to add. - * @return True if added. - */ - boolean add(T value); - - /** - * Remove value from set. - * - * @param value to remove. - * @return True if removed. - */ - boolean remove(T value); - - /** - * Clear the entire set. - */ - void clear(); - - /** - * Does the set contain value. - * - * @param value to search set for. - * @return True if set contains value. - */ - boolean contains(T value); - - /** - * Size of the set. - * - * @return size of the set. - */ - int size(); - - /** - * Validate the set according to the invariants. - * - * @return True if the set is valid. - */ - boolean validate(); - - /** - * Get this Set as a Java compatible Set - * - * @return Java compatible Set - */ - java.util.Set toSet(); - - /** - * Get this Set as a Java compatible Collection - * - * @return Java compatible Collection - */ - java.util.Collection toCollection(); - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IStack.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IStack.java deleted file mode 100644 index 5904d27..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/IStack.java +++ /dev/null @@ -1,87 +0,0 @@ -package io.github.dunwu.algorithm.common; - -/** - * A stack is a last in, first out (LIFO) abstract data type and linear data structure. A stack can have any abstract - * data type as an element, but is characterized by two fundamental operations, called push and pop. The push operation - * adds a new item to the top of the stack, or initializes the stack if it is empty. If the stack is full and does not - * contain enough space to accept the given item, the stack is then considered to be in an overflow state. The pop - * operation removes an item from the top of the stack. - *

- * - * @author Justin Wetherell - * @see Stack - * (Wikipedia)
- */ -public interface IStack { - - /** - * Push value on top of stack - * - * @param value to push on the stack. - */ - boolean push(T value); - - /** - * Pop the value from the top of stack. - * - * @return value popped off the top of the stack. - */ - T pop(); - - /** - * Peek the value from the top of stack. - * - * @return value popped off the top of the stack. - */ - T peek(); - - /** - * Remove value from stack. - * - * @param value to remove from stack. - * @return True if value was removed. - */ - boolean remove(T value); - - /** - * Clear the entire stack. - */ - void clear(); - - /** - * Does stack contain object. - * - * @param value object to find in stack. - * @return True is stack contains object. - */ - boolean contains(T value); - - /** - * Size of the stack. - * - * @return size of the stack. - */ - int size(); - - /** - * Validate the stack according to the invariants. - * - * @return True if the stack is valid. - */ - boolean validate(); - - /** - * Get this Stack as a Java compatible Queue - * - * @return Java compatible Queue - */ - java.util.Queue toLifoQueue(); - - /** - * Get this Stack as a Java compatible Collection - * - * @return Java compatible Collection - */ - java.util.Collection toCollection(); - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ISuffixTree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ISuffixTree.java deleted file mode 100644 index af24df2..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ISuffixTree.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.dunwu.algorithm.common; - -import java.util.Set; - -/** - * In computer science, a suffix tree (also called PAT tree or, in an earlier form, position tree) is a compressed trie - * containing all the suffixes of the given text as their keys and positions in the text as their values. Suffix trees - * allow particularly fast implementations of many important string operations. - *

- * - * @author Justin Wetherell - * @see Suffix Tree (Wikipedia) - *
- */ -public interface ISuffixTree { - - /** - * Does the sub-sequence exist in the suffix tree. - * - * @param sub-sequence to locate in the tree. - * @return True if the sub-sequence exist in the tree. - */ - boolean doesSubStringExist(C sub); - - /** - * Get all the suffixes in the tree. - * - * @return set of suffixes in the tree. - */ - Set getSuffixes(); - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ITree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ITree.java deleted file mode 100644 index 6036192..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/common/ITree.java +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.common; - -/** - * A tree can be defined recursively (locally) as a collection of nodes (starting at a root node), where each node is a - * data structure consisting of a value, together with a list of nodes (the "children"), with the constraints that no - * node is duplicated. A tree can be defined abstractly as a whole (globally) as an ordered tree, with a value assigned - * to each node. - *

- * - * @author Justin Wetherell - * @see Tree (Wikipedia) - *
- */ -public interface ITree { - - /** - * Add value to the tree. Tree can contain multiple equal values. - * - * @param value to add to the tree. - * @return True if successfully added to tree. - */ - boolean add(T value); - - /** - * Remove first occurrence of value in the tree. - * - * @param value to remove from the tree. - * @return T value removed from tree. - */ - T remove(T value); - - /** - * Clear the entire stack. - */ - void clear(); - - /** - * Does the tree contain the value. - * - * @param value to locate in the tree. - * @return True if tree contains value. - */ - boolean contains(T value); - - /** - * Get number of nodes in the tree. - * - * @return Number of nodes in the tree. - */ - int size(); - - /** - * Validate the tree according to the invariants. - * - * @return True if the tree is valid. - */ - boolean validate(); - - /** - * Get Tree as a Java compatible Collection - * - * @return Java compatible Collection - */ - java.util.Collection toCollection(); - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/LRU\347\274\223\345\255\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/LRU\347\274\223\345\255\230.java" deleted file mode 100644 index 7d4ebd1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/LRU\347\274\223\345\255\230.java" +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.design; - -import org.junit.jupiter.api.Assertions; - -import java.util.Iterator; -import java.util.LinkedHashMap; - -/** - * 146. LRU 缓存 - * - * @author Zhang Peng - * @date 2025-10-31 - */ -public class LRU缓存 { - - public static void main(String[] args) { - - LRUCache lRUCache = new LRUCache(2); - lRUCache.put(1, 1); // 缓存是 {1=1} - lRUCache.put(2, 2); // 缓存是 {1=1, 2=2} - Assertions.assertEquals(1, lRUCache.get(1)); - lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3} - Assertions.assertEquals(-1, lRUCache.get(2)); - lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3} - Assertions.assertEquals(-1, lRUCache.get(1)); - Assertions.assertEquals(3, lRUCache.get(3)); - Assertions.assertEquals(4, lRUCache.get(4)); - } - - static class LRUCache { - - private int capacity = 0; - private LinkedHashMap cache = null; - - public LRUCache(int capacity) { - this.capacity = capacity; - this.cache = new LinkedHashMap<>(capacity); - } - - public int get(int key) { - Integer val = cache.get(key); - if (val != null) { - cache.remove(key); - cache.put(key, val); - } - return val == null ? -1 : val; - } - - public void put(int key, int value) { - if (cache.containsKey(key)) { - cache.remove(key); - } else { - if (capacity <= cache.size()) { - Iterator iterator = cache.keySet().iterator(); - cache.remove(iterator.next()); - } - } - cache.put(key, value); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" deleted file mode 100644 index 67de9b1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\250.java" +++ /dev/null @@ -1,89 +0,0 @@ -package io.github.dunwu.algorithm.design; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; -import java.util.Stack; - -/** - * 224. 基本计算器 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 基本计算器 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(23, s.calculate("(1+(4+5+2)-3)+(6+8)")); - Assertions.assertEquals(12, s.calculate("1+(4+5+2)")); - Assertions.assertEquals(2147483647, s.calculate("2147483647")); - Assertions.assertEquals(2, s.calculate("1 + 1")); - Assertions.assertEquals(3, s.calculate("2 - 1 + 2")); - } - - static class Solution { - - public int calculate(String s) { - Stack stack = new Stack<>(); - Map map = new HashMap<>(); - for (int i = 0; i < s.length(); i++) { - if (s.charAt(i) == '(') { - stack.push(i); - } else if (s.charAt(i) == ')') { - map.put(stack.pop(), i); - } - } - return calculate(s, 0, s.length() - 1, map); - } - - public int calculate(String s, int start, int end, Map map) { - int num = 0; - char sign = '+'; - Stack stack = new Stack<>(); - for (int i = start; i <= end; i++) { - char c = s.charAt(i); - if (Character.isDigit(c)) { - num = num * 10 + (c - '0'); - } - if (c == '(') { - num = calculate(s, i + 1, map.get(i) - 1, map); - i = map.get(i); - } - - if (c == '+' || c == '-' || c == '*' || c == '/' || i == end) { - int pre = 0; - switch (sign) { - case '+': - stack.push(num); - break; - case '-': - stack.push(-num); - break; - case '*': - pre = stack.pop(); - stack.push(pre * num); - break; - case '/': - pre = stack.pop(); - stack.push(pre / num); - break; - default: - break; - } - sign = c; - num = 0; - } - } - - int result = 0; - while (!stack.isEmpty()) { - result += stack.pop(); - } - return result; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" deleted file mode 100644 index 6fe15e1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\345\237\272\346\234\254\350\256\241\347\256\227\345\231\2502.java" +++ /dev/null @@ -1,72 +0,0 @@ -package io.github.dunwu.algorithm.design; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 227. 基本计算器 II - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 基本计算器2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2147483647, s.calculate("2147483647")); - Assertions.assertEquals(2, s.calculate("1 + 1")); - Assertions.assertEquals(3, s.calculate("2 - 1 + 2")); - Assertions.assertEquals(7, s.calculate("3+2*2")); - } - - static class Solution { - - public int calculate(String s) { - return calculate(s, 0, s.length() - 1); - } - - public int calculate(String s, int start, int end) { - int num = 0; - char sign = '+'; - Stack stack = new Stack<>(); - for (int i = start; i <= end; i++) { - char c = s.charAt(i); - if (Character.isDigit(c)) { - num = num * 10 + (c - '0'); - } - if (c == '+' || c == '-' || c == '*' || c == '/' || i == s.length() - 1) { - int pre = 0; - switch (sign) { - case '+': - stack.push(num); - break; - case '-': - stack.push(-num); - break; - case '*': - pre = stack.pop(); - stack.push(pre * num); - break; - case '/': - pre = stack.pop(); - stack.push(pre / num); - break; - default: - break; - } - sign = c; - num = 0; - } - } - - int result = 0; - while (!stack.isEmpty()) { - result += stack.pop(); - } - return result; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" deleted file mode 100644 index 58424c4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\210\221\347\232\204\346\227\245\347\250\213\345\256\211\346\216\222\350\241\250.java" +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.design; - -import org.junit.jupiter.api.Assertions; - -import java.util.TreeMap; - -/** - * 729. 我的日程安排表 I - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 我的日程安排表 { - - public static void main(String[] args) { - MyCalendar s = new MyCalendar(); - Assertions.assertTrue(s.book(10, 20)); - Assertions.assertFalse(s.book(15, 25)); - Assertions.assertTrue(s.book(20, 30)); - } - - static class MyCalendar { - - private TreeMap calendar = null; - - public MyCalendar() { - calendar = new TreeMap<>(); - } - - public boolean book(int start, int end) { - Integer earlier = calendar.floorKey(start); - Integer later = calendar.ceilingKey(start); - if (later != null && later < end) { - return false; - } - if (earlier != null && start < calendar.get(earlier)) { - return false; - } - calendar.put(start, end); - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" deleted file mode 100644 index e1f68e8..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214.java" +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dunwu.algorithm.design; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; - -/** - * 950. 按递增顺序显示卡牌 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 按递增顺序显示卡牌 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 2, 13, 3, 11, 5, 17, 7 } - , s.deckRevealedIncreasing(new int[] { 17, 13, 11, 2, 3, 5, 7 })); - } - - static class Solution { - - public int[] deckRevealedIncreasing(int[] deck) { - int n = deck.length; - LinkedList res = new LinkedList<>(); - Arrays.sort(deck); - for (int i = n - 1; i >= 0; i--) { - if (!res.isEmpty()) { - res.addFirst(res.removeLast()); - } - res.addFirst(deck[i]); - } - int[] arr = new int[n]; - for (int i = 0; i < res.size(); i++) { - arr[i] = res.get(i); - } - return arr; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" deleted file mode 100644 index 2f0b46d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\346\227\240\346\263\225\345\220\203\345\215\210\351\244\220\347\232\204\345\255\246\347\224\237\346\225\260\351\207\217.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.design; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 1700. 无法吃午餐的学生数量 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 无法吃午餐的学生数量 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(0, s.countStudents(new int[] { 1, 1, 0, 0 }, new int[] { 0, 1, 0, 1 })); - Assertions.assertEquals(3, s.countStudents(new int[] { 1, 1, 1, 0, 0, 1 }, new int[] { 1, 0, 0, 0, 1, 1 })); - } - - static class Solution { - - public int countStudents(int[] students, int[] sandwiches) { - int total = students.length; - LinkedList studentQueue = new LinkedList<>(); - for (int s : students) { - studentQueue.addLast(s); - } - int matchNum = 0; - while (matchNum < sandwiches.length) { - int notMatchNum = 0; - int size = studentQueue.size(); - while (notMatchNum < size) { - Integer s = studentQueue.removeFirst(); - if (s == sandwiches[matchNum]) { - matchNum++; - break; - } else { - studentQueue.addLast(s); - notMatchNum++; - } - } - if (notMatchNum == size) { - break; - } - } - return total - matchNum; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\350\256\241\347\256\227\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\350\256\241\347\256\227\345\231\250.java" deleted file mode 100644 index 5e32109..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/design/\350\256\241\347\256\227\345\231\250.java" +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.dunwu.algorithm.design; - -import java.util.Arrays; - -/** - * 计数器模板 - * - * @author Zhang Peng - * @date 2025-10-31 - */ -public class 计算器 { - - public static void main(String[] args) { - Solution s = new Solution(); - System.out.println("args = " + Arrays.toString(args)); - } - - static class Solution { - - public int toNum(String s) { - if (s == null || s.length() == 0) { return 0; } - int num = 0; - for (char c : s.toCharArray()) { - num = num * 10 + (c - '0'); - } - return num; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/package-info.java deleted file mode 100644 index 6b44e2d..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * DFS 解岛屿数类型问题 - * - * @author Zhang Peng - * @date 2025-12-15 - */ -package io.github.dunwu.algorithm.dfs.island; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" deleted file mode 100644 index c6bafac..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\346\225\260\351\207\217.java" +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.dunwu.algorithm.dfs.island; - -import org.junit.jupiter.api.Assertions; - -/** - * 200. 岛屿数量 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 岛屿数量 { - - public static void main(String[] args) { - Solution s = new Solution(); - - char[][] input = { - { '1', '1', '1', '1', '0' }, - { '1', '1', '0', '1', '0' }, - { '1', '1', '0', '0', '0' }, - { '0', '0', '0', '0', '0' } - }; - Assertions.assertEquals(1, s.numIslands(input)); - - char[][] input2 = { - { '1', '1', '0', '0', '0' }, - { '1', '1', '0', '0', '0' }, - { '0', '0', '1', '0', '0' }, - { '0', '0', '0', '1', '1' } - }; - Assertions.assertEquals(3, s.numIslands(input2)); - } - - static class Solution { - - private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; - - public int numIslands(char[][] grid) { - if (grid == null || grid.length == 0) { return 0; } - int res = 0; - int m = grid.length, n = grid[0].length; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (grid[i][j] == '1') { - // 每发现一个岛屿,岛屿数量加一 - res++; - // 然后使用 DFS 将岛屿淹了 - dfs(grid, i, j); - } - } - } - return res; - } - - // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 - public void dfs(char[][] grid, int x, int y) { - int m = grid.length, n = grid[0].length; - if (x < 0 || x >= m || y < 0 || y >= n) { return; } - if (grid[x][y] == '0') { return; } - - grid[x][y] = '0'; - for (int[] d : directions) { - int i = x + d[0], j = y + d[1]; - dfs(grid, i, j); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" deleted file mode 100644 index df3719e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\345\262\233\345\261\277\347\232\204\346\234\200\345\244\247\351\235\242\347\247\257.java" +++ /dev/null @@ -1,71 +0,0 @@ -package io.github.dunwu.algorithm.dfs.island; - -import org.junit.jupiter.api.Assertions; - -/** - * 695. 岛屿的最大面积 - * - * @author Zhang Peng - * @date 2025-11-05 - */ -public class 岛屿的最大面积 { - - public static void main(String[] args) { - Solution s = new Solution(); - - int[][] input = { - { 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, - { 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0 }, - { 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 } - }; - Assertions.assertEquals(6, s.maxAreaOfIsland(input)); - - int[][] input2 = { { 0, 0, 0, 0, 0, 0, 0, 0 } }; - Assertions.assertEquals(0, s.maxAreaOfIsland(input2)); - } - - static class Solution { - - private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; - - public int maxAreaOfIsland(int[][] grid) { - - // base case - if (grid == null || grid.length == 0) return 0; - - int res = 0; - int m = grid.length, n = grid[0].length; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (grid[i][j] == 1) { - int size = dfs(grid, i, j); - res = Math.max(res, size); - } - } - } - return res; - } - - // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 - public int dfs(int[][] grid, int x, int y) { - int m = grid.length, n = grid[0].length; - if (x < 0 || x >= m || y < 0 || y >= n) { return 0; } - if (grid[x][y] == 0) { return 0; } - - int cnt = 1; - grid[x][y] = 0; - for (int[] d : directions) { - int i = x + d[0], j = y + d[1]; - cnt += dfs(grid, i, j); - } - return cnt; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" deleted file mode 100644 index 535ae08..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\255\220\345\262\233\345\261\277.java" +++ /dev/null @@ -1,93 +0,0 @@ -package io.github.dunwu.algorithm.dfs.island; - -import org.junit.jupiter.api.Assertions; - -/** - * 1905. 统计子岛屿 - * - * @author Zhang Peng - * @date 2025-11-05 - */ -public class 统计子岛屿 { - - public static void main(String[] args) { - Solution s = new Solution(); - - int[][] gridA1 = { - { 1, 1, 1, 0, 0 }, - { 0, 1, 1, 1, 1 }, - { 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0 }, - { 1, 1, 0, 1, 1 } - }; - int[][] gridB1 = { - { 1, 1, 1, 0, 0 }, - { 0, 0, 1, 1, 1 }, - { 0, 1, 0, 0, 0 }, - { 1, 0, 1, 1, 0 }, - { 0, 1, 0, 1, 0 } - }; - Assertions.assertEquals(3, s.countSubIslands(gridA1, gridB1)); - - int[][] gridA2 = { - { 1, 0, 1, 0, 1 }, - { 1, 1, 1, 1, 1 }, - { 0, 0, 0, 0, 0 }, - { 1, 1, 1, 1, 1 }, - { 1, 0, 1, 0, 1 } - }; - int[][] gridB2 = { - { 0, 0, 0, 0, 0 }, - { 1, 1, 1, 1, 1 }, - { 0, 1, 0, 1, 0 }, - { 0, 1, 0, 1, 0 }, - { 1, 0, 0, 0, 1 } - }; - Assertions.assertEquals(2, s.countSubIslands(gridA2, gridB2)); - } - - static class Solution { - - private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; - - public int countSubIslands(int[][] grid1, int[][] grid2) { - int m = grid1.length, n = grid1[0].length; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (grid1[i][j] == 0 && grid2[i][j] == 1) { - // 这个岛屿肯定不是子岛,淹掉 - dfs(grid2, i, j); - } - } - } - - int res = 0; - // 现在 grid2 中剩下的岛屿都是子岛,计算岛屿数量 - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (grid2[i][j] == 1) { - res++; - dfs(grid2, i, j); - } - } - } - return res; - } - - // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 - public void dfs(int[][] grid, int x, int y) { - // base case - int m = grid.length, n = grid[0].length; - if (x < 0 || x >= m || y < 0 || y >= n) { return; } - if (grid[x][y] == 0) { return; } - - grid[x][y] = 0; - for (int[] d : directions) { - int i = x + d[0], j = y + d[1]; - dfs(grid, i, j); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" deleted file mode 100644 index 20975ca..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\347\273\237\350\256\241\345\260\201\351\227\255\345\262\233\345\261\277\347\232\204\346\225\260\347\233\256.java" +++ /dev/null @@ -1,86 +0,0 @@ -package io.github.dunwu.algorithm.dfs.island; - -import org.junit.jupiter.api.Assertions; - -/** - * 1254. 统计封闭岛屿的数目 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 统计封闭岛屿的数目 { - - public static void main(String[] args) { - Solution s = new Solution(); - - int[][] input = { - { 1, 1, 1, 1, 1, 1, 1, 0 }, - { 1, 0, 0, 0, 0, 1, 1, 0 }, - { 1, 0, 1, 0, 1, 1, 1, 0 }, - { 1, 0, 0, 0, 0, 1, 0, 1 }, - { 1, 1, 1, 1, 1, 1, 1, 0 } - }; - Assertions.assertEquals(2, s.closedIsland(input)); - - int[][] input2 = { - { 1, 1, 1, 1, 1, 1, 1 }, - { 1, 0, 0, 0, 0, 0, 1 }, - { 1, 0, 1, 1, 1, 0, 1 }, - { 1, 0, 1, 0, 1, 0, 1 }, - { 1, 0, 1, 1, 1, 0, 1 }, - { 1, 0, 0, 0, 0, 0, 1 }, - { 1, 1, 1, 1, 1, 1, 1 } - }; - Assertions.assertEquals(2, s.closedIsland(input2)); - } - - static class Solution { - - private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; - - public int closedIsland(int[][] grid) { - - // base case - if (grid == null || grid.length == 0) { return 0; } - - // 将靠边的岛屿淹没 - int m = grid.length, n = grid[0].length; - for (int j = 0; j < n; j++) { - dfs(grid, 0, j); - dfs(grid, m - 1, j); - } - for (int i = 0; i < m; i++) { - dfs(grid, i, 0); - dfs(grid, i, n - 1); - } - - int res = 0; - // 遍历 grid,剩下的岛屿都是封闭岛屿 - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (grid[i][j] == 0) { - res++; - dfs(grid, i, j); - } - } - } - return res; - } - - // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 - public void dfs(int[][] grid, int x, int y) { - // base case - int m = grid.length, n = grid[0].length; - if (x < 0 || x >= m || y < 0 || y >= n) { return; } - if (grid[x][y] == 1) { return; } - - grid[x][y] = 1; - for (int[] d : directions) { - int i = x + d[0], j = y + d[1]; - dfs(grid, i, j); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" deleted file mode 100644 index 7bdaa0c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/island/\351\243\236\345\234\260\347\232\204\346\225\260\351\207\217.java" +++ /dev/null @@ -1,80 +0,0 @@ -package io.github.dunwu.algorithm.dfs.island; - -import org.junit.jupiter.api.Assertions; - -/** - * 1020. 飞地的数量/a> - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 飞地的数量 { - - public static void main(String[] args) { - Solution s = new Solution(); - - int[][] input = { - { 0, 0, 0, 0 }, - { 1, 0, 1, 0 }, - { 0, 1, 1, 0 }, - { 0, 0, 0, 0 } - }; - Assertions.assertEquals(3, s.numEnclaves(input)); - - int[][] input2 = { - { 0, 1, 1, 0 }, - { 0, 0, 1, 0 }, - { 0, 0, 1, 0 }, - { 0, 0, 0, 0 } - }; - Assertions.assertEquals(0, s.numEnclaves(input2)); - } - - static class Solution { - - private final int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; - - public int numEnclaves(int[][] grid) { - - // base case - if (grid == null || grid.length == 0) { return 0; } - - int m = grid.length, n = grid[0].length; - for (int j = 0; j < n; j++) { - dfs(grid, 0, j); - dfs(grid, m - 1, j); - } - for (int i = 0; i < m; i++) { - dfs(grid, i, 0); - dfs(grid, i, n - 1); - } - - int res = 0; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (grid[i][j] == 1) { - res += dfs(grid, i, j); - } - } - } - return res; - } - - // 淹没与 (x, y) 相邻的陆地,并返回淹没的陆地面积 - public int dfs(int[][] grid, int x, int y) { - int m = grid.length, n = grid[0].length; - if (x < 0 || x >= m || y < 0 || y >= n) { return 0; } - if (grid[x][y] == 0) { return 0; } - - int cnt = 1; - grid[x][y] = 0; - for (int[] d : directions) { - int i = x + d[0], j = y + d[1]; - cnt += dfs(grid, i, j); - } - return cnt; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/package-info.java deleted file mode 100644 index 3192edb..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 通过回溯算法解决排列、组合、子集类型的问题 - * - * @author Zhang Peng - * @date 2025-12-13 - */ -package io.github.dunwu.algorithm.dfs.permutation_combination; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\227.java" deleted file mode 100644 index 6062839..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\227.java" +++ /dev/null @@ -1,77 +0,0 @@ -package io.github.dunwu.algorithm.dfs.permutation_combination; - -import cn.hutool.core.collection.CollectionUtil; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 46. 全排列 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 全排列 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] expect = { { 1, 2, 3 }, { 1, 3, 2 }, { 2, 1, 3 }, { 2, 3, 1 }, { 3, 1, 2 }, { 3, 2, 1 } }; - int[][] expect2 = { { 0, 1 }, { 1, 0 } }; - Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.permute(new int[] { 1, 2, 3 }))); - Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(s.permute(new int[] { 0, 1 }))); - Assertions.assertArrayEquals(new int[][] { { 1 } }, ArrayUtil.toIntMatrixArray(s.permute(new int[] { 1 }))); - } - - static class Solution { - - // 「路径」中的元素会被标记为 true,避免重复使用 - boolean[] visited; - // 记录「路径」 - LinkedList path; - List> res; - - // 主函数,输入一组不重复的数字,返回它们的全排列 - List> permute(int[] nums) { - visited = new boolean[nums.length]; - path = new LinkedList<>(); - res = new LinkedList<>(); - backtrack(nums); - return res; - } - - // 路径:记录在 path 中 - // 选择列表:nums 中不存在于 path 的那些元素(visited[i] 为 false) - // 结束条件:nums 中的元素全都在 path 中出现 - void backtrack(int[] nums) { - // 【结束】【前序】到达决策树叶子节点,可以记录结果 - if (path.size() == nums.length) { - res.add(new LinkedList<>(path)); - System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); - return; - } - - for (int i = 0; i < nums.length; i++) { - - // 排除不合法的选择 - // nums[i] 已经在 path 中,跳过 - if (visited[i]) { continue; } - - // 【选择】 - path.add(nums[i]); - visited[i] = true; - System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); - - // 【回溯】 - backtrack(nums); - - // 【取消选择】 - path.removeLast(); - visited[i] = false; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\2272.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\2272.java" deleted file mode 100644 index 038cdda..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\205\250\346\216\222\345\210\2272.java" +++ /dev/null @@ -1,76 +0,0 @@ -package io.github.dunwu.algorithm.dfs.permutation_combination; - -import cn.hutool.core.collection.CollectionUtil; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 47. 全排列 II - * LCR 084. 全排列 II - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 全排列2 { - - public static void main(String[] args) { - Solution s = new Solution(); - - int[][] expect = { { 1, 1, 2 }, { 1, 2, 1 }, { 2, 1, 1 } }; - Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.permuteUnique(new int[] { 1, 1, 2 }))); - - int[][] expect2 = { { 1, 2, 3 }, { 1, 3, 2 }, { 2, 1, 3 }, { 2, 3, 1 }, { 3, 1, 2 }, { 3, 2, 1 } }; - Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(s.permuteUnique(new int[] { 1, 2, 3 }))); - } - - static class Solution { - - private boolean[] visited; - private List path; - private List> res; - - public List> permuteUnique(int[] nums) { - visited = new boolean[nums.length]; - path = new LinkedList<>(); - res = new LinkedList<>(); - Arrays.sort(nums); - backtrack(nums); - return res; - } - - public void backtrack(int[] nums) { - - // 【结束】【前序】到达决策树叶子节点,可以记录结果 - if (path.size() == nums.length) { - res.add(new LinkedList<>(path)); - System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); - } - - for (int i = 0; i < nums.length; i++) { - - // 排除不合法的选择 - if (visited[i]) { continue; } - // 剪枝逻辑,固定相同的元素在排列中的相对位置 - if (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) { continue; } - - // 【选择】 - visited[i] = true; - path.add(nums[i]); - System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); - - // 【回溯】 - backtrack(nums); - - // 【取消选择】 - path.remove(path.size() - 1); - visited[i] = false; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\206.java" deleted file mode 100644 index ce2377e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\206.java" +++ /dev/null @@ -1,70 +0,0 @@ -package io.github.dunwu.algorithm.dfs.permutation_combination; - -import cn.hutool.core.collection.CollectionUtil; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 78. 子集 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 子集 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] expect = { {}, { 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 3 }, { 2 }, { 2, 3 }, { 3 } }; - Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.subsets(new int[] { 1, 2, 3 }))); - Assertions.assertArrayEquals(new int[][] { {}, { 0 } }, ArrayUtil.toIntMatrixArray(s.subsets(new int[] { 0 }))); - } - - static class Solution { - - private boolean[] visited; - private List path; - private List> res; - - // 主函数 - public List> subsets(int[] nums) { - visited = new boolean[nums.length]; - path = new LinkedList<>(); - res = new LinkedList<>(); - Arrays.sort(nums); - backtrack(nums, 0); - return res; - } - - // 回溯算法核心函数,遍历子集问题的回溯树 - public void backtrack(int[] nums, int start) { - - // 【结束】【前序】到达决策树叶子节点,可以记录结果 - res.add(new LinkedList<>(path)); - System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); - - for (int i = start; i < nums.length; i++) { - - // 排除不合法的选择 - if (visited[i]) { continue; } - - // 【选择】 - visited[i] = true; - path.add(nums[i]); - System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); - - // 【回溯】 - backtrack(nums, i + 1); - - // 【取消选择】 - path.remove(path.size() - 1); - visited[i] = false; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\2062.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\2062.java" deleted file mode 100644 index d09fb5e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\345\255\220\351\233\2062.java" +++ /dev/null @@ -1,71 +0,0 @@ -package io.github.dunwu.algorithm.dfs.permutation_combination; - -import cn.hutool.core.collection.CollectionUtil; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 90. 子集 II - *

- * 元素可重复,不可复选 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 子集2 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - int[][] expect = { {}, { 1 }, { 1, 2 }, { 1, 2, 2 }, { 2 }, { 2, 2 } }; - Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.subsetsWithDup(new int[] { 1, 2, 2 }))); - - int[][] expect2 = { {}, { 0 } }; - Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(s.subsetsWithDup(new int[] { 0 }))); - } - - static class Solution { - - private List> res; - private LinkedList path; - - public List> subsetsWithDup(int[] nums) { - path = new LinkedList<>(); - res = new LinkedList<>(); - // 先排序,让相同的元素靠在一起 - Arrays.sort(nums); - backtrack(nums, 0); - return res; - } - - public void backtrack(int[] nums, int start) { - - // 【结束】 - res.add(new LinkedList<>(path)); - System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); - - for (int i = start; i < nums.length; i++) { - - // 剪枝逻辑,值相同的相邻树枝,只遍历第一条 - if (i > start && nums[i] == nums[i - 1]) continue; - - // 【选择】 - path.add(nums[i]); - System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); - - // 【回溯】 - backtrack(nums, i + 1); - - // 【取消选择】 - path.remove(path.size() - 1); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210.java" deleted file mode 100644 index c29d190..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210.java" +++ /dev/null @@ -1,61 +0,0 @@ -package io.github.dunwu.algorithm.dfs.permutation_combination; - -import cn.hutool.core.collection.CollectionUtil; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 77. 组合 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 组合 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] expect = { { 1, 2 }, { 1, 3 }, { 1, 4 }, { 2, 3 }, { 2, 4 }, { 3, 4 } }; - Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(s.combine(4, 2))); - Assertions.assertArrayEquals(new int[][] { { 1 } }, ArrayUtil.toIntMatrixArray(s.combine(1, 1))); - } - - static class Solution { - - private List path; - private List> res; - - public List> combine(int n, int k) { - path = new LinkedList<>(); - res = new LinkedList<>(); - backtrack(n, k, 1); - return res; - } - - public void backtrack(int n, int k, int s) { - - // 【结束】 - if (path.size() == k) { - res.add(new LinkedList<>(path)); - System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); - } - - for (int i = s; i <= n; i++) { - // 【选择】 - path.add(i); - System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); - - // 【回溯】 - // 通过 start 参数控制树枝的遍历,避免产生重复的子集 - backtrack(n, k, i + 1); - - // 【取消选择】 - path.remove(path.size() - 1); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\214.java" deleted file mode 100644 index 8deb466..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\214.java" +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.dunwu.algorithm.dfs.permutation_combination; - -import cn.hutool.core.collection.CollectionUtil; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 39. 组合总和 - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 组合总和 { - - public static void main(String[] args) { - Solution s = new Solution(); - - List> output = s.combinationSum(new int[] { 2, 3, 6, 7 }, 7); - Assertions.assertArrayEquals(new int[][] { { 2, 2, 3 }, { 7 } }, ArrayUtil.toIntMatrixArray(output)); - - List> output2 = s.combinationSum(new int[] { 2, 3, 5 }, 8); - Assertions.assertArrayEquals(new int[][] { { 2, 2, 2, 2 }, { 2, 3, 3 }, { 3, 5 } }, - ArrayUtil.toIntMatrixArray(output2)); - } - - static class Solution { - - private int sum; - private List path; - private List> res; - - public List> combinationSum(int[] candidates, int target) { - sum = 0; - path = new LinkedList<>(); - res = new LinkedList<>(); - Arrays.sort(candidates); - backtrack(candidates, target, 0); - return res; - } - - public void backtrack(int[] nums, int target, int start) { - - // 【结束】【前序】找到目标和,记录结果 - if (sum == target) { - res.add(new LinkedList<>(path)); - System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); - return; - } - // base case,超过目标和,停止向下遍历 - if (sum > target) { return; } - - for (int i = start; i < nums.length; i++) { - // 【选择】 - sum += nums[i]; - path.add(nums[i]); - System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); - - // 【回溯】 - // 同一元素可重复使用,注意参数 - backtrack(nums, target, i); - - // 【取消选择】 - path.remove(path.size() - 1); - sum -= nums[i]; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2142.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2142.java" deleted file mode 100644 index e57c58c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2142.java" +++ /dev/null @@ -1,86 +0,0 @@ -package io.github.dunwu.algorithm.dfs.permutation_combination; - -import cn.hutool.core.collection.CollectionUtil; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 40. 组合总和 II - * LCR 082. 组合总和 II - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 组合总和2 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - List> output = s.combinationSum2(new int[] { 10, 1, 2, 7, 6, 1, 5 }, 8); - int[][] expect = { { 1, 1, 6 }, { 1, 2, 5 }, { 1, 7 }, { 2, 6 } }; - Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(output)); - - List> output2 = s.combinationSum2(new int[] { 2, 5, 2, 1, 2 }, 5); - int[][] expect2 = { { 1, 2, 2 }, { 5 } }; - Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(output2)); - } - - static class Solution { - - private int sum; - private boolean[] visited; - private List path; - private List> res; - - public List> combinationSum2(int[] candidates, int target) { - sum = 0; - visited = new boolean[candidates.length]; - path = new ArrayList<>(); - res = new ArrayList<>(); - Arrays.sort(candidates); - backtrack(candidates, target, 0); - return res; - } - - public void backtrack(int[] nums, int target, int start) { - - // 【结束】【前序】找到目标和,记录结果 - if (sum == target) { - res.add(new LinkedList<>(path)); - System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); - return; - } - // base case,超过目标和,停止向下遍历 - if (sum > target) { return; } - - for (int i = start; i < nums.length; i++) { - - // 剪枝逻辑 - if (visited[i]) { continue; } - if (i > start && nums[i] == nums[i - 1] && !visited[i - 1]) { continue; } - - // 【选择】 - sum += nums[i]; - visited[i] = true; - path.add(nums[i]); - System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); - - // 【回溯】 - backtrack(nums, target, i + 1); - - // 【取消选择】 - path.remove(path.size() - 1); - visited[i] = false; - sum -= nums[i]; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2143.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2143.java" deleted file mode 100644 index c0128a6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/permutation_combination/\347\273\204\345\220\210\346\200\273\345\222\2143.java" +++ /dev/null @@ -1,83 +0,0 @@ -package io.github.dunwu.algorithm.dfs.permutation_combination; - -import cn.hutool.core.collection.CollectionUtil; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 216. 组合总和 III - * - * @author Zhang Peng - * @date 2025-11-04 - */ -public class 组合总和3 { - - public static void main(String[] args) { - Solution s = new Solution(); - - Assertions.assertArrayEquals(new int[][] { { 1, 2, 4 } }, ArrayUtil.toIntMatrixArray(s.combinationSum3(3, 7))); - - int[][] expect2 = { { 1, 2, 6 }, { 1, 3, 5 }, { 2, 3, 4 } }; - Assertions.assertArrayEquals(expect2, ArrayUtil.toIntMatrixArray(s.combinationSum3(3, 9))); - - Assertions.assertArrayEquals(new int[][] {}, ArrayUtil.toIntMatrixArray(s.combinationSum3(4, 1))); - } - - static class Solution { - - private int sum; - private boolean[] visited; - private List path; - private List> res; - - public List> combinationSum3(int k, int n) { - sum = 0; - visited = new boolean[9]; - path = new LinkedList<>(); - res = new LinkedList<>(); - int[] nums = new int[9]; - for (int i = 0; i < 9; i++) { - nums[i] = i + 1; - } - backtrack(nums, n, k, 0); - return res; - } - - public void backtrack(int[] nums, int target, int k, int s) { - - // 【结束】【前序】找到目标和,记录结果 - if (sum == target && path.size() == k) { - res.add(new LinkedList<>(path)); - System.out.printf("【结果】 %s\n\n", CollectionUtil.join(path, " -> ")); - return; - } - // base case,超过目标和,停止向下遍历 - if (sum > target || path.size() > k) { return; } - - for (int i = s; i < nums.length; i++) { - - if (visited[i]) { continue; } - - // 【选择】 - sum += nums[i]; - visited[i] = true; - path.add(nums[i]); - System.out.printf("\t\t%s\n", CollectionUtil.join(path, " -> ")); - - // 【回溯】 - // 同一元素可重复使用,注意参数 - backtrack(nums, target, k, i + 1); - - // 【取消选择】 - path.remove(path.size() - 1); - visited[i] = false; - sum -= nums[i]; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\216.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\216.java" deleted file mode 100644 index 9e15542..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\216.java" +++ /dev/null @@ -1,96 +0,0 @@ -package io.github.dunwu.algorithm.dfs.sudoku; - -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * 51. N 皇后 - * - * @author Zhang Peng - * @since 2020-07-04 - */ -public class N皇后 { - - public static void main(String[] args) { - Solution s = new Solution(); - List> output = s.solveNQueens(4); - String[][] expect = { { ".Q..", "...Q", "Q...", "..Q." }, { "..Q.", "Q...", "...Q", ".Q.." } }; - Assertions.assertArrayEquals(expect, ArrayUtil.toStringMatrixArray(output)); - - List> output2 = s.solveNQueens(1); - String[][] expect2 = { { "Q" } }; - Assertions.assertArrayEquals(expect2, ArrayUtil.toStringMatrixArray(output2)); - } - - static class Solution { - - private List> res; - - // 输入棋盘边长 n,返回所有合法的放置 - public List> solveNQueens(int n) { - res = new ArrayList<>(); - // '.' 表示空,'Q' 表示皇后,初始化空棋盘。 - char[] arr = new char[n]; - Arrays.fill(arr, '.'); - String str = new String(arr); - List board = new ArrayList<>(); - for (int i = 0; i < n; i++) { - board.add(str); - } - backtrack(board, 0); - return res; - } - - // 路径:board 中小于 row 的那些行都已经成功放置了皇后 - // 选择列表:第 row 行的所有列都是放置皇后的选择 - // 结束条件:row 超过 board 的最后一行 - public void backtrack(List board, int row) { - // 触发结束条件 - if (row == board.size()) { - res.add(new ArrayList<>(board)); - return; - } - - int n = board.get(row).length(); - for (int col = 0; col < n; col++) { - // 排除不合法选择 - if (!isValid(board, row, col)) { - continue; - } - // 做选择 - char[] newRow = board.get(row).toCharArray(); - newRow[col] = 'Q'; - board.set(row, new String(newRow)); - // 进入下一行决策 - backtrack(board, row + 1); - // 撤销选择 - newRow[col] = '.'; - board.set(row, new String(newRow)); - } - } - - // 是否可以在 board[row][col] 放置皇后? - public boolean isValid(List board, int row, int col) { - int n = board.size(); - // 检查列是否有皇后互相冲突 - for (int i = 0; i < row; i++) { - if (board.get(i).charAt(col) == 'Q') { return false; } - } - // 检查右上方是否有皇后互相冲突 - for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { - if (board.get(i).charAt(j) == 'Q') { return false; } - } - // 检查左上方是否有皇后互相冲突 - for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { - if (board.get(i).charAt(j) == 'Q') { return false; } - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\2162.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\2162.java" deleted file mode 100644 index c9a72cf..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/N\347\232\207\345\220\2162.java" +++ /dev/null @@ -1,94 +0,0 @@ -package io.github.dunwu.algorithm.dfs.sudoku; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * 52. N皇后II - * - * @author Zhang Peng - * @since 2020-07-04 - */ -public class N皇后2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.totalNQueens(4)); - Assertions.assertEquals(1, s.totalNQueens(1)); - } - - static class Solution { - - private List> res; - - public int totalNQueens(int n) { - return solveNQueens(n).size(); - } - - // 输入棋盘边长 n,返回所有合法的放置 - public List> solveNQueens(int n) { - res = new ArrayList<>(); - // '.' 表示空,'Q' 表示皇后,初始化空棋盘。 - char[] arr = new char[n]; - Arrays.fill(arr, '.'); - String str = new String(arr); - List board = new ArrayList<>(); - for (int i = 0; i < n; i++) { - board.add(str); - } - backtrack(board, 0); - return res; - } - - // 路径:board 中小于 row 的那些行都已经成功放置了皇后 - // 选择列表:第 row 行的所有列都是放置皇后的选择 - // 结束条件:row 超过 board 的最后一行 - public void backtrack(List board, int row) { - // 触发结束条件 - if (row == board.size()) { - res.add(new ArrayList<>(board)); - return; - } - - int n = board.get(row).length(); - for (int col = 0; col < n; col++) { - // 排除不合法选择 - if (!isValid(board, row, col)) { - continue; - } - // 做选择 - char[] newRow = board.get(row).toCharArray(); - newRow[col] = 'Q'; - board.set(row, new String(newRow)); - // 进入下一行决策 - backtrack(board, row + 1); - // 撤销选择 - newRow[col] = '.'; - board.set(row, new String(newRow)); - } - } - - // 是否可以在 board[row][col] 放置皇后? - public boolean isValid(List board, int row, int col) { - int n = board.size(); - // 检查列是否有皇后互相冲突 - for (int i = 0; i < row; i++) { - if (board.get(i).charAt(col) == 'Q') { return false; } - } - // 检查右上方是否有皇后互相冲突 - for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { - if (board.get(i).charAt(j) == 'Q') { return false; } - } - // 检查左上方是否有皇后互相冲突 - for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { - if (board.get(i).charAt(j) == 'Q') { return false; } - } - return true; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/package-info.java deleted file mode 100644 index 34ca619..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 回溯算法解数独、N 皇后问题 - * - * @author Zhang Peng - * @date 2025-12-13 - */ -package io.github.dunwu.algorithm.dfs.sudoku; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/\350\247\243\346\225\260\347\213\254.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/\350\247\243\346\225\260\347\213\254.java" deleted file mode 100644 index 3a198c3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/sudoku/\350\247\243\346\225\260\347\213\254.java" +++ /dev/null @@ -1,249 +0,0 @@ -package io.github.dunwu.algorithm.dfs.sudoku; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * 37. 解数独 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 解数独 { - - public static void main(String[] args) { - - char[][] expect = { - { '5', '3', '4', '6', '7', '8', '9', '1', '2' }, - { '6', '7', '2', '1', '9', '5', '3', '4', '8' }, - { '1', '9', '8', '3', '4', '2', '5', '6', '7' }, - { '8', '5', '9', '7', '6', '1', '4', '2', '3' }, - { '4', '2', '6', '8', '5', '3', '7', '9', '1' }, - { '7', '1', '3', '9', '2', '4', '8', '5', '6' }, - { '9', '6', '1', '5', '3', '7', '2', '8', '4' }, - { '2', '8', '7', '4', '1', '9', '6', '3', '5' }, - { '3', '4', '5', '2', '8', '6', '1', '7', '9' } - }; - char[][] input = { - { '5', '3', '.', '.', '7', '.', '.', '.', '.' }, - { '6', '.', '.', '1', '9', '5', '.', '.', '.' }, - { '.', '9', '8', '.', '.', '.', '.', '6', '.' }, - { '8', '.', '.', '.', '6', '.', '.', '.', '3' }, - { '4', '.', '.', '8', '.', '3', '.', '.', '1' }, - { '7', '.', '.', '.', '2', '.', '.', '.', '6' }, - { '.', '6', '.', '.', '.', '.', '2', '8', '.' }, - { '.', '.', '.', '4', '1', '9', '.', '.', '5' }, - { '.', '.', '.', '.', '8', '.', '.', '7', '9' } - }; - char[][] input2 = { - { '5', '3', '.', '.', '7', '.', '.', '.', '.' }, - { '6', '.', '.', '1', '9', '5', '.', '.', '.' }, - { '.', '9', '8', '.', '.', '.', '.', '6', '.' }, - { '8', '.', '.', '.', '6', '.', '.', '.', '3' }, - { '4', '.', '.', '8', '.', '3', '.', '.', '1' }, - { '7', '.', '.', '.', '2', '.', '.', '.', '6' }, - { '.', '6', '.', '.', '.', '.', '2', '8', '.' }, - { '.', '.', '.', '4', '1', '9', '.', '.', '5' }, - { '.', '.', '.', '.', '8', '.', '.', '7', '9' } - }; - - Solution s = new Solution(); - s.solveSudoku(input); - Assertions.assertArrayEquals(expect, input); - - Solution2 s2 = new Solution2(); - s2.solveSudoku(input2); - Assertions.assertArrayEquals(expect, input2); - } - - static class Solution { - - private int n; - // 标记是否已经找到可行解 - boolean found = false; - - public void solveSudoku(char[][] board) { - n = board.length; - backtrack(board, 0); - } - - // 路径:board 中小于 index 的位置所填的数字 - // 选择列表:数字 1~9 - // 结束条件:整个 board 都填满数字 - void backtrack(char[][] board, int index) { - if (found) { - // 已经找到一个可行解,立即结束 - return; - } - - int[] point = point(index); - int row = point[0], col = point[1]; - if (index == n * n) { - // 找到一个可行解,触发 base case - found = true; - return; - } - - if (board[row][col] != '.') { - // 如果有预设数字,不用我们穷举 - backtrack(board, index + 1); - return; - } - - for (char ch = '1'; ch <= '9'; ch++) { - // 剪枝:如果遇到不合法的数字,就跳过 - if (!isValid(board, row, col, ch)) { continue; } - - // 做选择 - board[row][col] = ch; - - backtrack(board, index + 1); - if (found) { - // 如果找到一个可行解,立即结束 - // 不要撤销选择,否则 board[i][j] 会被重置为 '.' - return; - } - - // 撤销选择 - board[row][col] = '.'; - } - } - - // 判断是否可以在 (r, c) 位置放置数字 num - boolean isValid(char[][] board, int row, int col, char num) { - for (int i = 0; i < 9; i++) { - // 判断行是否存在重复 - if (board[row][i] == num) return false; - // 判断列是否存在重复 - if (board[i][col] == num) return false; - // 判断 3 x 3 方框是否存在重复 - if (board[(row / 3) * 3 + i / 3][(col / 3) * 3 + i % 3] == num) { return false; } - } - return true; - } - - public int index(int x, int y) { - return x * n + y; - } - - public int[] point(int index) { - int x = index / n; - int y = index % n; - return new int[] { x, y }; - } - - } - - static class Solution2 { - - private int n; - - // 标记是否已经找到可行解 - private boolean found; - - // 记录每行已经出现的数字 - // 比如 rows[0] = {1, 2, 3} 表示第 0 行已经出现了数字 1, 2, 3 - private final List> rows; - - // 记录每列已经出现的数字 - private final List> cols; - - // 记录每个九宫格已经出现的数字 - private final List> boxes; - - public Solution2() { - found = false; - rows = new ArrayList<>(9); - cols = new ArrayList<>(9); - boxes = new ArrayList<>(9); - for (int i = 0; i < 9; i++) { - rows.add(new HashSet<>()); - cols.add(new HashSet<>()); - boxes.add(new HashSet<>()); - } - } - - public void solveSudoku(char[][] board) { - n = board.length; - // 将预设数字加入集合 - for (int i = 0; i < 9; i++) { - for (int j = 0; j < 9; j++) { - if (board[i][j] != '.') { - rows.get(i).add(board[i][j]); - cols.get(j).add(board[i][j]); - boxes.get(getBoxIndex(i, j)).add(board[i][j]); - } - } - } - backtrack(board, 0); - } - - // 路径:board 中小于 index 的位置所填的数字 - // 选择列表:数字 1~9 - // 结束条件:整个 board 都填满数字 - public void backtrack(char[][] board, int index) { - - // 已经找到一个可行解,立即结束 - if (found) { return; } - - // 找到一个可行解,触发 base case - if (index == n * n) { - found = true; - return; - } - - int row = index / n; - int col = index % n; - // 如果有预设数字,无需穷举 - if (board[row][col] != '.') { - backtrack(board, index + 1); - return; - } - - for (char ch = '1'; ch <= '9'; ch++) { - - // 【剪枝】如果遇到不合法的数字,就跳过 - if (!isValid(row, col, ch)) { continue; } - - // 【选择】把 ch 填入 board[i][j] - board[row][col] = ch; - rows.get(row).add(ch); - cols.get(col).add(ch); - boxes.get(getBoxIndex(row, col)).add(ch); - - backtrack(board, index + 1); - if (found) { - // 如果找到一个可行解,立即结束 - // 不要撤销选择,否则 board[i][j] 会被重置为 '.' - return; - } - - // 【取消选择】把 board[i][j] 重置为 '.' - board[row][col] = '.'; - rows.get(row).remove(ch); - cols.get(col).remove(ch); - boxes.get(getBoxIndex(row, col)).remove(ch); - } - } - - // 获取 (row, col) 所在的九宫格索引 - public int getBoxIndex(int row, int col) { - return (row / 3) * 3 + (col / 3); - } - - // 判断是否可以在 (row, col) 位置放置数字 num - public boolean isValid(int row, int col, char num) { - // 现在只需要查询三次哈希表即可 - if (rows.get(row).contains(num)) { return false; } - if (cols.get(col).contains(num)) { return false; } - if (boxes.get(getBoxIndex(row, col)).contains(num)) { return false; } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/template/\345\233\236\346\272\257\347\256\227\346\263\225\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/template/\345\233\236\346\272\257\347\256\227\346\263\225\346\250\241\346\235\277.java" deleted file mode 100644 index 24b5dd5..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/template/\345\233\236\346\272\257\347\256\227\346\263\225\346\250\241\346\235\277.java" +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.dunwu.algorithm.dfs.template; - -/** - * 回溯算法模板 - * - * @author Zhang Peng - * @date 2025-12-11 - */ -public class 回溯算法模板 { - - // 【回溯算法伪代码模板】 - // for 选择 in 选择列表: - // # 做选择 - // 将该选择从选择列表移除 - // 路径.add(选择) - // backtrack(路径, 选择列表) - // # 撤销选择 - // 路径.remove(选择) - // 将该选择再加入选择列表 -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\344\274\230\347\276\216\347\232\204\346\216\222\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\344\274\230\347\276\216\347\232\204\346\216\222\345\210\227.java" deleted file mode 100644 index cb4aff8..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\344\274\230\347\276\216\347\232\204\346\216\222\345\210\227.java" +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 526. 优美的排列 - * - * @author Zhang Peng - * @date 2025-12-12 - */ -public class 优美的排列 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(1, s.countArrangement(1)); - Assertions.assertEquals(2, s.countArrangement(2)); - } - - static class Solution { - - // 记录所有的「优美排列」的个数 - private int res = 0; - // track 中的元素会被标记为 true,避免重复选择 - private boolean[] visited; - // 记录回溯算法的递归路径,即每个索引选择的元素 - private LinkedList path; - - public int countArrangement(int n) { - res = 0; - visited = new boolean[n + 1]; - path = new LinkedList<>(); - dfs(n, 1); - return res; - } - - // 回溯算法标准框架,站在索引的视角选择元素 - void dfs(int n, int index) { - // base case,到达叶子节点 - if (index > n) { - // 找到一个结果 - res += 1; - return; - } - - // 索引 index 开始选择元素 - for (int val = 1; val <= n; val++) { - // 已经被其他索引选过的元素,不能重复选择 - if (visited[val]) { - continue; - } - if (!(index % val == 0 || val % index == 0)) { - continue; - } - // 【选择】index 选择元素 elem - visited[val] = true; - path.addLast(val); - // 【回溯】 - dfs(n, index + 1); - // 【取消选择】 - path.removeLast(); - visited[val] = false; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262.java" deleted file mode 100644 index 7c63a40..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262.java" +++ /dev/null @@ -1,72 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 131. 分割回文串 - * - * @author Zhang Peng - * @date 2025-12-12 - */ -public class 分割回文串 { - - public static void main(String[] args) { - Solution s = new Solution(); - - String[][] expect = new String[][] { { "a", "a", "b" }, { "aa", "b" } }; - List> output = s.partition("aab"); - Assertions.assertEquals(expect.length, output.size()); - - List> output2 = s.partition("a"); - Assertions.assertEquals(1, output2.size()); - } - - static class Solution { - - private List path; - private List> res; - - public List> partition(String s) { - path = new LinkedList<>(); - res = new LinkedList<>(); - dfs(s, 0); - return res; - } - - public void dfs(String s, int start) { - if (start == s.length()) { - // base case,走到叶子节点 - // 即整个 s 被成功分割为若干个回文子串,记下答案 - res.add(new LinkedList(path)); - } - for (int i = start; i < s.length(); i++) { - if (!isPalindrome(s, start, i)) { - // s[start..i] 不是回文串,不能分割 - continue; - } - // s[start..i] 是一个回文串,可以进行分割 - // 做选择,把 s[start..i] 放入路径列表中 - path.add(s.substring(start, i + 1)); - // 进入回溯树的下一层,继续切分 s[i+1..] - dfs(s, i + 1); - // 撤销选择 - path.remove(path.size() - 1); - } - } - - // 用双指针技巧判断 s[low..high] 是否是一个回文串 - public boolean isPalindrome(String s, int low, int high) { - while (low < high) { - if (s.charAt(low) != s.charAt(high)) { return false; } - low++; - high--; - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\215\225\350\257\215\346\220\234\347\264\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\215\225\350\257\215\346\220\234\347\264\242.java" deleted file mode 100644 index ef11cfe..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\215\225\350\257\215\346\220\234\347\264\242.java" +++ /dev/null @@ -1,70 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -/** - * 79. 单词搜索 - * - * @author Zhang Peng - * @date 2025-12-12 - */ -public class 单词搜索 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue( - s.exist(new char[][] { { 'A', 'B', 'C', 'E' }, { 'S', 'F', 'C', 'S' }, { 'A', 'D', 'E', 'E' } }, "ABCCED")); - Assertions.assertTrue( - s.exist(new char[][] { { 'A', 'B', 'C', 'E' }, { 'S', 'F', 'C', 'S' }, { 'A', 'D', 'E', 'E' } }, "SEE")); - Assertions.assertFalse( - s.exist(new char[][] { { 'A', 'B', 'C', 'E' }, { 'S', 'F', 'C', 'S' }, { 'A', 'D', 'E', 'E' } }, "ABCB")); - } - - static class Solution { - - boolean found = false; - - public boolean exist(char[][] board, String word) { - found = false; - int m = board.length, n = board[0].length; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - dfs(board, i, j, word, 0); - if (found) { return true; } - } - } - return false; - } - - // 从 (i, j) 开始向四周搜索,试图匹配 word[p..] - void dfs(char[][] board, int i, int j, String word, int p) { - if (p == word.length()) { - // 整个 word 已经被匹配完,找到了一个答案 - found = true; - return; - } - if (found) { - // 已经找到了一个答案,不用再搜索了 - return; - } - int m = board.length, n = board[0].length; - if (i < 0 || j < 0 || i >= m || j >= n) { - return; - } - if (board[i][j] != word.charAt(p)) { - return; - } - - // 已经匹配过的字符,我们给它添一个负号作为标记,避免走回头路 - board[i][j] = (char) (-board[i][j]); - // word[p] 被 board[i][j] 匹配,开始向四周搜索 word[p+1..] - dfs(board, i + 1, j, word, p + 1); - dfs(board, i, j + 1, word, p + 1); - dfs(board, i - 1, j, word, p + 1); - dfs(board, i, j - 1, word, p + 1); - board[i][j] = (char) (-board[i][j]); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" deleted file mode 100644 index 9799f09..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -/** - * https://leetcode-cn.com/problems/reverse-string/ - * - * @author Zhang Peng - * @since 2020-07-08 - */ -public class 反转字符串 { - - public static void main(String[] args) { - char[] str = { 'h', 'e', 'l', 'l', 'o' }; - reverseString(str); - Assertions.assertArrayEquals(new char[] { 'o', 'l', 'l', 'e', 'h' }, str); - - char[] str2 = { 'H', 'a', 'n', 'n', 'a', 'h' }; - reverseString(str2); - Assertions.assertArrayEquals(new char[] { 'h', 'a', 'n', 'n', 'a', 'H' }, str2); - } - - public static void reverseString(char[] s) { - if (s == null || s.length == 0) return; - int l = 0, r = s.length - 1; - recursive(s, l, r); - } - - private static void recursive(char[] s, int l, int r) { - if (l >= r) return; - char temp = s[l]; - s[l] = s[r]; - s[r] = temp; - recursive(s, l + 1, r - 1); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\244\215\345\216\237IP\345\234\260\345\235\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\244\215\345\216\237IP\345\234\260\345\235\200.java" deleted file mode 100644 index ce16a6a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\345\244\215\345\216\237IP\345\234\260\345\235\200.java" +++ /dev/null @@ -1,88 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 93. 复原 IP 地址 - * - * @author Zhang Peng - * @date 2025-12-12 - */ -public class 复原IP地址 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new String[] { "255.255.11.135", "255.255.111.35" }, - s.restoreIpAddresses("25525511135").toArray()); - Assertions.assertArrayEquals(new String[] { "0.0.0.0" }, s.restoreIpAddresses("0000").toArray()); - Assertions.assertArrayEquals(new String[] { "1.0.10.23", "1.0.102.3", "10.1.0.23", "10.10.2.3", "101.0.2.3" }, - s.restoreIpAddresses("101023").toArray()); - } - - static class Solution { - - private LinkedList path; - private LinkedList res; - - public List restoreIpAddresses(String s) { - path = new LinkedList<>(); - res = new LinkedList<>(); - dfs(s, 0); - return res; - } - - public void dfs(String s, int start) { - - // base case,走到叶子节点 - // 即整个 s 被成功分割为合法的四部分,记下答案 - if (start == s.length() && path.size() == 4) { - String ip = String.join(".", path); - res.add(ip); - } - - for (int i = start; i < s.length(); i++) { - - // s[start..i] 不是合法的 ip 数字,不能分割 - if (!isValid(s, start, i)) { continue; } - - // 已经分解成 4 部分了,不能再分解了 - if (path.size() >= 4) { continue; } - - // 【选择】 - // s[start..i] 是一个合法的 ip 数字,可以进行分割 - // 做选择,把 s[start..i] 放入路径列表中 - path.add(s.substring(start, i + 1)); - - // 【回溯】 - dfs(s, i + 1); - - // 【取消选择】 - path.removeLast(); - } - } - - public boolean isValid(String s, int start, int end) { - - int length = end - start + 1; - - if (length == 0 || length > 3) { return false; } - - // 如果只有一位数字,肯定是合法的 - if (length == 1) { return true; } - - // 多于一位数字,但开头是 0,肯定不合法 - if (s.charAt(start) == '0') { return false; } - - // 排除了开头是 0 的情况,那么如果是两位数,肯定是合法的 - if (length <= 2) { return true; } - - // 现在输入的一定是三位数,不能大于 255 - return Integer.parseInt(s.substring(start, start + length)) <= 255; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\346\240\274\351\233\267\347\274\226\347\240\201.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\346\240\274\351\233\267\347\274\226\347\240\201.java" deleted file mode 100644 index 92162c4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\346\240\274\351\233\267\347\274\226\347\240\201.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 526. 优美的排列 - * - * @author Zhang Peng - * @date 2025-12-12 - */ -public class 格雷编码 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 0, 1 }, ArrayUtil.toIntArray(s.grayCode(1))); - Assertions.assertArrayEquals(new int[] { 0, 1, 3, 2 }, ArrayUtil.toIntArray(s.grayCode(2))); - } - - static class Solution { - - private boolean[] visited; - private LinkedList path; - private LinkedList res; - - public List grayCode(int n) { - visited = new boolean[n]; - path = new LinkedList<>(); - res = null; - dfs(n, 0); - return res; - } - - public void dfs(int n, int root) { - if (res != null) return; - if (path.size() == (1 << n)) { - res = new LinkedList<>(path); - return; - } - if (visited[root]) return; - - visited[root] = true; - path.addLast(root); - - for (int i = 0; i < n; i++) { - int next = flipBit(root, i); - dfs(n, next); - } - - path.removeLast(); - visited[root] = false; - } - - // 把第 i 位取反(0 变 1,1 变 0) - int flipBit(int x, int i) { - return x ^ (1 << i); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" deleted file mode 100644 index def2aea..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 17. 电话号码的字母组合 - * - * @author Zhang Peng - * @date 2025-11-05 - */ -public class 电话号码的字母组合 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new String[] { "ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf" }, - s.letterCombinations("23").toArray()); - Assertions.assertArrayEquals(new String[] { "a", "b", "c" }, s.letterCombinations("2").toArray()); - Assertions.assertArrayEquals(new String[] { "t", "u", "v" }, s.letterCombinations("8").toArray()); - } - - static class Solution { - - private StringBuilder sb; - private LinkedList res; - private final String[] options = new String[] { - "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" - }; - - public List letterCombinations(String digits) { - if (digits.isEmpty()) { return new LinkedList<>(); } - sb = new StringBuilder(); - res = new LinkedList<>(); - // 从 digits[0] 开始进行回溯 - dfs(digits, 0); - return res; - } - - // 回溯算法主函数 - public void dfs(String digits, int start) { - // 到达回溯树底部 - if (sb.length() == digits.length()) { - res.add(sb.toString()); - return; - } - - // 回溯算法框架 - int digit = digits.charAt(start) - '0'; - for (char c : options[digit].toCharArray()) { - sb.append(c); - dfs(digits, start + 1); - sb.deleteCharAt(sb.length() - 1); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" deleted file mode 100644 index d9a0551..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\350\277\236\347\273\255\345\267\256\347\233\270\345\220\214\347\232\204\346\225\260\345\255\227.java" +++ /dev/null @@ -1,78 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 967. 连续差相同的数字 - * - * @author Zhang Peng - * @date 2025-11-05 - */ -public class 连续差相同的数字 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 181, 292, 707, 818, 929 }, s.numsSameConsecDiff(3, 7)); - Assertions.assertArrayEquals(new int[] { 10, 12, 21, 23, 32, 34, 43, 45, 54, 56, 65, 67, 76, 78, 87, 89, 98 }, - s.numsSameConsecDiff(2, 1)); - Assertions.assertArrayEquals(new int[] { 11, 22, 33, 44, 55, 66, 77, 88, 99 }, s.numsSameConsecDiff(2, 0)); - Assertions.assertArrayEquals(new int[] { 13, 20, 24, 31, 35, 42, 46, 53, 57, 64, 68, 75, 79, 86, 97 }, - s.numsSameConsecDiff(2, 2)); - } - - static class Solution { - - // 记录当前路径组成的数字的值 - private int num = 0; - // 记录当前数字的位数 - private int digit = 0; - private List res; - - public int[] numsSameConsecDiff(int n, int k) { - - num = 0; - digit = 0; - res = new LinkedList<>(); - - dfs(n, k); - - int[] arr = new int[res.size()]; - for (int i = 0; i < res.size(); i++) { - arr[i] = res.get(i); - } - return arr; - } - - // 回溯算法核心函数 - void dfs(int n, int k) { - // base case,到达叶子节点 - if (digit == n) { - // 找到一个合法的 n 位数 - res.add(num); - return; - } - - // 回溯算法标准框架 - for (int i = 0; i <= 9; i++) { - // 本题的剪枝逻辑 1,第一个数字不能是 0 - if (digit == 0 && i == 0) continue; - // 本题的剪枝逻辑 2,相邻两个数字的差的绝对值必须等于 k - if (digit > 0 && Math.abs(i - num % 10) != k) continue; - - // 做选择,在 track 尾部追加数字 i - digit++; - num = 10 * num + i; - // 进入下一层回溯树 - dfs(n, k); - // 取消选择,删除 track 尾部数字 - num = num / 10; - digit--; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\351\235\236\351\200\222\345\207\217\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\351\235\236\351\200\222\345\207\217\345\255\220\345\272\217\345\210\227.java" deleted file mode 100644 index 0c5494d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dfs/\351\235\236\351\200\222\345\207\217\345\255\220\345\272\217\345\210\227.java" +++ /dev/null @@ -1,76 +0,0 @@ -package io.github.dunwu.algorithm.dfs; - -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - -/** - * 491. 非递减子序列 - * - * @author Zhang Peng - * @date 2025-12-12 - */ -public class 非递减子序列 { - - public static void main(String[] args) { - Solution s = new Solution(); - - int[][] expect = new int[][] { - { 4, 6 }, { 4, 6, 7 }, { 4, 6, 7, 7 }, { 4, 7 }, { 4, 7, 7 }, { 6, 7 }, { 6, 7, 7 }, { 7, 7 } - }; - List> output = s.findSubsequences(new int[] { 4, 6, 7, 7 }); - Assertions.assertArrayEquals(expect, ArrayUtil.toIntMatrixArray(output)); - - List> output2 = s.findSubsequences(new int[] { 4, 4, 3, 2, 1 }); - Assertions.assertArrayEquals(new int[][] { { 4, 4 } }, ArrayUtil.toIntMatrixArray(output2)); - } - - static class Solution { - - private List path; - private List> res; - - public List> findSubsequences(int[] nums) { - - // base case - if (nums == null || nums.length == 0) { return new LinkedList<>(); } - - path = new LinkedList<>(); - res = new LinkedList<>(); - - dfs(nums, 0); - return res; - } - - public void dfs(int[] nums, int start) { - if (path.size() >= 2) { - res.add(new LinkedList<>(path)); - } - - // 用哈希集合防止重复选择相同元素 - HashSet visited = new HashSet<>(); - - for (int i = start; i < nums.length; i++) { - - if (!path.isEmpty() && nums[i] < path.get(path.size() - 1)) { continue; } - // 保证不要重复使用相同的元素 - if (visited.contains(nums[i])) { continue; } - - // 【选择】 - visited.add(nums[i]); - path.add(nums[i]); - - // 【递归】 - dfs(nums, i + 1); - - // 【取消选择】 - path.remove(path.size() - 1); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/N\346\254\241\345\271\202.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/N\346\254\241\345\271\202.java" deleted file mode 100644 index 80a3464..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/N\346\254\241\345\271\202.java" +++ /dev/null @@ -1,75 +0,0 @@ -package io.github.dunwu.algorithm.divide; - -import org.junit.jupiter.api.Assertions; - -/** - * 50. Pow(x, n) 求 N次幂 - * - * @author Zhang Peng - * @see 50. Pow(x, n) - * @since 2020-07-02 - */ -public class N次幂 { - - public static void main(String[] args) { - Assertions.assertEquals(1024.00000, myPow(2.00000, 10)); - Assertions.assertEquals(9.261000000000001, myPow(2.10000, 3)); - Assertions.assertEquals(0.25000, myPow(2.00000, -2)); - - Assertions.assertEquals(1024.00000, myPow2(2.00000, 10)); - Assertions.assertEquals(9.261000000000001, myPow2(2.10000, 3)); - Assertions.assertEquals(0.25000, myPow2(2.00000, -2)); - } - - /** - * 分治算法 - *

- * x^n 可以视为 y^2(n为偶数) 或 x*y^2(n为奇数) - *

- * 时间复杂度:O(log N) - */ - public static double myPow(double x, int n) { - if (n > 0) return helper(x, n); - return 1.00000 / helper(x, -n); - } - - public static double helper(double x, int n) { - if (n == 0) { - return 1.00000; - } - - double y = helper(x, n / 2); - if (n % 2 == 0) { - return y * y; - } else { - return x * y * y; - } - } - - /** - * 暴力破解法 - *

- * 时间复杂度:O(N) - */ - public static double myPow2(double x, int n) { - double result = 1.00000; - - if (n == 0) { - return 1.00000; - } - - int cnt = n > 0 ? n : -n; - for (int i = 0; i < cnt; i++) { - result *= x; - } - - if (n < 0) result = 1.00000 / result; - return result; - } - - // 库函数 - public static double myPow3(double x, int n) { - return Math.pow(x, n); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/package-info.java deleted file mode 100644 index f051be8..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 分治算法 - * - * @author Zhang Peng - * @since 2020-07-02 - */ -package io.github.dunwu.algorithm.divide; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/\345\244\232\346\225\260\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/\345\244\232\346\225\260\345\205\203\347\264\240.java" deleted file mode 100644 index a93d092..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/divide/\345\244\232\346\225\260\345\205\203\347\264\240.java" +++ /dev/null @@ -1,48 +0,0 @@ -package io.github.dunwu.algorithm.divide; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 多数元素 - * - * @author Zhang Peng - * @see 多数元素 - * @since 2020-07-02 - */ -public class 多数元素 { - - public static void main(String[] args) { - Assertions.assertEquals(3, majorityElement(new int[] { 3, 2, 3 })); - Assertions.assertEquals(2, majorityElement(new int[] { 2, 2, 1, 1, 1, 2, 2 })); - Assertions.assertEquals(6, majorityElement(new int[] { 6, 6, 6, 7, 7 })); - } - - // 暴力破解法 - // 时间复杂度:O(N) + O(log N) - public static int majorityElement(int[] nums) { - Arrays.sort(nums); - int max = 1; - int count = 0; - int currElem = nums[0]; - int maxElem = nums[0]; - for (int i = 0; i < nums.length; i++) { - if (nums[i] != currElem) { - count = 1; - currElem = nums[i]; - } else { - count++; - if (maxElem == currElem) { - max = count; - } else { - if (max < count) { - maxElem = currElem; - } - } - } - } - return maxElem; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" deleted file mode 100644 index dcb4260..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2602.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.dp.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 264. 丑数II - * - * @author Zhang Peng - * @date 2025-01-24 - */ -public class 丑数2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(12, s.nthUglyNumber(10)); - Assertions.assertEquals(1, s.nthUglyNumber(1)); - Assertions.assertEquals(15, s.nthUglyNumber(11)); - } - - static class Solution { - - public int nthUglyNumber(int n) { - int[] dp = new int[n + 1]; - dp[1] = 1; - int p2 = 1, p3 = 1, p5 = 1; - for (int index = 2; index <= n; index++) { - int n2 = dp[p2] * 2, n3 = dp[p3] * 3, n5 = dp[p5] * 5; - dp[index] = min(n2, n3, n5); - if (dp[index] == n2) { p2++; } - if (dp[index] == n3) { p3++; } - if (dp[index] == n5) { p5++; } - } - return dp[n]; - } - - public int min(int a, int b, int c) { - return Math.min(a, Math.min(b, c)); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" deleted file mode 100644 index 1ca3fb6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\344\270\221\346\225\2603.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.dp.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 1201. 丑数 III - * - * @author Zhang Peng - * @date 2025-01-24 - */ -public class 丑数3 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.nthUglyNumber(3, 2, 3, 5)); - Assertions.assertEquals(6, s.nthUglyNumber(4, 2, 3, 4)); - Assertions.assertEquals(10, s.nthUglyNumber(5, 2, 11, 13)); - } - - static class Solution { - - public int nthUglyNumber(int n, int a, int b, int c) { - int[] dp = new int[n + 1]; - int pa = 1, pb = 1, pc = 1; - dp[0] = 1; - for (int i = 1; i <= n; i++) { - int na = pa * a, nb = pb * b, nc = pc * c; - dp[i] = min(na, nb, nc); - if (dp[i] == na) { pa++; } - if (dp[i] == nb) { pb++; } - if (dp[i] == nc) { pc++; } - } - return dp[n]; - } - - int min(int a, int b, int c) { - return Math.min(a, Math.min(b, c)); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\346\234\200\344\275\216\347\245\250\344\273\267.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\346\234\200\344\275\216\347\245\250\344\273\267.java" deleted file mode 100644 index 80c922b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\346\234\200\344\275\216\347\245\250\344\273\267.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.dp.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 983. 最低票价 - * - * @author Zhang Peng - * @since 2025-11-17 - */ -public class 最低票价 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(11, s.mincostTickets(new int[] { 1, 4, 6, 7, 8, 20 }, new int[] { 2, 7, 15 })); - Assertions.assertEquals(17, - s.mincostTickets(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 30, 31 }, new int[] { 2, 7, 15 })); - } - - // 动态规划 - static class Solution { - - public int mincostTickets(int[] days, int[] costs) { - int n = days.length; - int lastDay = days[n - 1]; - boolean[] isTravel = new boolean[lastDay + 1]; - for (int d : days) { isTravel[d] = true; } - - // dp[i] 表示 1 到 i 天的最小花费 - int[] dp = new int[lastDay + 1]; - dp[0] = 0; - for (int i = 1; i <= lastDay; i++) { - if (!isTravel[i]) { - // 如果第 i 天不在 days 中,则第 i 天和第 i - 1 天花费相同 - dp[i] = dp[i - 1]; - } else { - // 如果第 i 天在 days 中 - // 则求三种不同方案最小值: - dp[i] = min( - // 在第 i 天购买为期 1 天的通行证的最小花费 - costs[0] + dp[i - 1], - // 在第 i - 7 天购买为期 7 天的通行证的最小花费(如果 i - 7 < 0,视为 0,f[0] 花费为 0) - costs[1] + dp[Math.max(0, i - 7)], - // 在第 i - 30 天购买为期 30 天的通行证的最小花费(如果 i - 30 < 0,视为 0,f[0] 花费为 0) - costs[2] + dp[Math.max(0, i - 30)] - ); - } - } - return dp[lastDay]; - } - - public int min(int a, int b, int c) { - return Math.min(a, Math.min(b, c)); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" deleted file mode 100644 index 107feec..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\347\273\237\350\256\241\346\236\204\351\200\240\345\245\275\345\255\227\347\254\246\344\270\262\347\232\204\346\226\271\346\241\210\346\225\260.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.dp.array; - -import org.junit.jupiter.api.Assertions; - -/** - * 2466. 统计构造好字符串的方案数 - * - * @author Zhang Peng - * @since 2025-11-17 - */ -public class 统计构造好字符串的方案数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(8, s.countGoodStrings(3, 3, 1, 1)); - Assertions.assertEquals(5, s.countGoodStrings(2, 3, 1, 2)); - } - - static class Solution { - - public int countGoodStrings(int low, int high, int zero, int one) { - final int MOD = 1_000_000_007; - int res = 0; - // dp[i] 表示构造长为 i 的字符串的方案数 - int[] dp = new int[high + 1]; - // 构造空串的方案数为 1 - dp[0] = 1; - for (int i = 1; i <= high; i++) { - if (i >= zero) dp[i] = dp[i - zero]; - if (i >= one) dp[i] = (dp[i] + dp[i - one]) % MOD; - if (i >= low) res = (res + dp[i]) % MOD; - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\345\206\263\346\231\272\345\212\233\351\227\256\351\242\230.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\345\206\263\346\231\272\345\212\233\351\227\256\351\242\230.java" deleted file mode 100644 index 5126e91..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\345\206\263\346\231\272\345\212\233\351\227\256\351\242\230.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.dp.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 2140. 解决智力问题 - * - * @author Zhang Peng - * @date 2025-11-17 - */ -public class 解决智力问题 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(5, s.mostPoints(new int[][] { { 3, 2 }, { 4, 3 }, { 4, 4 }, { 2, 5 } })); - Assertions.assertEquals(7, s.mostPoints(new int[][] { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 } })); - } - - static class Solution { - - long[] memo; - - public long mostPoints(int[][] questions) { - if (questions == null || questions.length == 0) { return 0; } - memo = new long[questions.length + 1]; - Arrays.fill(memo, -1); - return dp(questions, 0); - } - - public long dp(int[][] questions, int i) { - if (i < 0 || i >= questions.length) { return 0L; } - if (memo[i] != -1) { return memo[i]; } - int score = questions[i][0]; - int skip = questions[i][1]; - memo[i] = Math.max( - dp(questions, i + 1), - dp(questions, i + skip + 1) + score - ); - return memo[i]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\347\240\201\346\226\271\346\263\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\347\240\201\346\226\271\346\263\225.java" deleted file mode 100644 index d813925..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\350\247\243\347\240\201\346\226\271\346\263\225.java" +++ /dev/null @@ -1,103 +0,0 @@ -package io.github.dunwu.algorithm.dp.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 91. 解码方法 - * - * @author Zhang Peng - * @since 2025-11-17 - */ -public class 解码方法 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.numDecodings("12")); - Assertions.assertEquals(3, s.numDecodings("226")); - Assertions.assertEquals(0, s.numDecodings("06")); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(2, s2.numDecodings("12")); - Assertions.assertEquals(3, s2.numDecodings("226")); - Assertions.assertEquals(0, s2.numDecodings("06")); - } - - // 回溯解法 - static class Solution { - - private StringBuilder sb; - private LinkedList res; - - public int numDecodings(String s) { - sb = new StringBuilder(); - res = new LinkedList<>(); - backtrack(s, 0); - return res.size(); - } - - public void backtrack(String s, int start) { - - // base case,走到叶子节点 - // 即整个 s 被成功分割为合法的四部分,记下答案 - if (start == s.length()) { - res.add(sb.toString()); - return; - } - - for (int i = start; i < s.length(); i++) { - - // s[start..i] 不是合法的 ip 数字,不能分割 - char letter = getLetter(s, start, i); - if (letter == '#') { continue; } - - // 【选择】 - // s[start..i] 是一个合法的 ip 数字,可以进行分割 - // 做选择,把 s[start..i] 放入路径列表中 - sb.append(letter); - - // 【回溯】 - backtrack(s, i + 1); - - // 【取消选择】 - sb.deleteCharAt(sb.length() - 1); - } - } - - public char getLetter(String s, int begin, int end) { - int len = end - begin + 1; - if (len <= 0 || len > 2) { return '#'; } - String numStr = s.substring(begin, begin + len); - if (numStr.startsWith("0")) { return '#'; } - int num = Integer.parseInt(numStr); - if (num < 1 || num > 26) { return '#'; } - return (char) ('A' + (num - 1)); - } - - } - - // 动态规划 - static class Solution2 { - - public int numDecodings(String s) { - int n = s.length(); - s = " " + s; - char[] ch = s.toCharArray(); - int[] dp = new int[n + 1]; - dp[0] = 1; - for (int i = 1; i <= n; i++) { - // a : 代表「当前位置」单独形成 item - // b : 代表「当前位置」与「前一位置」共同形成 item - int a = ch[i] - '0', b = (ch[i - 1] - '0') * 10 + (ch[i] - '0'); - // 如果 a 属于有效值,那么 dp[i] 可以由 dp[i - 1] 转移过来 - if (1 <= a && a <= 9) dp[i] = dp[i - 1]; - // 如果 b 属于有效值,那么 dp[i] 可以由 dp[i - 2] 或者 dp[i - 1] & dp[i - 2] 转移过来 - if (10 <= b && b <= 26) dp[i] += dp[i - 2]; - } - return dp[n]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" deleted file mode 100644 index feeb72a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/array/\351\233\266\351\222\261\345\205\221\346\215\242.java" +++ /dev/null @@ -1,87 +0,0 @@ -package io.github.dunwu.algorithm.dp.array; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 322. 零钱兑换 - * - * @author Zhang Peng - * @since 2025-11-17 - */ -public class 零钱兑换 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.coinChange(new int[] { 1, 2, 5 }, 11)); - Assertions.assertEquals(-1, s.coinChange(new int[] { 2 }, 3)); - Assertions.assertEquals(0, s.coinChange(new int[] { 1 }, 0)); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(3, s2.coinChange(new int[] { 1, 2, 5 }, 11)); - Assertions.assertEquals(-1, s2.coinChange(new int[] { 2 }, 3)); - Assertions.assertEquals(0, s2.coinChange(new int[] { 1 }, 0)); - } - - static class Solution { - - int[] memo; - - public int coinChange(int[] coins, int amount) { - memo = new int[amount + 1]; - // 备忘录初始化为一个不会被取到的特殊值,代表还未被计算 - Arrays.fill(memo, -666); - - return dp(coins, amount); - } - - int dp(int[] coins, int amount) { - if (amount == 0) return 0; - if (amount < 0) return -1; - // 查备忘录,防止重复计算 - if (memo[amount] != -666) { return memo[amount]; } - - int res = Integer.MAX_VALUE; - for (int coin : coins) { - // 计算子问题的结果 - int subProblem = dp(coins, amount - coin); - - // 子问题无解则跳过 - if (subProblem == -1) continue; - // 在子问题中选择最优解,然后加一 - res = Math.min(res, subProblem + 1); - } - // 把计算结果存入备忘录 - memo[amount] = (res == Integer.MAX_VALUE) ? -1 : res; - return memo[amount]; - } - - } - - static class Solution2 { - - public int coinChange(int[] coins, int amount) { - int[] dp = new int[amount + 1]; - // 数组大小为 amount + 1,初始值也为 amount + 1 - Arrays.fill(dp, amount + 1); - - // base case - dp[0] = 0; - // 外层 for 循环在遍历所有状态的所有取值 - for (int i = 0; i < dp.length; i++) { - // 内层 for 循环在求所有选择的最小值 - for (int coin : coins) { - // 子问题无解,跳过 - if (i - coin < 0) { - continue; - } - dp[i] = Math.min(dp[i], 1 + dp[i - coin]); - } - } - return (dp[amount] == amount + 1) ? -1 : dp[amount]; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/package-info.java deleted file mode 100644 index 1e7cb09..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 动态规划 - 斐波那契类型 - * - * @author Zhang Peng - * @date 2025-11-12 - */ -package io.github.dunwu.algorithm.dp.fib; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" deleted file mode 100644 index e0d3ca1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\344\275\277\347\224\250\346\234\200\345\260\217\350\212\261\350\264\271\347\210\254\346\245\274\346\242\257.java" +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.dunwu.algorithm.dp.fib; - -import org.junit.jupiter.api.Assertions; - -/** - * 746. 使用最小花费爬楼梯 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 使用最小花费爬楼梯 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(15, s.minCostClimbingStairs(new int[] { 10, 15, 20 })); - Assertions.assertEquals(6, s.minCostClimbingStairs(new int[] { 1, 100, 1, 1, 1, 100, 1, 1, 100, 1 })); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(15, s2.minCostClimbingStairs(new int[] { 10, 15, 20 })); - Assertions.assertEquals(6, s2.minCostClimbingStairs(new int[] { 1, 100, 1, 1, 1, 100, 1, 1, 100, 1 })); - } - - static class Solution { - - public int minCostClimbingStairs(int[] cost) { - if (cost == null || cost.length == 0) { return 0; } - int N = cost.length; - int[] dp = new int[N + 1]; - dp[0] = dp[1] = 0; - for (int i = 2; i <= N; i++) { - dp[i] = Math.min( - dp[i - 1] + cost[i - 1], - dp[i - 2] + cost[i - 2] - ); - } - return dp[N]; - } - - } - - static class Solution2 { - - public int minCostClimbingStairs(int[] cost) { - if (cost == null || cost.length == 0) { return 0; } - int pre1 = 0, pre2 = 0; - for (int i = 2; i <= cost.length; i++) { - int tmp = Math.min( - pre1 + cost[i - 1], - pre2 + cost[i - 2] - ); - pre2 = pre1; - pre1 = tmp; - } - return pre1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" deleted file mode 100644 index 2442b5b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\345\210\240\351\231\244\345\271\266\350\216\267\345\276\227\347\202\271\346\225\260.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.dp.fib; - -import org.junit.jupiter.api.Assertions; - -/** - * 740. 删除并获得点数 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 删除并获得点数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(6, s.deleteAndEarn(new int[] { 3, 4, 2 })); - // 删除 4 获得 4 个点数,因此 3 也被删除。 - // 之后,删除 2 获得 2 个点数。总共获得 6 个点数。 - Assertions.assertEquals(9, s.deleteAndEarn(new int[] { 2, 2, 3, 3, 3, 4 })); - // 删除 3 获得 3 个点数,接着要删除两个 2 和 4 。 - // 之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。 - // 总共获得 9 个点数。 - } - - static class Solution { - - public int deleteAndEarn(int[] nums) { - - if (nums == null || nums.length == 0) { return 0; } - - int n = nums.length; - int max = Integer.MIN_VALUE; - for (int i = 1; i < n; i++) { - max = Math.max(max, nums[i]); - } - - int[] sums = new int[max + 1]; - for (int num : nums) { - sums[num] += num; - } - return rob(sums); - } - - public int rob(int[] nums) { - if (nums == null || nums.length == 0) { return 0; } - if (nums.length == 1) { return nums[0]; } - int N = nums.length; - int first = nums[0], second = Math.max(nums[0], nums[1]); - for (int i = 2; i < N; i++) { - int tmp = Math.max(second, first + nums[i]); - first = second; - second = tmp; - } - return second; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" deleted file mode 100644 index 9acda1e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\211\223\345\256\266\345\212\253\350\210\215.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.dp.fib; - -import org.junit.jupiter.api.Assertions; - -/** - * 198. 打家劫舍 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 打家劫舍 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.rob(new int[] { 1, 2, 3, 1 })); - Assertions.assertEquals(12, s.rob(new int[] { 2, 7, 9, 3, 1 })); - Assertions.assertEquals(1, s.rob(new int[] { 1, 1 })); - } - - static class Solution { - - public int rob(int[] nums) { - if (nums == null || nums.length == 0) { return 0; } - if (nums.length == 1) { return nums[0]; } - int N = nums.length; - int first = nums[0], second = Math.max(nums[0], nums[1]); - for (int i = 2; i < N; i++) { - int tmp = Math.max(second, first + nums[i]); - first = second; - second = tmp; - } - return second; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260.java" deleted file mode 100644 index a2bc7f4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260.java" +++ /dev/null @@ -1,110 +0,0 @@ -package io.github.dunwu.algorithm.dp.fib; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 509. 斐波那契数 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 斐波那契数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(1, s.fib(2)); - Assertions.assertEquals(2, s.fib(3)); - Assertions.assertEquals(3, s.fib(4)); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(1, s2.fib(2)); - Assertions.assertEquals(2, s2.fib(3)); - Assertions.assertEquals(3, s2.fib(4)); - - Solution2 s3 = new Solution2(); - Assertions.assertEquals(1, s3.fib(2)); - Assertions.assertEquals(2, s3.fib(3)); - Assertions.assertEquals(3, s3.fib(4)); - } - - /** - * 使用备忘录优化动态规划问题 - */ - static class Solution { - - int fib(int n) { - // 备忘录全初始化为 -1 - // 因为斐波那契数肯定是非负整数,所以初始化为特殊值 -1 表示未计算 - - // 因为数组的索引从 0 开始,所以需要 n + 1 个空间 - // 这样才能把 `f(0) ~ f(n)` 都记录到 memo 中 - int[] memo = new int[n + 1]; - Arrays.fill(memo, -1); - - return dp(memo, n); - } - - // 带着备忘录进行递归 - int dp(int[] memo, int n) { - // base case - if (n == 0 || n == 1) { - return n; - } - // 已经计算过,不用再计算了 - if (memo[n] != -1) { - return memo[n]; - } - // 在返回结果之前,存入备忘录 - memo[n] = dp(memo, n - 1) + dp(memo, n - 2); - return memo[n]; - } - - } - - /** - * DP Table 解决动态规划问题 - */ - static class Solution2 { - - int fib(int n) { - if (n == 0 || n == 1) { - return n; - } - - int[] dp = new int[n + 1]; - dp[0] = 0; - dp[1] = 1; - for (int i = 2; i <= n; i++) { - dp[i] = dp[i - 1] + dp[i - 2]; - } - return dp[n]; - } - - } - - /** - * 在 DP Table 基础上优化空间复杂度 - */ - static class Solution3 { - - int fib(int n) { - if (n == 0 || n == 1) { - return n; - } - - // 分别代表 dp[i - 1] 和 dp[i - 2] - int dp_i_1 = 1, dp_i_2 = 0; - for (int i = 2; i <= n; i++) { - // dp[i] = dp[i - 1] + dp[i - 2]; - int dp_i = dp_i_1 + dp_i_2; - dp_i_2 = dp_i_1; - dp_i_1 = dp_i; - } - return dp_i_1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" deleted file mode 100644 index 2b7f0bf..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\210\254\346\245\274\346\242\257.java" +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.dunwu.algorithm.dp.fib; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 70. 爬楼梯 - * - * @author Zhang Peng - * @since 2020-07-04 - */ -public class 爬楼梯 { - - public static void main(String[] args) { - - Solution s = new Solution(); - Assertions.assertEquals(1, s.climbStairs(0)); - Assertions.assertEquals(1, s.climbStairs(1)); - Assertions.assertEquals(2, s.climbStairs(2)); - Assertions.assertEquals(3, s.climbStairs(3)); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(1, s2.climbStairs(0)); - Assertions.assertEquals(1, s2.climbStairs(1)); - Assertions.assertEquals(2, s2.climbStairs(2)); - Assertions.assertEquals(3, s2.climbStairs(3)); - } - - static class Solution { - - int[] memo = null; - - public int climbStairs(int n) { - memo = new int[n + 1]; - Arrays.fill(memo, -1); - return dp(n); - } - - // 爬第n阶楼梯的方法数量,等于 2 部分之和 - // - // 爬上 n−1 阶楼梯的方法数量。因为再爬1阶就能到第n阶 - // 爬上 n−2 阶楼梯的方法数量,因为再爬2阶就能到第n阶 - public int dp(int n) { - if (n == 0 || n == 1) return 1; - if (memo[n] != -1) return memo[n]; - memo[n] = dp(n - 1) + dp(n - 2); - return memo[n]; - } - - } - - // 空间复杂度 o(1) - static class Solution2 { - - public int climbStairs(int n) { - if (n == 0 || n == 1) return 1; - int pre1 = 1, pre2 = 1; - for (int i = 2; i <= n; i++) { - int tmp = pre1 + pre2; - pre2 = pre1; - pre1 = tmp; - } - return pre1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\254\254N\344\270\252\346\263\260\346\263\242\351\202\243\345\245\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\254\254N\344\270\252\346\263\260\346\263\242\351\202\243\345\245\221\346\225\260.java" deleted file mode 100644 index 87a3c49..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/fib/\347\254\254N\344\270\252\346\263\260\346\263\242\351\202\243\345\245\221\346\225\260.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.dp.fib; - -import org.junit.jupiter.api.Assertions; - -/** - * 1137. 第 N 个泰波那契数 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 第N个泰波那契数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.tribonacci(4)); - Assertions.assertEquals(1389537, s.tribonacci(25)); - } - - static class Solution { - - public int tribonacci(int n) { - if (n == 0) return 0; - if (n == 1 || n == 2) return 1; - - int[] dp = new int[n + 1]; - dp[0] = 0; - dp[1] = 1; - dp[2] = 1; - for (int i = 3; i <= n; i++) { - dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]; - } - return dp[n]; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/package-info.java deleted file mode 100644 index 60b8318..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 动态规划 - 矩阵 - * - * @author Zhang Peng - * @date 2025-11-12 - */ -package io.github.dunwu.algorithm.dp.matrix; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" deleted file mode 100644 index 9d2e036..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.dunwu.algorithm.dp.matrix; - -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; - -import java.util.List; - -/** - * 120. 三角形最小路径和 - * - * @author Zhang Peng - * @since 2020-07-04 - */ -public class 三角形最小路径和 { - - public static void main(String[] args) { - Solution s = new Solution(); - List> input = ArrayUtil.toIntMatrixList(new int[][] { { 2 }, { 3, 4 }, { 6, 5, 7 }, { 4, 1, 8, 3 } }); - Assertions.assertEquals(11, s.minimumTotal(input)); - List> input2 = ArrayUtil.toIntMatrixList(new int[][] { { -10 } }); - Assertions.assertEquals(-10, s.minimumTotal(input2)); - } - - static class Solution { - - public int minimumTotal(List> triangle) { - - // base case - if (triangle == null || triangle.size() == 0) { return 0; } - if (triangle.size() == 1) { return triangle.get(0).get(0); } - - // 状态定义 - int n = triangle.size(); - int[][] dp = new int[n][n]; - - // 初始状态 - dp[0][0] = triangle.get(0).get(0); - - // 状态转移方程 - int min = Integer.MAX_VALUE; - for (int i = 1; i < n; i++) { - dp[i][0] = triangle.get(i).get(0) + dp[i - 1][0]; - for (int j = 1; j < i; j++) { - dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + triangle.get(i).get(j); - } - dp[i][i] = dp[i - 1][i - 1] + triangle.get(i).get(i); - } - - for (int j = 0; j < n; j++) { - min = Math.min(min, dp[n - 1][j]); - } - return min; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" deleted file mode 100644 index b1965bc..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.dp.matrix; - -import org.junit.jupiter.api.Assertions; - -/** - * 931. 下降路径最小和 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 下降路径最小和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(13, s.minFallingPathSum(new int[][] { { 2, 1, 3 }, { 6, 5, 4 }, { 7, 8, 9 } })); - Assertions.assertEquals(-59, s.minFallingPathSum(new int[][] { { -19, 57 }, { -40, -5 } })); - } - - static class Solution { - - public int minFallingPathSum(int[][] matrix) { - - // base case - if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return 0; } - if (matrix.length == 1) { return matrix[0][0]; } - - // 状态定义 - int n = matrix.length; - int[][] dp = new int[n][n]; - - // 初始状态、边界状态 - for (int j = 0; j < n; j++) { - dp[0][j] = matrix[0][j]; - } - - // 状态转移 - for (int i = 1; i < n; i++) { - dp[i][0] = Math.min(dp[i - 1][0], dp[i - 1][1]) + matrix[i][0]; - for (int j = 1; j < n - 1; j++) { - dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i - 1][j + 1]) + matrix[i][j]; - } - dp[i][n - 1] = Math.min(dp[i - 1][n - 1], dp[i - 1][n - 2]) + matrix[i][n - 1]; - } - - int min = Integer.MAX_VALUE; - for (int j = 0; j < n; j++) { - min = Math.min(min, dp[n - 1][j]); - } - return min; - } - - public int min(int a, int b, int c) { - return Math.min(a, Math.min(b, c)); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" deleted file mode 100644 index aa700cf..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\204.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.dp.matrix; - -import org.junit.jupiter.api.Assertions; - -/** - * 62. 不同路径 - * - * @author Zhang Peng - * @date 2025-11-12 - */ -public class 不同路径 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(28, s.uniquePaths(3, 7)); - Assertions.assertEquals(3, s.uniquePaths(3, 2)); - } - - static class Solution { - - public int uniquePaths(int m, int n) { - - // 状态定义 - int[][] dp = new int[m][n]; - - // 初始状态、边界状态 - for (int i = 0; i < m; i++) { dp[i][0] = 1; } - for (int j = 0; j < n; j++) { dp[0][j] = 1; } - - // 状态转移方程 - for (int i = 1; i < m; i++) { - for (int j = 1; j < n; j++) { - dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; - } - } - return dp[m - 1][n - 1]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" deleted file mode 100644 index 50295cf..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\344\270\215\345\220\214\350\267\257\345\276\2042.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.dp.matrix; - -import org.junit.jupiter.api.Assertions; - -/** - * 63. 不同路径 II - * - * @author Zhang Peng - * @date 2025-11-12 - */ -public class 不同路径2 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] input1 = new int[][] { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 } }; - Assertions.assertEquals(2, s.uniquePathsWithObstacles(input1)); - int[][] input2 = new int[][] { { 0, 1 }, { 0, 0 } }; - Assertions.assertEquals(1, s.uniquePathsWithObstacles(input2)); - int[][] input3 = new int[][] { { 1, 0 } }; - Assertions.assertEquals(0, s.uniquePathsWithObstacles(input3)); - int[][] input4 = new int[][] { { 0, 1, 0, 0 } }; - Assertions.assertEquals(0, s.uniquePathsWithObstacles(input4)); - } - - static class Solution { - - public int uniquePathsWithObstacles(int[][] obstacleGrid) { - - // base case - if (obstacleGrid == null || obstacleGrid.length == 0) { return 0; } - int m = obstacleGrid.length, n = obstacleGrid[0].length; - // 起点、终点有障碍,注定无法到达 - if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) { return 0; } - - // 状态定义 - int[][] dp = new int[m][n]; - - // 初始状态、边界状态 - dp[0][0] = 1; - for (int i = 1; i < m; i++) { dp[i][0] = (obstacleGrid[i][0] == 1) ? 0 : dp[i - 1][0]; } - for (int j = 1; j < n; j++) { dp[0][j] = (obstacleGrid[0][j] == 1) ? 0 : dp[0][j - 1]; } - - // 状态转移方程 - for (int i = 1; i < m; i++) { - for (int j = 1; j < n; j++) { - if (obstacleGrid[i][j] == 1) { - dp[i][j] = 0; - } else { - dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; - } - } - } - return dp[m - 1][n - 1]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" deleted file mode 100644 index 2d4926a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" +++ /dev/null @@ -1,80 +0,0 @@ -package io.github.dunwu.algorithm.dp.matrix; - -import org.junit.jupiter.api.Assertions; - -/** - * 221. 最大正方形 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最大正方形 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - char[][] input1 = new char[][] { - { '1', '0', '1', '0', '0' }, - { '1', '0', '1', '1', '1' }, - { '1', '1', '1', '1', '1' }, - { '1', '0', '0', '1', '0' } - }; - Assertions.assertEquals(4, s.maximalSquare(input1)); - - char[][] input2 = new char[][] { { '0', '1' }, { '1', '0' } }; - Assertions.assertEquals(1, s.maximalSquare(input2)); - - char[][] input3 = new char[][] { { '0' } }; - Assertions.assertEquals(0, s.maximalSquare(input3)); - - char[][] input4 = new char[][] { - { '1', '0', '1', '1', '0', '1' }, - { '1', '1', '1', '1', '1', '1' }, - { '0', '1', '1', '0', '1', '1' }, - { '1', '1', '1', '0', '1', '0' }, - { '0', '1', '1', '1', '1', '1' }, - { '1', '1', '0', '1', '1', '1' } - }; - Assertions.assertEquals(4, s.maximalSquare(input4)); - } - - static class Solution { - - public int maximalSquare(char[][] matrix) { - - // base case - if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) { return 0; } - - // 状态定义 - int m = matrix.length, n = matrix[0].length; - int[][] dp = new int[m][n]; - - // 状态转移方程 - int max = 0; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (i == 0 || j == 0) { - dp[i][j] = matrix[i][j] == '1' ? 1 : 0; - } else { - if (matrix[i][j] == '1') { - dp[i][j] = min( - dp[i - 1][j], - dp[i][j - 1], - dp[i - 1][j - 1] - ) + 1; - } - } - max = Math.max(dp[i][j], max); - } - } - return max * max; - } - - public int min(int a, int b, int c) { - return Math.min(Math.min(a, b), c); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" deleted file mode 100644 index b20d79b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/matrix/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.dp.matrix; - -import org.junit.jupiter.api.Assertions; - -/** - * 64. 最小路径和 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最小路径和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(7, s.minPathSum(new int[][] { { 1, 3, 1 }, { 1, 5, 1 }, { 4, 2, 1 } })); - Assertions.assertEquals(12, s.minPathSum(new int[][] { { 1, 2, 3 }, { 4, 5, 6 } })); - } - - static class Solution { - - public int minPathSum(int[][] grid) { - if (grid == null || grid.length == 0 || grid[0].length == 0) { return 0; } - int m = grid.length, n = grid[0].length; - int[][] dp = new int[m][n]; - dp[0][0] = grid[0][0]; - for (int i = 1; i < m; i++) { dp[i][0] = dp[i - 1][0] + grid[i][0]; } - for (int j = 1; j < n; j++) { dp[0][j] = dp[0][j - 1] + grid[0][j]; } - for (int i = 1; i < m; i++) { - for (int j = 1; j < n; j++) { - dp[i][j] = Math.min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; - } - } - return dp[m - 1][n - 1]; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/package-info.java deleted file mode 100644 index 48674a2..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 动态规划算法 - * - * @author Zhang Peng - * @since 2020-03-06 - */ -package io.github.dunwu.algorithm.dp; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" deleted file mode 100644 index af5cc5f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" +++ /dev/null @@ -1,36 +0,0 @@ -package io.github.dunwu.algorithm.dp.state; - -import org.junit.jupiter.api.Assertions; - -/** - * 121. 买卖股票的最佳时机 - * - * @author Zhang Peng - * @since 2020-07-05 - */ -public class 买卖股票的最佳时机 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(5, s.maxProfit(new int[] { 7, 1, 5, 3, 6, 4 })); - Assertions.assertEquals(0, s.maxProfit(new int[] { 7, 6, 4, 3, 1 })); - } - - static class Solution { - - public int maxProfit(int[] prices) { - int min = prices[0]; - int max = 0; - for (int i = 1; i < prices.length; i++) { - if (prices[i] <= min) { - min = prices[i]; - } else { - max = Math.max(max, prices[i] - min); - } - } - return max; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\2722.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\2722.java" deleted file mode 100644 index 98b90e7..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\2722.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.dp.state; - -import org.junit.jupiter.api.Assertions; - -/** - * 122. 买卖股票的最佳时机 II - * - * @author Zhang Peng - * @since 2020-07-05 - */ -public class 买卖股票的最佳时机2 { - - public static void main(String[] args) { - int[] prices = { 7, 1, 5, 3, 6, 4 }; - int[] prices2 = { 1, 2, 3, 4, 5 }; - Assertions.assertEquals(7, maxProfit(prices)); - Assertions.assertEquals(4, maxProfit(prices2)); - } - - public static int maxProfit(int[] prices) { - if (prices == null || prices.length == 0) return 0; - - int max = 0; - final int days = prices.length; - final int[][] dp = new int[days][2]; - - dp[0][0] = 0; - dp[0][1] = -prices[0]; - - for (int i = 1; i < days; i++) { - dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); - dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); - max = Math.max(dp[i][0], dp[i][1]); - } - return max; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" deleted file mode 100644 index 916188a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272III.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.dp.state; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 123. 买卖股票的最佳时机 III - * @since 2020-07-05 - */ -public class 买卖股票的最佳时机III { - - public static void main(String[] args) { - int[] prices = { 3, 3, 5, 0, 0, 3, 1, 4 }; - int[] prices2 = { 1, 2, 3, 4, 5 }; - Assertions.assertEquals(6, maxProfit(prices)); - Assertions.assertEquals(4, maxProfit(prices2)); - } - - public static int maxProfit(int[] prices) { - if (prices == null || prices.length == 0) return 0; - final int days = prices.length; - final int deal = 2; // 交易笔数 - - // 定义二维数组 - // 一维表示第 i 天 - // 二维表示交易笔数,最多 2 笔 - // 三维表示是否持有股票:0/1(持有) - int[][][] dp = new int[days][deal + 1][2]; - - // 第一天数据初始化 - for (int k = 0; k <= deal; k++) { - dp[0][k][0] = 0; - dp[0][k][1] = -prices[0]; - } - - for (int i = 1; i < days; i++) { // 扫描天数 - for (int k = deal; k >= 1; k--) { - dp[i][k][0] = Math.max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i]); - dp[i][k][1] = Math.max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i]); - } - } - - return dp[days - 1][deal][0]; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" deleted file mode 100644 index f2bb072..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272IV.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.dp.state; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 188. 买卖股票的最佳时机 IV - * @since 2020-07-05 - */ -public class 买卖股票的最佳时机IV { - - public static void main(String[] args) { - int[] prices = { 2, 4, 1 }; - int[] prices2 = { 3, 2, 6, 5, 0, 3 }; - Assertions.assertEquals(2, maxProfit(2, prices)); - Assertions.assertEquals(7, maxProfit(2, prices2)); - } - - public static int maxProfit(final int k, int[] prices) { - if (prices == null || prices.length == 0) return 0; - final int days = prices.length; - if (k > days / 2) return maxProfit(prices); - - // 定义二维数组 - // 一维表示第 i 天 - // 二维表示交易笔数,最多 2 笔 - // 三维表示是否持有股票:0/1(持有) - int[][][] dp = new int[days][k + 1][2]; - - // 第一天数据初始化 - for (int j = 0; j <= k; j++) { - dp[0][j][0] = 0; - dp[0][j][1] = -prices[0]; - } - - for (int i = 1; i < days; i++) { // 扫描天数 - for (int j = k; j >= 1; j--) { - dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]); - dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]); - } - } - - return dp[days - 1][k][0]; - } - - public static int maxProfit(int[] prices) { - if (prices == null || prices.length == 0) return 0; - - int max = 0; - final int days = prices.length; - final int[][] dp = new int[days][2]; - - dp[0][0] = 0; - dp[0][1] = -prices[0]; - - for (int i = 1; i < days; i++) { - dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); - dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); - max = Math.max(dp[i][0], dp[i][1]); - } - return max; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" deleted file mode 100644 index 134b337..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272\345\220\253\346\211\213\347\273\255\350\264\271.java" +++ /dev/null @@ -1,36 +0,0 @@ -package io.github.dunwu.algorithm.dp.state; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 714. - * 买卖股票的最佳时机含手续费 - * @since 2020-07-05 - */ -public class 买卖股票的最佳时机含手续费 { - - public static void main(String[] args) { - int[] prices = { 1, 3, 2, 8, 4, 9 }; - Assertions.assertEquals(8, maxProfit(prices, 2)); - } - - public static int maxProfit(int[] prices, int fee) { - if (prices == null || prices.length == 0) return 0; - - int max = 0; - final int days = prices.length; - final int[][] dp = new int[days][2]; - - dp[0][0] = 0; - dp[0][1] = -prices[0]; - - for (int i = 1; i < days; i++) { - dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee); - dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); - max = Math.max(dp[i][0], dp[i][1]); - } - return max; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" deleted file mode 100644 index 9836d29..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/state/\346\234\200\344\275\263\344\271\260\345\215\226\350\202\241\347\245\250\346\227\266\346\234\272\345\220\253\345\206\267\345\206\273\346\234\237.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.dp.state; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 309. 最佳买卖股票时机含冷冻期 - * @since 2020-07-05 - */ -public class 最佳买卖股票时机含冷冻期 { - - public static void main(String[] args) { - int[] prices = { 1, 2, 3, 0, 2 }; - Assertions.assertEquals(3, maxProfit(prices)); - } - - public static int maxProfit(int[] prices) { - if (prices == null || prices.length == 0) return 0; - - int max = 0; - final int days = prices.length; - final int[][][] dp = new int[days][2][2]; - - dp[0][0][0] = 0; - dp[0][0][1] = 0; - dp[0][1][0] = -prices[0]; - - for (int i = 1; i < days; i++) { - dp[i][0][0] = Math.max(dp[i - 1][0][0], dp[i - 1][0][1]); - dp[i][0][1] = dp[i - 1][1][0] + prices[i]; - dp[i][1][0] = Math.max(dp[i - 1][0][0] - prices[i], dp[i - 1][1][0]); - - int temp1 = Math.max(dp[i][0][0], dp[i][0][1]); - int temp2 = Math.max(dp[i][1][0], temp1); - max = Math.max(max, temp2); - } - return max; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" deleted file mode 100644 index a3df26e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\345\210\240\351\231\244\346\223\215\344\275\234.java" +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.dunwu.algorithm.dp.str; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 583. 两个字符串的删除操作 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 两个字符串的删除操作 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.minDistance("sea", "eat")); - } - - static class Solution { - - public int minDistance(String word1, String word2) { - int lcs = longestCommonSubsequence(word1, word2); - return word1.length() + word2.length() - lcs - lcs; - } - - public int longestCommonSubsequence(String text1, String text2) { - int[][] memo = new int[text1.length()][text2.length()]; - for (int i = 0; i < text1.length(); i++) { - Arrays.fill(memo[i], -1); - } - return dp(memo, text1, 0, text2, 0); - } - - public int dp(int[][] memo, String text1, int i, String text2, int j) { - if (i < 0 || j < 0 || i >= text1.length() || j >= text2.length()) { return 0; } - if (memo[i][j] != -1) { return memo[i][j]; } - - if (text1.charAt(i) == text2.charAt(j)) { - memo[i][j] = 1 + dp(memo, text1, i + 1, text2, j + 1); - } else { - memo[i][j] = max( - dp(memo, text1, i + 1, text2, j), - dp(memo, text1, i, text2, j + 1), - dp(memo, text1, i + 1, text2, j + 1) - ); - } - return memo[i][j]; - } - - public int max(int a, int b, int c) { - return Math.max(a, Math.max(b, c)); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\260\217ASCII\345\210\240\351\231\244\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\260\217ASCII\345\210\240\351\231\244\345\222\214.java" deleted file mode 100644 index 18a5317..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\344\270\244\344\270\252\345\255\227\347\254\246\344\270\262\347\232\204\346\234\200\345\260\217ASCII\345\210\240\351\231\244\345\222\214.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.dp.str; - -import org.junit.jupiter.api.Assertions; - -/** - * 712. 两个字符串的最小ASCII删除和 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 两个字符串的最小ASCII删除和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(231, s.minimumDeleteSum("sea", "eat")); - Assertions.assertEquals(403, s.minimumDeleteSum("delete", "leet")); - } - - static class Solution { - - public int minimumDeleteSum(String s1, String s2) { - int m = s1.length(), n = s2.length(); - int[][] dp = new int[m + 1][n + 1]; - for (int i = 1; i <= m; i++) { - dp[i][0] = dp[i - 1][0] + s1.codePointAt(i - 1); - } - for (int j = 1; j <= n; j++) { - dp[0][j] = dp[0][j - 1] + s2.codePointAt(j - 1); - } - for (int i = 1; i <= m; i++) { - int code1 = s1.codePointAt(i - 1); - for (int j = 1; j <= n; j++) { - int code2 = s2.codePointAt(j - 1); - if (code1 == code2) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = Math.min(dp[i - 1][j] + code1, dp[i][j - 1] + code2); - } - } - } - return dp[m][n]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" deleted file mode 100644 index 97e11ea..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\345\215\225\350\257\215\346\213\206\345\210\206.java" +++ /dev/null @@ -1,112 +0,0 @@ -package io.github.dunwu.algorithm.dp.str; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - -/** - * 139. 单词拆分 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 单词拆分 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.wordBreak("leetcode", Arrays.asList("leet", "code"))); - Assertions.assertTrue(s.wordBreak("applepenapple", Arrays.asList("apple", "pen"))); - Assertions.assertFalse(s.wordBreak("catsandog", Arrays.asList("cats", "dog", "sand", "and", "cat"))); - - Solution2 s2 = new Solution2(); - Assertions.assertTrue(s2.wordBreak("leetcode", Arrays.asList("leet", "code"))); - Assertions.assertTrue(s2.wordBreak("applepenapple", Arrays.asList("apple", "pen"))); - Assertions.assertFalse(s2.wordBreak("catsandog", Arrays.asList("cats", "dog", "sand", "and", "cat"))); - } - - // 回溯解决方案 - static class Solution { - - // 记录是否找到一个合法的答案 - boolean found = false; - // 记录回溯算法的路径 - private LinkedList path; - - public boolean wordBreak(String s, List wordDict) { - found = false; - path = new LinkedList<>(); - backtrack(wordDict, s, 0); - return found; - } - - public void backtrack(List wordDict, String target, int start) { - - // 找到一个合法答案 - if (start == target.length()) { found = true; } - // 如果已经找到答案,就不要再递归搜索了 - if (found) { return; } - - // 回溯算法框架 - for (String word : wordDict) { - - int len = word.length(); - - // 无效情况,剪枝 - if (start + len > target.length()) { return; } - if (!target.substring(start, start + len).equals(word)) { continue; } - - // 【选择】 - path.add(word); - // 【回溯】 - backtrack(wordDict, target, start + len); - // 【取消选择】 - path.remove(path.size() - 1); - } - } - - } - - static class Solution2 { - - // 备忘录,-1 代表未计算,0 代表无法凑出,1 代表可以凑出 - private int[] memo; - // 用哈希集合方便快速判断是否存在 - HashSet wordDict; - - public boolean wordBreak(String s, List wordDict) { - this.wordDict = new HashSet<>(wordDict); - this.memo = new int[s.length()]; - Arrays.fill(memo, -1); - return dp(s, 0); - } - - public boolean dp(String s, int index) { - // base case - if (index == s.length()) { return true; } - // 避免冗余 - if (memo[index] != -1) { return memo[index] == 0 ? false : true; } - - // 遍历 s[i..] 的所有前缀 - for (int len = 1; index + len <= s.length(); len++) { - // 看看哪些前缀存在 wordDict 中 - String prefix = s.substring(index, index + len); - if (wordDict.contains(prefix)) { - // 找到一个单词匹配 s[i..i+len) - // 只要 s[i+len..] 可以被拼出,s[i..] 就能被拼出 - if (dp(s, index + len)) { - memo[index] = 1; - return true; - } - } - } - // s[i..] 无法被拼出 - memo[index] = 0; - return false; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.java" deleted file mode 100644 index 4104ba8..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.dp.str; - -import org.junit.jupiter.api.Assertions; - -/** - * 516. 最长回文子序列 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最长回文子序列 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.longestPalindromeSubseq("bbbab")); - Assertions.assertEquals(2, s.longestPalindromeSubseq("v")); - } - - static class Solution { - - public int longestPalindromeSubseq(String s) { - int n = s.length(); - int[][] dp = new int[n][n]; - for (int i = n - 1; i >= 0; i--) { - dp[i][i] = 1; - for (int j = i + 1; j < n; j++) { - if (s.charAt(i) == s.charAt(j)) { - dp[i][j] = dp[i + 1][j - 1] + 2; - } else { - dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]); - } - } - } - return dp[0][n - 1]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\347\274\226\350\276\221\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\347\274\226\350\276\221\350\267\235\347\246\273.java" deleted file mode 100644 index 2dc83a4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/str/\347\274\226\350\276\221\350\267\235\347\246\273.java" +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.dunwu.algorithm.dp.str; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 72. 编辑距离 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 编辑距离 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.minDistance("horse", "ros")); - Assertions.assertEquals(5, s.minDistance("intention", "execution")); - } - - static class Solution { - - int[][] memo; - - public int minDistance(String word1, String word2) { - memo = new int[word1.length()][word2.length()]; - for (int i = 0; i < word1.length(); i++) { - Arrays.fill(memo[i], Integer.MAX_VALUE); - } - return dp(word1, 0, word2, 0); - } - - public int dp(String word1, int i, String word2, int j) { - if (i >= word1.length()) { return word2.length() - j; } - if (j >= word2.length()) { return word1.length() - i; } - if (memo[i][j] != Integer.MAX_VALUE) { - return memo[i][j]; - } - if (word1.charAt(i) == word2.charAt(j)) { - memo[i][j] = dp(word1, i + 1, word2, j + 1); - } else { - memo[i][j] = min( - dp(word1, i + 1, word2, j), - dp(word1, i, word2, j + 1), - dp(word1, i + 1, word2, j + 1) - ) + 1; - } - return memo[i][j]; - } - - public int min(int a, int b, int c) { - return Math.min(a, Math.min(b, c)); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\215\347\233\270\344\272\244\347\232\204\347\272\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\215\347\233\270\344\272\244\347\232\204\347\272\277.java" deleted file mode 100644 index 290ae9d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\344\270\215\347\233\270\344\272\244\347\232\204\347\272\277.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.dp.subseq; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 300. 最长递增子序列 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 不相交的线 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.maxUncrossedLines(new int[] { 1, 4, 2 }, new int[] { 1, 2, 4 })); - } - - static class Solution { - - int[][] memo; - - public int maxUncrossedLines(int[] nums1, int[] nums2) { - memo = new int[nums1.length + 1][nums2.length + 1]; - for (int i = 0; i <= nums1.length; i++) { - Arrays.fill(memo[i], -1); - } - return dp(nums1, 0, nums2, 0); - } - - public int dp(int[] nums1, int i, int[] nums2, int j) { - if (i < 0 || i >= nums1.length || j < 0 || j >= nums2.length) { return 0; } - if (memo[i][j] != -1) { return memo[i][j]; } - if (nums1[i] == nums2[j]) { - memo[i][j] = dp(nums1, i + 1, nums2, j + 1) + 1; - } else { - memo[i][j] = max( - dp(nums1, i, nums2, j + 1), - dp(nums1, i + 1, nums2, j), - dp(nums1, i + 1, nums2, j + 1) - ); - } - return memo[i][j]; - } - - public int max(int a, int b, int c) { - return Math.max(a, Math.max(b, c)); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" deleted file mode 100644 index ad63c86..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.dp.subseq; - -import org.junit.jupiter.api.Assertions; - -/** - * 392. 判断子序列 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 判断子序列 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isSubsequence("abc", "ahbgdc")); - Assertions.assertFalse(s.isSubsequence("axc", "ahbgdc")); - Assertions.assertTrue(s.isSubsequence("", "ahbgdc")); - Assertions.assertFalse(s.isSubsequence("aaaaaa", "bbaaaa")); - } - - static class Solution { - - public boolean isSubsequence(String s, String t) { - int m = s.length(), n = t.length(); - - // dp[i][j] 表示 s 的前 i 个字符是否是 t 的前 j 个字符的子序列 - boolean[][] dp = new boolean[m + 1][n + 1]; - - // 初始化:空字符串是任何字符串的子序列 - for (int j = 0; j <= n; j++) { - dp[0][j] = true; - } - - // 动态规划填表 - for (int i = 1; i <= m; i++) { - for (int j = 1; j <= n; j++) { - if (s.charAt(i - 1) == t.charAt(j - 1)) { - // 字符匹配,取决于前一个状态 - dp[i][j] = dp[i - 1][j - 1]; - } else { - // 字符不匹配,只能尝试在 t 中继续寻找 - dp[i][j] = dp[i][j - 1]; - } - } - } - - return dp[m][n]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" deleted file mode 100644 index 22b2183..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.dp.subseq; - -import org.junit.jupiter.api.Assertions; - -/** - * 53. 最大子序和 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 最大子序和 { - - public static void main(String[] args) { - int[] nums = { -2, 1, -3, 4, -1, 2, 1, -5, 4 }; - Assertions.assertEquals(6, maxSubArray(nums)); - Assertions.assertEquals(-1, maxSubArray(new int[] { -1 })); - } - - public static int maxSubArray(int[] nums) { - if (nums == null || nums.length == 0) return 0; - - int[] dp = new int[nums.length + 1]; - dp[0] = nums[0]; - int max = dp[0]; - for (int i = 1; i < nums.length; i++) { - dp[i] = dp[i - 1] >= 0 ? dp[i - 1] + nums[i] : nums[i]; - } - - for (int i = 0; i < nums.length; i++) { - if (max < dp[i]) { - max = dp[i]; - } - } - return max; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" deleted file mode 100644 index d7ff0fe..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227.java" +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.dunwu.algorithm.dp.subseq; - -import org.junit.jupiter.api.Assertions; - -/** - * 300. 最长上升子序列 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 最长上升子序列 { - - public static void main(String[] args) { - int[] nums = { 10, 9, 2, 5, 3, 7, 101, 18 }; - Assertions.assertEquals(4, lengthOfLIS(nums)); - Assertions.assertEquals(1, lengthOfLIS(new int[] { 0 })); - } - - public static int lengthOfLIS(int[] nums) { - if (nums == null || nums.length == 0) return 0; - int max = 1; - final int[] dp = new int[nums.length + 1]; - for (int i = 0; i < nums.length; i++) dp[i] = 1; - for (int i = 1; i < nums.length; i++) { - for (int j = 0; j < i; j++) { - if (nums[j] < nums[i]) { - dp[i] = Math.max(dp[i], dp[j] + 1); - } - } - max = Math.max(max, dp[i]); - } - return max; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" deleted file mode 100644 index cf7c08e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227.java" +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.dunwu.algorithm.dp.subseq; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 1143. 最长公共子序列 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最长公共子序列 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.longestCommonSubsequence("abcde", "ace")); - Assertions.assertEquals(3, s.longestCommonSubsequence("abc", "abc")); - Assertions.assertEquals(0, s.longestCommonSubsequence("abc", "def")); - } - - static class Solution { - - private int[][] memo; - - public int longestCommonSubsequence(String text1, String text2) { - int m = text1.length(), n = text2.length(); - memo = new int[m + 1][n + 1]; - for (int i = 0; i <= m; i++) { - Arrays.fill(memo[i], -1); - } - return dp(text1, 0, text2, 0); - } - - public int dp(String text1, int i, String text2, int j) { - if (i < 0 || i >= text1.length() || j < 0 || j >= text2.length()) { return 0; } - if (memo[i][j] != -1) { return memo[i][j]; } - if (text1.charAt(i) == text2.charAt(j)) { - memo[i][j] = dp(text1, i + 1, text2, j + 1) + 1; - } else { - memo[i][j] = max( - dp(text1, i + 1, text2, j), - dp(text1, i, text2, j + 1), - dp(text1, i + 1, text2, j + 1) - ); - } - return memo[i][j]; - } - - public int max(int a, int b, int c) { - return Math.max(a, Math.max(b, c)); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\256\232\345\267\256\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\256\232\345\267\256\345\255\220\345\272\217\345\210\227.java" deleted file mode 100644 index d7ae1d4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\345\256\232\345\267\256\345\255\220\345\272\217\345\210\227.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.dp.subseq; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 1218. 最长定差子序列 - * - * @author Zhang Peng - * @date 2025-11-14 - */ -public class 最长定差子序列 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.longestSubsequence(new int[] { 1, 2, 3, 4 }, 1)); - Assertions.assertEquals(1, s.longestSubsequence(new int[] { 1, 3, 5, 7 }, 1)); - Assertions.assertEquals(4, s.longestSubsequence(new int[] { 1, 5, 7, 8, 5, 3, 4, 2, 1 }, -2)); - Assertions.assertEquals(2, s.longestSubsequence(new int[] { 3, 4, -3, -2, -4 }, -5)); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(4, s2.longestSubsequence(new int[] { 1, 2, 3, 4 }, 1)); - Assertions.assertEquals(1, s2.longestSubsequence(new int[] { 1, 3, 5, 7 }, 1)); - Assertions.assertEquals(4, s2.longestSubsequence(new int[] { 1, 5, 7, 8, 5, 3, 4, 2, 1 }, -2)); - Assertions.assertEquals(2, s2.longestSubsequence(new int[] { 3, 4, -3, -2, -4 }, -5)); - } - - static class Solution { - - public int longestSubsequence(int[] arr, int diff) { - int n = arr.length; - Map map = new HashMap<>(); - int[][] dp = new int[n][2]; - dp[0][1] = 1; - map.put(arr[0], 0); - for (int i = 1; i < n; i++) { - dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]); - dp[i][1] = 1; - int prev = arr[i] - diff; - if (map.containsKey(prev)) dp[i][1] = Math.max(dp[i][1], dp[map.get(prev)][1] + 1); - map.put(arr[i], i); - } - return Math.max(dp[n - 1][0], dp[n - 1][1]); - } - - } - - static class Solution2 { - - public int longestSubsequence(int[] arr, int diff) { - int res = 1; - Map map = new HashMap<>(); - for (int val : arr) { - map.put(val, map.getOrDefault(val - diff, 0) + 1); - res = Math.max(res, map.get(val)); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\346\225\260\345\257\271\351\223\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\346\225\260\345\257\271\351\223\276.java" deleted file mode 100644 index ae2ef0d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\346\225\260\345\257\271\351\223\276.java" +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.dp.subseq; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.Comparator; - -/** - * 646. 最长数对链 - * - * @author Zhang Peng - * @date 2025-11-14 - */ -public class 最长数对链 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] input1 = new int[][] { { 1, 2 }, { 2, 3 }, { 3, 4 } }; - Assertions.assertEquals(2, s.findLongestChain(input1)); - - int[][] input2 = new int[][] { { 1, 2 }, { 7, 8 }, { 4, 5 } }; - Assertions.assertEquals(3, s.findLongestChain(input2)); - } - - static class Solution { - - public int findLongestChain(int[][] pairs) { - Arrays.sort(pairs, Comparator.comparingInt(pair -> pair[0])); - int n = pairs.length; - int[] dp = new int[n]; - for (int i = 0; i < n; i++) { - dp[i] = 1; - for (int j = 0; j < i; j++) { - if (pairs[i][0] > pairs[j][1]) { - dp[i] = Math.max(dp[i], dp[j] + 1); - } - } - } - return dp[n - 1]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\347\255\211\345\267\256\346\225\260\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\347\255\211\345\267\256\346\225\260\345\210\227.java" deleted file mode 100644 index e0b1b49..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\347\255\211\345\267\256\346\225\260\345\210\227.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.dp.subseq; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 1027. 最长等差数列 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最长等差数列 { - - public static void main(String[] args) { - Solution s = new Solution(); - // Assertions.assertEquals(4, s.longestArithSeqLength(new int[] { 3, 6, 9, 12 })); - // Assertions.assertEquals(3, s.longestArithSeqLength(new int[] { 9, 4, 7, 2, 10 })); - Assertions.assertEquals(4, s.longestArithSeqLength(new int[] { 20, 1, 15, 3, 10, 5, 8 })); - } - - static class Solution { - - public int longestArithSeqLength(int[] nums) { - int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE; - for (int num : nums) { - min = Math.min(min, num); - max = Math.max(max, num); - } - - int res = 1; - int maxDiff = max - min; - for (int diff = -maxDiff; diff <= maxDiff; diff++) { - res = Math.max(longestSubsequence(nums, diff), res); - } - return res; - } - - public int longestSubsequence(int[] arr, int diff) { - int res = 1; - Map map = new HashMap<>(); - for (int val : arr) { - map.put(val, map.getOrDefault(val - diff, 0) + 1); - res = Math.max(res, map.get(val)); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" deleted file mode 100644 index ad8cb65..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/subseq/\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.dp.subseq; - -import org.junit.jupiter.api.Assertions; - -/** - * 300. 最长递增子序列 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最长递增子序列 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.lengthOfLIS(new int[] { 10, 9, 2, 5, 3, 7, 101, 18 })); - Assertions.assertEquals(4, s.lengthOfLIS(new int[] { 0, 1, 0, 3, 2, 3 })); - Assertions.assertEquals(1, s.lengthOfLIS(new int[] { 7, 7, 7, 7, 7, 7, 7 })); - } - - static class Solution { - - public int lengthOfLIS(int[] nums) { - int n = nums.length; - int[] dp = new int[n]; - int max = 1; - for (int i = 0; i < n; i++) { - dp[i] = 1; - for (int j = 0; j < i; j++) { - // 枚举区间 [0,i) 的所有数 nums[j],如果满足 nums[j]300. 最长递增子序列 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最长递增子序列的个数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.findNumberOfLIS(new int[] { 1, 3, 5, 4, 7 })); - Assertions.assertEquals(5, s.findNumberOfLIS(new int[] { 2, 2, 2, 2, 2 })); - Assertions.assertEquals(3, s.findNumberOfLIS(new int[] { 1, 2, 4, 3, 5, 4, 7, 2 })); - } - - static class Solution { - - public int findNumberOfLIS(int[] nums) { - - int n = nums.length; - int[] dp = new int[n]; - int[] cnt = new int[n]; - int max = 1; - for (int i = 0; i < n; i++) { - dp[i] = cnt[i] = 1; - for (int j = 0; j < i; j++) { - if (nums[j] < nums[i]) { - if (dp[i] < dp[j] + 1) { - dp[i] = dp[j] + 1; - cnt[i] = cnt[j]; - } else if (dp[i] == dp[j] + 1) { - cnt[i] += cnt[j]; - } - } - } - max = Math.max(max, dp[i]); - } - int res = 0; - for (int i = 0; i < n; i++) { - if (dp[i] == max) res += cnt[i]; - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\346\250\241\346\235\277.java" deleted file mode 100644 index 654e676..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\346\250\241\346\235\277.java" +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.dunwu.algorithm.dp.template; - -/** - * 动态规划模板 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 动态规划模板 { - // 自顶向下递归的动态规划 - // def dp(状态1, 状态2, ...): - // for 选择 in 所有可能的选择: - // # 此时的状态已经因为做了选择而改变 - // result = 求最值(result, dp(状态1, 状态2, ...)) - // return result - - // 自底向上迭代的动态规划 - // 初始化 base case - // dp[0][0][...] = base case - // # 进行状态转移 - // for 状态1 in 状态1的所有取值: - // for 状态2 in 状态2的所有取值: - // for ... - // dp[状态1][状态2][...] = 求最值(选择1,选择2...) -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\350\247\243\350\203\214\345\214\205\351\227\256\351\242\230\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\350\247\243\350\203\214\345\214\205\351\227\256\351\242\230\346\250\241\346\235\277.java" deleted file mode 100644 index ded4738..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/template/\345\212\250\346\200\201\350\247\204\345\210\222\350\247\243\350\203\214\345\214\205\351\227\256\351\242\230\346\250\241\346\235\277.java" +++ /dev/null @@ -1,22 +0,0 @@ -package io.github.dunwu.algorithm.dp.template; - -/** - * 动态规划解背包问题模板 - * - * @author Zhang Peng - * @date 2025-12-17 - */ -public class 动态规划解背包问题模板 { - - // int[][] dp[N+1][W+1] - // dp[0][..] = 0 - // dp[..][0] = 0 - // - // for i in [1..N]: - // for w in [1..W]: - // dp[i][w] = max( - // 把物品 i 装进背包, - // 不把物品 i 装进背包 - // ) - // return dp[N][W] -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" deleted file mode 100644 index 3f7dff2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204.java" +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.dunwu.algorithm.dp; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @since 2020-07-05 - */ -public class 乘积最大子数组 { - - public static void main(String[] args) { - int[] nums = { 2, 3, -2, 4 }; - int[] nums2 = { -2, 0, -1 }; - // Assertions.assertEquals(6, maxProduct(nums)); - Assertions.assertEquals(6, maxProduct2(nums)); - Assertions.assertEquals(0, maxProduct2(nums2)); - } - - public static int maxProduct(int[] nums) { - return backtrack(nums, 0, 0, 1, 0); - } - - // 递归 + 回溯 暴力破解 - // 时间复杂度 O(2^N) - public static int backtrack(int[] nums, int begin, int end, int res, int max) { - if (end >= nums.length || begin > end) return max; - res *= nums[end]; - if (res > max) { - return backtrack(nums, begin, end + 1, res, res); - } else { - return backtrack(nums, end + 1, end + 1, 1, max); - } - } - - public static int maxProduct2(int[] nums) { - int min = nums[0]; - int max = nums[0]; - int res = nums[0]; - for (int i = 1; i < nums.length; i++) { - int currMax = Math.max(Math.max(nums[i] * max, nums[i] * min), nums[i]); - int currMin = Math.min(Math.min(nums[i] * max, nums[i] * min), nums[i]); - res = Math.max(currMax, res); - max = currMax; - min = currMin; - } - return res; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" deleted file mode 100644 index f478807..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.dp; - -import org.junit.jupiter.api.Assertions; - -/** - * 416. 分割等和子集 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 分割等和子集 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.canPartition(new int[] { 1, 5, 11, 5 })); - Assertions.assertFalse(s.canPartition(new int[] { 1, 2, 3, 5 })); - } - - static class Solution { - - public boolean canPartition(int[] wights) { - - int sum = 0; - for (int weight : wights) { - sum += weight; - } - - // 和为奇数时,不可能划分成两个和相等的集合 - if (sum % 2 != 0) return false; - - // 初始化为背包问题 - int W = sum / 2; - int N = wights.length; - - // base case - boolean[][] dp = new boolean[N + 1][W + 1]; - for (int i = 0; i <= N; i++) - dp[i][0] = true; - - for (int i = 1; i <= N; i++) { - for (int w = 1; w <= W; w++) { - if (w - wights[i - 1] < 0) { - dp[i][w] = dp[i - 1][w]; - } else { - dp[i][w] = dp[i - 1][w] - || dp[i - 1][w - wights[i - 1]]; - } - } - } - return dp[N][W]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" deleted file mode 100644 index e7af1a6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\234\200\345\244\247\345\255\220\346\225\260\347\273\204\345\222\214.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.dp; - -import org.junit.jupiter.api.Assertions; - -/** - * 53. 最大子数组和 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 最大子数组和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(6, s.maxSubArray(new int[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 })); - } - - static class Solution { - - public int maxSubArray(int[] nums) { - int n = nums.length; - if (n == 0) return 0; - int[] dp = new int[n]; - // base case - // 第一个元素前面没有子数组 - dp[0] = nums[0]; - // 状态转移方程 - int res = Integer.MIN_VALUE; - for (int i = 1; i < n; i++) { - dp[i] = Math.max(nums[i], nums[i] + dp[i - 1]); - res = Math.max(res, dp[i]); - System.out.printf("nums[%d] = %d, dp[%d] = %d\n", i, nums[i], i, dp[i]); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\222.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\222.java" deleted file mode 100644 index 4ace68d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\222.java" +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.dunwu.algorithm.dp; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * 118. 杨辉三角 - * - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 杨辉三角 { - - public static void main(String[] args) { - Solution s = new Solution(); - List> expect = new ArrayList<>(); - expect.add(Arrays.asList(1)); - expect.add(Arrays.asList(1, 1)); - expect.add(Arrays.asList(1, 2, 1)); - expect.add(Arrays.asList(1, 3, 3, 1)); - expect.add(Arrays.asList(1, 4, 6, 4, 1)); - List> lists = s.generate(5); - Assertions.assertArrayEquals(expect.toArray(), lists.toArray()); - } - - static class Solution { - - public List> generate(int row) { - int[][] matrix = new int[row][row]; - matrix[0][0] = 1; - List> res = new ArrayList<>(); - res.add(Collections.singletonList(1)); - for (int i = 1; i < row; i++) { - List list = new ArrayList<>(); - for (int j = 0; j <= i; j++) { - if (j == 0) { - matrix[i][j] = matrix[i - 1][j]; - } else { - matrix[i][j] = matrix[i - 1][j] + matrix[i - 1][j - 1]; - } - list.add(matrix[i][j]); - } - res.add(list); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\2222.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\2222.java" deleted file mode 100644 index a6a3faa..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\346\235\250\350\276\211\344\270\211\350\247\2222.java" +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.dunwu.algorithm.dp; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * 119. 杨辉三角 II - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 杨辉三角2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 3, 1 }, s.getRow(3).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1 }, s.getRow(0).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1, 1 }, s.getRow(1).toArray()); - } - - static class Solution { - - public List getRow(int rowIndex) { - int row = rowIndex + 1; - int[][] matrix = new int[row][row]; - matrix[0][0] = 1; - List> res = new ArrayList<>(); - res.add(Collections.singletonList(1)); - for (int i = 1; i < row; i++) { - List list = new ArrayList<>(); - for (int j = 0; j <= i; j++) { - if (j == 0) { - matrix[i][j] = matrix[i - 1][j]; - } else { - matrix[i][j] = matrix[i - 1][j] + matrix[i - 1][j - 1]; - } - list.add(matrix[i][j]); - } - res.add(list); - } - return res.get(rowIndex); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" deleted file mode 100644 index c0b0b76..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/dp/\351\233\266\351\222\261\345\205\221\346\215\2422.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.dp; - -import org.junit.jupiter.api.Assertions; - -/** - * 518. 零钱兑换 II - * - * @author Zhang Peng - * @date 2025-11-11 - */ -public class 零钱兑换2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.change(5, new int[] { 1, 2, 5 })); - Assertions.assertEquals(0, s.change(3, new int[] { 2 })); - Assertions.assertEquals(1, s.change(10, new int[] { 10 })); - } - - static class Solution { - - public int change(int amount, int[] coins) { - int n = coins.length; - int[][] dp = new int[n + 1][amount + 1]; - // base case - for (int i = 0; i <= n; i++) - dp[i][0] = 1; - - for (int i = 1; i <= n; i++) { - for (int j = 1; j <= amount; j++) - if (j - coins[i - 1] >= 0) { - dp[i][j] = dp[i - 1][j] - + dp[i][j - coins[i - 1]]; - } else { dp[i][j] = dp[i - 1][j]; } - } - return dp[n][amount]; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Edge.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Edge.java deleted file mode 100644 index c4ee513..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Edge.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.dunwu.algorithm.graph; - -/** - * 存储相邻节点及边的权重 - */ -public class Edge { - - public int to; - public int weight; - - public Edge(int to, int weight) { - this.to = to; - this.weight = weight; - } - -} \ No newline at end of file diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Graph.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Graph.java deleted file mode 100644 index eaf8c0c..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Graph.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.dunwu.algorithm.graph; - -import java.util.List; - -public interface Graph { - - // 添加一条边(带权重) - void addEdge(int from, int to, int weight); - - // 删除一条边 - void removeEdge(int from, int to); - - // 判断两个节点是否相邻 - boolean hasEdge(int from, int to); - - // 返回一条边的权重 - int weight(int from, int to); - - // 返回某个节点的所有邻居节点和对应权重 - List neighbors(int v); - - // 返回节点总数 - int size(); - -} \ No newline at end of file diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/State.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/State.java deleted file mode 100644 index 3b78a8f..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/State.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.github.dunwu.algorithm.graph; - -// 图结构的 BFS 遍历,从节点 s 开始进行 BFS,且记录遍历步数(从起点 s 到当前节点的边的条数) -// 每个节点自行维护 State 类,记录从 s 走来的遍历步数 -public class State { - - // 当前节点 ID - public int node; - // 从起点 s 到当前节点的遍历步数 - public int step; - - public State(int node, int step) { - this.node = node; - this.step = step; - } - -} \ No newline at end of file diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Vertex.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Vertex.java deleted file mode 100644 index 46dec8a..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/Vertex.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.dunwu.algorithm.graph; - -/** - * 图节点 - */ -public class Vertex { - - public int id; - public Vertex[] neighbors; - -} \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" deleted file mode 100644 index a78231e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\210\244\346\226\255\344\272\214\345\210\206\345\233\276.java" +++ /dev/null @@ -1,139 +0,0 @@ -package io.github.dunwu.algorithm.graph.bipartite; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.Queue; - -/** - * 785. 判断二分图 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 判断二分图 { - - public static void main(String[] args) { - - int[][] input = new int[][] { { 1, 2, 3 }, { 0, 2 }, { 0, 1, 3 }, { 0, 2 } }; - int[][] input2 = new int[][] { { 1, 3 }, { 0, 2 }, { 1, 3 }, { 0, 2 } }; - - Solution s = new Solution(); - Assertions.assertFalse(s.isBipartite(input)); - Assertions.assertFalse(s.isBipartite(input2)); - - Solution2 s2 = new Solution2(); - Assertions.assertFalse(s2.isBipartite(input)); - Assertions.assertFalse(s2.isBipartite(input2)); - } - - // 二分图算法(DFS 版本) - static class Solution { - - // 记录图是否符合二分图性质 - private boolean ok = true; - // 记录图中节点的颜色,false 和 true 代表两种不同颜色 - private boolean[] color; - // 记录图中节点是否被访问过 - private boolean[] visited; - - // 主函数,输入邻接表,判断是否是二分图 - public boolean isBipartite(int[][] graph) { - int n = graph.length; - color = new boolean[n]; - visited = new boolean[n]; - // 因为图不一定是联通的,可能存在多个子图 - // 所以要把每个节点都作为起点进行一次遍历 - // 如果发现任何一个子图不是二分图,整幅图都不算二分图 - for (int v = 0; v < n; v++) { - if (!visited[v]) { - dfs(graph, v); - } - } - return ok; - } - - // DFS 遍历框架 - private void dfs(int[][] graph, int v) { - // 如果已经确定不是二分图了,就不用浪费时间再递归遍历了 - if (!ok) return; - - visited[v] = true; - for (int w : graph[v]) { - if (!visited[w]) { - // 相邻节点 w 没有被访问过 - // 那么应该给节点 w 涂上和节点 v 不同的颜色 - color[w] = !color[v]; - // 继续遍历 w - dfs(graph, w); - } else { - // 相邻节点 w 已经被访问过 - // 根据 v 和 w 的颜色判断是否是二分图 - if (color[w] == color[v]) { - // 若相同,则此图不是二分图 - ok = false; - } - } - } - } - - } - - // 二分图算法(BFS 版本) - static class Solution2 { - - // 记录图是否符合二分图性质 - private boolean ok = true; - // 记录图中节点的颜色,false 和 true 代表两种不同颜色 - private boolean[] color; - // 记录图中节点是否被访问过 - private boolean[] visited; - - public boolean isBipartite(int[][] graph) { - int n = graph.length; - color = new boolean[n]; - visited = new boolean[n]; - - for (int v = 0; v < n; v++) { - if (!visited[v]) { - // 改为使用 BFS 函数 - bfs(graph, v); - } - } - - return ok; - } - - // 从 start 节点开始进行 BFS 遍历 - private void bfs(int[][] graph, int start) { - Queue q = new LinkedList<>(); - visited[start] = true; - q.offer(start); - - while (!q.isEmpty() && ok) { - int v = q.poll(); - // 从节点 v 向所有相邻节点扩散 - for (int w : graph[v]) { - if (!visited[w]) { - // 相邻节点 w 没有被访问过 - // 那么应该给节点 w 涂上和节点 v 不同的颜色 - color[w] = !color[v]; - // 标记 w 节点,并放入队列 - visited[w] = true; - q.offer(w); - } else { - // 相邻节点 w 已经被访问过 - // 根据 v 和 w 的颜色判断是否是二分图 - if (color[w] == color[v]) { - // 若相同,则此图不是二分图 - ok = false; - return; - } - } - } - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" deleted file mode 100644 index 1dc1d9b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/bipartite/\345\217\257\350\203\275\347\232\204\344\272\214\345\210\206\346\263\225.java" +++ /dev/null @@ -1,86 +0,0 @@ -package io.github.dunwu.algorithm.graph.bipartite; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 886. 可能的二分法 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 可能的二分法 { - - public static void main(String[] args) { - - int[][] input = new int[][] { { 1, 2 }, { 1, 3 }, { 2, 4 } }; - int[][] input2 = new int[][] { { 1, 2 }, { 1, 3 }, { 2, 3 } }; - int[][] input3 = new int[][] { { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 5 }, { 1, 5 } }; - - Solution s = new Solution(); - Assertions.assertTrue(s.possibleBipartition(4, input)); - Assertions.assertFalse(s.possibleBipartition(3, input2)); - Assertions.assertFalse(s.possibleBipartition(5, input3)); - } - - static class Solution { - - private boolean ok = true; - private boolean[] color; - private boolean[] visited; - - public boolean possibleBipartition(int n, int[][] dislikes) { - // 图节点编号从 1 开始 - color = new boolean[n + 1]; - visited = new boolean[n + 1]; - // 转化成邻接表表示图结构 - List[] graph = buildGraph(n, dislikes); - - for (int v = 1; v <= n; v++) { - if (!visited[v]) { - dfs(graph, v); - } - } - return ok; - } - - // 建图函数 - private List[] buildGraph(int n, int[][] dislikes) { - // 图节点编号为 1...n - List[] graph = new LinkedList[n + 1]; - for (int i = 1; i <= n; i++) { - graph[i] = new LinkedList<>(); - } - for (int[] edge : dislikes) { - int v = edge[1]; - int w = edge[0]; - // 「无向图」相当于「双向图」 - // v -> w - graph[v].add(w); - // w -> v - graph[w].add(v); - } - return graph; - } - - // 和之前判定二分图的 traverse 函数完全相同 - private void dfs(List[] graph, int v) { - if (!ok) return; - visited[v] = true; - for (int w : graph[v]) { - if (!visited[w]) { - color[w] = !color[v]; - dfs(graph, w); - } else { - if (color[w] == color[v]) { - ok = false; - } - } - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" deleted file mode 100644 index b111b38..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/dfs/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\350\267\257\345\276\204.java" +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.dunwu.algorithm.graph.dfs; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 797. 所有可能的路径 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 所有可能的路径 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] input = new int[][] { - { 1, 2 }, { 3 }, { 3 }, {} - }; - List> expect = new LinkedList<>(); - expect.add(Arrays.asList(0, 1, 3)); - expect.add(Arrays.asList(0, 2, 3)); - List> output = s.allPathsSourceTarget(input); - for (int i = 0; i < expect.size(); i++) { - Assertions.assertArrayEquals(expect.get(i).toArray(), output.get(i).toArray()); - } - // System.out.println("v = " + output); - } - - static class Solution { - - private List path; - private List> res; - - public List> allPathsSourceTarget(int[][] graph) { - path = new LinkedList<>(); - res = new LinkedList<>(); - dfs(graph, 0); - return res; - } - - // 图的遍历框架 - void dfs(int[][] graph, int s) { - - // 添加节点 s 到路径 - path.add(s); - - int n = graph.length; - if (s == n - 1) { - // 到达终点 - res.add(new LinkedList<>(path)); - path.remove(path.size() - 1); - return; - } - - // 递归每个相邻节点 - for (int v : graph[s]) { - dfs(graph, v); - } - - // 从路径移出节点 s - path.remove(path.size() - 1); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/BFS\351\201\215\345\216\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/BFS\351\201\215\345\216\206\345\233\276.java" deleted file mode 100644 index 74141ec..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/BFS\351\201\215\345\216\206\345\233\276.java" +++ /dev/null @@ -1,87 +0,0 @@ -package io.github.dunwu.algorithm.graph.template; - -import io.github.dunwu.algorithm.graph.Edge; -import io.github.dunwu.algorithm.graph.Graph; -import io.github.dunwu.algorithm.graph.State; - -import java.util.LinkedList; -import java.util.Queue; - -/** - * 图的遍历框架 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class BFS遍历图 { - - // 图结构的 BFS 遍历,从节点 s 开始进行 BFS - void bfs(Graph graph, int s) { - boolean[] visited = new boolean[graph.size()]; - Queue q = new LinkedList<>(); - q.offer(s); - visited[s] = true; - - while (!q.isEmpty()) { - int cur = q.poll(); - System.out.println("visit " + cur); - for (Edge e : graph.neighbors(cur)) { - if (visited[e.to]) { - continue; - } - q.offer(e.to); - visited[e.to] = true; - } - } - } - - // 从 s 开始 BFS 遍历图的所有节点,且记录遍历的步数 - void bfs2(Graph graph, int s) { - boolean[] visited = new boolean[graph.size()]; - Queue q = new LinkedList<>(); - q.offer(s); - visited[s] = true; - // 记录从 s 开始走到当前节点的步数 - int step = 0; - while (!q.isEmpty()) { - int sz = q.size(); - for (int i = 0; i < sz; i++) { - int cur = q.poll(); - System.out.println("visit " + cur + " at step " + step); - for (Edge e : graph.neighbors(cur)) { - if (visited[e.to]) { - continue; - } - q.offer(e.to); - visited[e.to] = true; - } - } - step++; - } - } - - // 图结构的 BFS 遍历,从节点 s 开始进行 BFS,且记录遍历步数(从起点 s 到当前节点的边的条数) - // 每个节点自行维护 State 类,记录从 s 走来的遍历步数 - void bfs3(Graph graph, int s) { - boolean[] visited = new boolean[graph.size()]; - Queue q = new LinkedList<>(); - - q.offer(new State(s, 0)); - visited[s] = true; - - while (!q.isEmpty()) { - State state = q.poll(); - int node = state.node; - int step = state.step; - System.out.println("visit " + node + " with step " + step); - for (Edge e : graph.neighbors(node)) { - if (visited[e.to]) { - continue; - } - q.offer(new State(e.to, step + 1)); - visited[e.to] = true; - } - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" deleted file mode 100644 index 86b8925..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\212\202\347\202\271.java" +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.dunwu.algorithm.graph.template; - -import io.github.dunwu.algorithm.graph.Edge; -import io.github.dunwu.algorithm.graph.Graph; -import io.github.dunwu.algorithm.graph.Vertex; - -/** - * 图的遍历框架 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class DFS遍历图的所有节点 { - - // 遍历图的所有节点 - void traverse(Graph graph, int s, boolean[] visited) { - // base case - if (s < 0 || s >= graph.size()) { return; } - // 防止死循环 - if (visited[s]) { return; } - // 前序位置 - visited[s] = true; - System.out.println("visit " + s); - for (Edge e : graph.neighbors(s)) { - traverse(graph, e.to, visited); - } - // 后序位置 - } - - // 图的遍历框架 - // 需要一个 visited 数组记录被遍历过的节点 - // 避免走回头路陷入死循环 - void traverse(Vertex v, boolean[] visited) { - // base case - if (v == null) { return; } - // 防止死循环 - if (visited[v.id]) { return; } - // 前序位置 - visited[v.id] = true; - System.out.println("visit " + v.id); - for (Vertex neighbor : v.neighbors) { - traverse(neighbor, visited); - } - // 后序位置 - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" deleted file mode 100644 index 0a53f86..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.graph.template; - -import io.github.dunwu.algorithm.graph.Edge; -import io.github.dunwu.algorithm.graph.Graph; -import io.github.dunwu.algorithm.tree.Node; - -import java.util.LinkedList; - -/** - * DFS遍历图的所有路径 - * - * @author Zhang Peng - * @date 2025-12-02 - */ -public class DFS遍历图的所有路径 { - - // onPath 和 path 记录当前递归路径上的节点 - boolean[] onPath = null; - // 多叉树的遍历框架,寻找从根节点到目标节点的路径 - LinkedList path = new LinkedList<>(); - - void traverse(Node root, Node targetNode) { - // base case - if (root == null) { - return; - } - if (root.val == targetNode.val) { - // 找到目标节点 - System.out.println("find path: " + String.join("->", path) + "->" + targetNode); - return; - } - // 前序位置 - path.addLast(String.valueOf(root.val)); - for (Node child : root.children) { - traverse(child, targetNode); - } - // 后序位置 - path.removeLast(); - } - - void traverse(Graph graph, int from, int to) { - if (onPath == null) { onPath = new boolean[graph.size()]; } - // base case - if (from < 0 || from >= graph.size()) { return; } - // 防止死循环(成环) - if (onPath[from]) { return; } - if (from == to) { - // 找到目标节点 - System.out.println("find path: " + String.join("->", path) + "->" + to); - return; - } - - // 前序位置 - onPath[from] = true; - path.add(String.valueOf(from)); - for (Edge e : graph.neighbors(from)) { - traverse(graph, e.to, to); - } - // 后序位置 - path.remove(path.size() - 1); - onPath[from] = false; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" deleted file mode 100644 index 8081142..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/DFS\351\201\215\345\216\206\345\233\276\347\232\204\346\211\200\346\234\211\350\276\271.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.graph.template; - -import io.github.dunwu.algorithm.graph.Edge; -import io.github.dunwu.algorithm.graph.Graph; -import io.github.dunwu.algorithm.graph.Vertex; -import io.github.dunwu.algorithm.tree.Node; - -/** - * DFS遍历图的所有边 - * - * @author Zhang Peng - * @date 2025-11-06 - */ -public class DFS遍历图的所有边 { - - // 遍历多叉树的树枝 - void traverseBranch(Node root) { - // base case - if (root == null) { return; } - for (Node child : root.children) { - System.out.println("visit branch: " + root.val + " -> " + child.val); - traverseBranch(child); - } - } - - // 遍历图的边 - // 需要一个二维 visited 数组记录被遍历过的边,visited[from][to] 表示边 from->to 已经被遍历过 - void traverseEdges(Vertex v, boolean[][] visited) { - // base case - if (v == null) { return; } - for (Vertex neighbor : v.neighbors) { - // 如果边已经被遍历过,则跳过 - if (visited[v.id][neighbor.id]) { continue; } - // 标记并访问边 - visited[v.id][neighbor.id] = true; - System.out.println("visit edge: " + v.id + " -> " + neighbor.id); - traverseEdges(neighbor, visited); - } - } - - // 从起点 s 开始遍历图的所有边 - void traverseEdges(Graph graph, int s, boolean[][] visited) { - // base case - if (s < 0 || s >= graph.size()) { return; } - for (Edge e : graph.neighbors(s)) { - // 如果边已经被遍历过,则跳过 - if (visited[s][e.to]) { continue; } - // 标记并访问边 - visited[s][e.to] = true; - System.out.println("visit edge: " + s + " -> " + e.to); - traverseEdges(graph, e.to, visited); - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/Dijkstra.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/Dijkstra.java deleted file mode 100644 index 518770b..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/Dijkstra.java +++ /dev/null @@ -1,78 +0,0 @@ -package io.github.dunwu.algorithm.graph.template; - -import io.github.dunwu.algorithm.graph.Edge; -import io.github.dunwu.algorithm.graph.Graph; - -import java.util.Arrays; -import java.util.PriorityQueue; - -/** - * Dijkstra 算法模板 - * - * @author Zhang Peng - * @date 2025-12-03 - */ -public class Dijkstra { - - // 输入不包含负权重边的加权图 graph 和起点 src - // 返回从起点 src 到其他节点的最小路径权重和 - public int[] dijkstra(Graph graph, int src) { - // 记录从起点 src 到其他节点的最小路径权重和 - // distTo[i] 表示从起点 src 到节点 i 的最小路径权重和 - int[] distTo = new int[graph.size()]; - // 都初始化为正无穷,表示未计算 - Arrays.fill(distTo, Integer.MAX_VALUE); - - // 优先级队列,distFromStart 较小的节点排在前面 - PriorityQueue pq = new PriorityQueue<>((a, b) -> { - return a.distFromStart - b.distFromStart; - }); - - // 从起点 src 开始进行 BFS - pq.offer(new State(src, 0)); - distTo[src] = 0; - - while (!pq.isEmpty()) { - State state = pq.poll(); - int curNode = state.node; - int curDistFromStart = state.distFromStart; - - if (distTo[curNode] < curDistFromStart) { - // 在 Dijkstra 算法中,队列中可能存在重复的节点 state - // 所以要在元素出队时进行判断,去除较差的重复节点 - continue; - } - - for (Edge e : graph.neighbors(curNode)) { - int nextNode = e.to; - int nextDistFromStart = curDistFromStart + e.weight; - - if (distTo[nextNode] <= nextDistFromStart) { - continue; - } - - // 将 nextNode 节点加入优先级队列 - pq.offer(new State(nextNode, nextDistFromStart)); - // 记录 nextNode 节点到起点的最小路径权重和 - distTo[nextNode] = nextDistFromStart; - } - } - - return distTo; - } - - static class State { - - // 当前节点 ID - int node; - // 从起点 s 到当前 node 节点的最小路径权重和 - int distFromStart; - - public State(int node, int distFromStart) { - this.node = node; - this.distFromStart = distFromStart; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\271\266\346\237\245\351\233\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\271\266\346\237\245\351\233\206.java" deleted file mode 100644 index bc15937..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\345\271\266\346\237\245\351\233\206.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.graph.template; - -/** - * 并查集 - * - * @author Zhang Peng - * @date 2025-12-03 - */ -public class 并查集 { - - static class UF { - - // 连通分量个数 - private int count; - // 存储每个节点的父节点 - private int[] parent; - - // n 为图中节点的个数 - public UF(int n) { - this.count = n; - parent = new int[n]; - for (int i = 0; i < n; i++) { - parent[i] = i; - } - } - - // 将节点 p 和节点 q 连通 - public void union(int p, int q) { - int rootP = find(p); - int rootQ = find(q); - - if (rootP == rootQ) { return; } - - parent[rootQ] = rootP; - // 两个连通分量合并成一个连通分量 - count--; - } - - // 判断节点 p 和节点 q 是否连通 - public boolean connected(int p, int q) { - int rootP = find(p); - int rootQ = find(q); - return rootP == rootQ; - } - - public int find(int x) { - if (parent[x] != x) { - parent[x] = find(parent[x]); - } - return parent[x]; - } - - // 返回图中的连通分量个数 - public int count() { - return count; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" deleted file mode 100644 index 140b44c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\347\237\251\351\230\265\345\256\236\347\216\260\345\233\276.java" +++ /dev/null @@ -1,138 +0,0 @@ -package io.github.dunwu.algorithm.graph.template; - -import io.github.dunwu.algorithm.graph.Edge; - -import java.util.ArrayList; -import java.util.List; - -/** - * 邻接矩阵实现图 - * - * @author Zhang Peng - * @date 2025-11-06 - */ -public class 邻接矩阵实现图 { - - // 加权有向图的通用实现(邻接矩阵) - static class WeightedDigraph { - - // 邻接矩阵,matrix[from][to] 存储从节点 from 到节点 to 的边的权重 - // 0 表示没有连接 - private int[][] matrix; - - public WeightedDigraph(int n) { - matrix = new int[n][n]; - } - - // 增,添加一条带权重的有向边,复杂度 O(1) - public void addEdge(int from, int to, int weight) { - matrix[from][to] = weight; - } - - // 删,删除一条有向边,复杂度 O(1) - public void removeEdge(int from, int to) { - matrix[from][to] = 0; - } - - // 查,判断两个节点是否相邻,复杂度 O(1) - public boolean hasEdge(int from, int to) { - return matrix[from][to] != 0; - } - - // 查,返回一条边的权重,复杂度 O(1) - public int weight(int from, int to) { - return matrix[from][to]; - } - - // 查,返回某个节点的所有邻居节点,复杂度 O(V) - public List neighbors(int v) { - List res = new ArrayList<>(); - for (int i = 0; i < matrix[v].length; i++) { - if (matrix[v][i] != 0) { - res.add(new Edge(i, matrix[v][i])); - } - } - return res; - } - - public static void main(String[] args) { - WeightedDigraph graph = new WeightedDigraph(3); - graph.addEdge(0, 1, 1); - graph.addEdge(1, 2, 2); - graph.addEdge(2, 0, 3); - graph.addEdge(2, 1, 4); - - System.out.println(graph.hasEdge(0, 1)); // true - System.out.println(graph.hasEdge(1, 0)); // false - - graph.neighbors(2).forEach(edge -> { - System.out.println(2 + " -> " + edge.to + ", wight: " + edge.weight); - }); - // 2 -> 0, wight: 3 - // 2 -> 1, wight: 4 - - graph.removeEdge(0, 1); - System.out.println(graph.hasEdge(0, 1)); // false - } - - } - - // 无向加权图的通用实现 - static class WeightedUndigraph { - - private WeightedDigraph graph; - - public WeightedUndigraph(int n) { - graph = new WeightedDigraph(n); - } - - // 增,添加一条带权重的无向边 - public void addEdge(int from, int to, int weight) { - graph.addEdge(from, to, weight); - graph.addEdge(to, from, weight); - } - - // 删,删除一条无向边 - public void removeEdge(int from, int to) { - graph.removeEdge(from, to); - graph.removeEdge(to, from); - } - - // 查,判断两个节点是否相邻 - public boolean hasEdge(int from, int to) { - return graph.hasEdge(from, to); - } - - // 查,返回一条边的权重 - public int weight(int from, int to) { - return graph.weight(from, to); - } - - // 查,返回某个节点的所有邻居节点 - public List neighbors(int v) { - return graph.neighbors(v); - } - - public static void main(String[] args) { - WeightedUndigraph graph = new WeightedUndigraph(3); - graph.addEdge(0, 1, 1); - graph.addEdge(2, 0, 3); - graph.addEdge(2, 1, 4); - - System.out.println(graph.hasEdge(0, 1)); // true - System.out.println(graph.hasEdge(1, 0)); // true - - graph.neighbors(2).forEach(edge -> { - System.out.println(2 + " <-> " + edge.to + ", wight: " + edge.weight); - }); - // 2 <-> 0, wight: 3 - // 2 <-> 1, wight: 4 - - graph.removeEdge(0, 1); - System.out.println(graph.hasEdge(0, 1)); // false - System.out.println(graph.hasEdge(1, 0)); // false - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\350\241\250\345\256\236\347\216\260\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\350\241\250\345\256\236\347\216\260\345\233\276.java" deleted file mode 100644 index 2372c4c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/template/\351\202\273\346\216\245\350\241\250\345\256\236\347\216\260\345\233\276.java" +++ /dev/null @@ -1,159 +0,0 @@ -package io.github.dunwu.algorithm.graph.template; - -import io.github.dunwu.algorithm.graph.Edge; - -import java.util.ArrayList; -import java.util.List; - -/** - * 邻接表实现图 - * - * @author Zhang Peng - * @date 2025-11-06 - */ -public class 邻接表实现图 { - - /** - * 加权有向图的通用实现(邻接表) - */ - static class WeightedDigraph { - - // 邻接表,graph[v] 存储节点 v 的所有邻居节点及对应权重 - private List[] graph; - - public WeightedDigraph(int n) { - // 我们这里简单起见,建图时要传入节点总数,这其实可以优化 - // 比如把 graph 设置为 Map>,就可以动态添加新节点了 - graph = new List[n]; - for (int i = 0; i < n; i++) { - graph[i] = new ArrayList<>(); - } - } - - // 增,添加一条带权重的有向边,复杂度 O(1) - public void addEdge(int from, int to, int weight) { - graph[from].add(new Edge(to, weight)); - } - - // 删,删除一条有向边,复杂度 O(V) - public void removeEdge(int from, int to) { - for (int i = 0; i < graph[from].size(); i++) { - if (graph[from].get(i).to == to) { - graph[from].remove(i); - break; - } - } - } - - // 查,判断两个节点是否相邻,复杂度 O(V) - public boolean hasEdge(int from, int to) { - for (Edge e : graph[from]) { - if (e.to == to) { - return true; - } - } - return false; - } - - // 查,返回一条边的权重,复杂度 O(V) - public int weight(int from, int to) { - for (Edge e : graph[from]) { - if (e.to == to) { - return e.weight; - } - } - throw new IllegalArgumentException("No such edge"); - } - - // 上面的 hasEdge、removeEdge、weight 方法遍历 List 的行为是可以优化的 - // 比如用 Map> 存储邻接表 - // 这样就可以避免遍历 List,复杂度就能降到 O(1) - - // 查,返回某个节点的所有邻居节点,复杂度 O(1) - public List neighbors(int v) { - return graph[v]; - } - - public static void main(String[] args) { - WeightedDigraph graph = new WeightedDigraph(3); - graph.addEdge(0, 1, 1); - graph.addEdge(1, 2, 2); - graph.addEdge(2, 0, 3); - graph.addEdge(2, 1, 4); - - System.out.println(graph.hasEdge(0, 1)); // true - System.out.println(graph.hasEdge(1, 0)); // false - - graph.neighbors(2).forEach(edge -> { - System.out.println(2 + " -> " + edge.to + ", wight: " + edge.weight); - }); - // 2 -> 0, wight: 3 - // 2 -> 1, wight: 4 - - graph.removeEdge(0, 1); - System.out.println(graph.hasEdge(0, 1)); // false - } - - } - - /** - * 无向加权图的通用实现 - */ - static class WeightedUndigraph { - - private WeightedDigraph graph; - - public WeightedUndigraph(int n) { - graph = new WeightedDigraph(n); - } - - // 增,添加一条带权重的无向边 - public void addEdge(int from, int to, int weight) { - graph.addEdge(from, to, weight); - graph.addEdge(to, from, weight); - } - - // 删,删除一条无向边 - public void removeEdge(int from, int to) { - graph.removeEdge(from, to); - graph.removeEdge(to, from); - } - - // 查,判断两个节点是否相邻 - public boolean hasEdge(int from, int to) { - return graph.hasEdge(from, to); - } - - // 查,返回一条边的权重 - public int weight(int from, int to) { - return graph.weight(from, to); - } - - // 查,返回某个节点的所有邻居节点 - public List neighbors(int v) { - return graph.neighbors(v); - } - - public static void main(String[] args) { - WeightedUndigraph graph = new WeightedUndigraph(3); - graph.addEdge(0, 1, 1); - graph.addEdge(2, 0, 3); - graph.addEdge(2, 1, 4); - - System.out.println(graph.hasEdge(0, 1)); // true - System.out.println(graph.hasEdge(1, 0)); // true - - graph.neighbors(2).forEach(edge -> { - System.out.println(2 + " <-> " + edge.to + ", wight: " + edge.weight); - }); - // 2 <-> 0, wight: 3 - // 2 <-> 1, wight: 4 - - graph.removeEdge(0, 1); - System.out.println(graph.hasEdge(0, 1)); // false - System.out.println(graph.hasEdge(1, 0)); // false - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" deleted file mode 100644 index 62c8c0d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\250.java" +++ /dev/null @@ -1,139 +0,0 @@ -package io.github.dunwu.algorithm.graph.topological_sort; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; - -/** - * 207. 课程表 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 课程表 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.canFinish(2, new int[][] { { 1, 0 } })); - Assertions.assertFalse(s.canFinish(2, new int[][] { { 1, 0 }, { 0, 1 } })); - - Solution2 s2 = new Solution2(); - Assertions.assertTrue(s2.canFinish(2, new int[][] { { 1, 0 } })); - Assertions.assertFalse(s2.canFinish(2, new int[][] { { 1, 0 }, { 0, 1 } })); - } - - // 环检测算法(DFS 版本) - static class Solution { - - // 记录一次递归堆栈中的节点 - boolean[] onPath; - // 记录节点是否被遍历过 - boolean[] visited; - // 记录图中是否有环 - boolean hasCycle = false; - - public boolean canFinish(int numCourses, int[][] prerequisites) { - List[] graph = buildGraph(numCourses, prerequisites); - visited = new boolean[numCourses]; - onPath = new boolean[numCourses]; - - // 遍历图中的所有节点 - for (int i = 0; i < numCourses; i++) { - dfs(graph, i); - } - // 只要没有循环依赖可以完成所有课程 - return !hasCycle; - } - - public void dfs(List[] graph, int s) { - // 找到环,或已访问,则无需再遍历 - if (onPath[s]) { hasCycle = true; } - if (hasCycle || visited[s]) { return; } - - // 【前序】 - visited[s] = true; - onPath[s] = true; - for (int t : graph[s]) { - dfs(graph, t); - } - // 【后序】 - onPath[s] = false; - } - - public List[] buildGraph(int n, int[][] data) { - List[] graph = new LinkedList[n]; - for (int i = 0; i < n; i++) { - graph[i] = new LinkedList<>(); - } - - for (int[] edge : data) { - int from = edge[1], to = edge[0]; - graph[from].add(to); - } - return graph; - } - - } - - // 环检测算法(BFS 版本) - static class Solution2 { - - public boolean canFinish(int numCourses, int[][] prerequisites) { - // 建图,有向边代表「被依赖」关系 - List[] graph = buildGraph(numCourses, prerequisites); - // 构建入度数组 - int[] indegree = new int[numCourses]; - for (int[] edge : prerequisites) { - int from = edge[1], to = edge[0]; - // 节点 to 的入度加一 - indegree[to]++; - } - - // 根据入度初始化队列中节点 - Queue q = new LinkedList<>(); - for (int i = 0; i < numCourses; i++) { - if (indegree[i] == 0) { - // 节点 i 没有入度,即没有依赖的节点 - // 可以作为拓扑排序的起点,加入队列 - q.offer(i); - } - } - - // 记录遍历的节点个数 - int count = 0; - // 开始执行 BFS 遍历 - while (!q.isEmpty()) { - // 弹出节点 cur,并将它指向的节点的入度减一 - int cur = q.poll(); - count++; - for (int next : graph[cur]) { - indegree[next]--; - if (indegree[next] == 0) { - // 如果入度变为 0,说明 next 依赖的节点都已被遍历 - q.offer(next); - } - } - } - - // 如果所有节点都被遍历过,说明不成环 - return count == numCourses; - } - - public List[] buildGraph(int n, int[][] data) { - List[] graph = new LinkedList[n]; - for (int i = 0; i < n; i++) { - graph[i] = new LinkedList<>(); - } - - for (int[] edge : data) { - int from = edge[1], to = edge[0]; - graph[from].add(to); - } - return graph; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" deleted file mode 100644 index 998b686..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/topological_sort/\350\257\276\347\250\213\350\241\2502.java" +++ /dev/null @@ -1,156 +0,0 @@ -package io.github.dunwu.algorithm.graph.topological_sort; - -import org.junit.jupiter.api.Assertions; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; - -/** - * 210. 课程表 II - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 课程表2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 0, 1 }, s.findOrder(2, new int[][] { { 1, 0 } })); - Assertions.assertArrayEquals(new int[] { 0, 2, 1, 3 }, - s.findOrder(4, new int[][] { { 1, 0 }, { 2, 0 }, { 3, 1 }, { 3, 2 } })); - - Solution2 s2 = new Solution2(); - Assertions.assertArrayEquals(new int[] { 0, 1 }, s2.findOrder(2, new int[][] { { 1, 0 } })); - Assertions.assertArrayEquals(new int[] { 0, 2, 1, 3 }, - s2.findOrder(4, new int[][] { { 1, 0 }, { 2, 0 }, { 3, 1 }, { 3, 2 } })); - } - - // 拓扑排序算法(DFS 版本) - static class Solution { - - // 记录后序遍历结果 - private List preorder; - // 记录一次递归堆栈中的节点 - boolean[] onPath; - // 记录节点是否被遍历过 - boolean[] visited; - // 记录图中是否有环 - boolean hasCycle = false; - - public int[] findOrder(int numCourses, int[][] prerequisites) { - List[] graph = buildGraph(numCourses, prerequisites); - preorder = new LinkedList<>(); - visited = new boolean[numCourses]; - onPath = new boolean[numCourses]; - - for (int i = 0; i < numCourses; i++) { - dfs(graph, i); - } - - // 有环图无法进行拓扑排序 - if (hasCycle) { return new int[0]; } - - // 逆后序遍历结果即为拓扑排序结果 - Collections.reverse(preorder); - int[] order = new int[numCourses]; - for (int i = 0; i < numCourses; i++) { - order[i] = preorder.get(i); - } - return order; - } - - public void dfs(List[] graph, int s) { - // 找到环,或已访问,则无需再遍历 - if (onPath[s]) { hasCycle = true; } - if (hasCycle || visited[s]) { return; } - - // 【前序】 - visited[s] = true; - onPath[s] = true; - for (int t : graph[s]) { - dfs(graph, t); - } - // 【后序】 - preorder.add(s); - onPath[s] = false; - } - - public List[] buildGraph(int n, int[][] data) { - List[] graph = new LinkedList[n]; - for (int i = 0; i < n; i++) { - graph[i] = new LinkedList<>(); - } - - for (int[] edge : data) { - int from = edge[1], to = edge[0]; - graph[from].add(to); - } - return graph; - } - - } - - // 拓扑排序算法(BFS 版本) - static class Solution2 { - - public int[] findOrder(int numCourses, int[][] prerequisites) { - // 建图,和环检测算法相同 - List[] graph = buildGraph(numCourses, prerequisites); - // 计算入度,和环检测算法相同 - int[] indegree = new int[numCourses]; - for (int[] edge : prerequisites) { - int from = edge[1], to = edge[0]; - indegree[to]++; - } - - // 根据入度初始化队列中的节点,和环检测算法相同 - Queue q = new LinkedList<>(); - for (int i = 0; i < numCourses; i++) { - if (indegree[i] == 0) { - q.offer(i); - } - } - - // 记录拓扑排序结果 - int[] res = new int[numCourses]; - // 记录遍历节点的顺序(索引) - int count = 0; - // 开始执行 BFS 算法 - while (!q.isEmpty()) { - int cur = q.poll(); - // 弹出节点的顺序即为拓扑排序结果 - res[count] = cur; - count++; - for (int next : graph[cur]) { - indegree[next]--; - if (indegree[next] == 0) { - q.offer(next); - } - } - } - - // 存在环,拓扑排序不存在 - if (count != numCourses) { - return new int[0]; - } - return res; - } - - public List[] buildGraph(int n, int[][] data) { - List[] graph = new LinkedList[n]; - for (int i = 0; i < n; i++) { - graph[i] = new LinkedList<>(); - } - - for (int[] edge : data) { - int from = edge[1], to = edge[0]; - graph[from].add(to); - } - return graph; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" deleted file mode 100644 index 8619903..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\345\206\227\344\275\231\350\277\236\346\216\245.java" +++ /dev/null @@ -1,82 +0,0 @@ -package io.github.dunwu.algorithm.graph.union_find; - -import org.junit.jupiter.api.Assertions; - -/** - * 684. 冗余连接 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 冗余连接 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[][] input = new int[][] { { 1, 2 }, { 1, 3 }, { 2, 3 } }; - int[][] input2 = new int[][] { { 1, 2 }, { 2, 3 }, { 3, 4 }, { 1, 4 }, { 1, 5 } }; - Assertions.assertArrayEquals(new int[] { 2, 3 }, s.findRedundantConnection(input)); - Assertions.assertArrayEquals(new int[] { 1, 4 }, s.findRedundantConnection(input2)); - } - - static class Solution { - - public int[] findRedundantConnection(int[][] edges) { - UF uf = new UF(edges.length + 1); - for (int[] edge : edges) { - int p = edge[0], q = edge[1]; - if (uf.connected(p, q)) { - return new int[] { p, q }; - } else { - uf.union(p, q); - } - } - return new int[0]; - } - - static class UF { - - // 连通分量个数 - private int count; - // 存储每个节点的父节点 - private int[] parent; - - public UF(int n) { - this.count = n; - parent = new int[n]; - for (int i = 0; i < n; i++) { - parent[i] = i; - } - } - - public void union(int p, int q) { - int rootP = find(p); - int rootQ = find(q); - - if (rootP == rootQ) { return; } - - parent[rootQ] = rootP; - count--; - } - - public boolean connected(int p, int q) { - int rootP = find(p); - int rootQ = find(q); - return rootP == rootQ; - } - - public int find(int x) { - if (parent[x] != x) { - parent[x] = find(parent[x]); - } - return parent[x]; - } - - public int count() { - return count; - } - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\347\255\211\345\274\217\346\226\271\347\250\213\347\232\204\345\217\257\346\273\241\350\266\263\346\200\247.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\347\255\211\345\274\217\346\226\271\347\250\213\347\232\204\345\217\257\346\273\241\350\266\263\346\200\247.java" deleted file mode 100644 index c78af57..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\347\255\211\345\274\217\346\226\271\347\250\213\347\232\204\345\217\257\346\273\241\350\266\263\346\200\247.java" +++ /dev/null @@ -1,94 +0,0 @@ -package io.github.dunwu.algorithm.graph.union_find; - -import org.junit.jupiter.api.Assertions; - -/** - * 990. 等式方程的可满足性 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 等式方程的可满足性 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertFalse(s.equationsPossible(new String[] { "a==b", "b!=a" })); - Assertions.assertTrue(s.equationsPossible(new String[] { "b==a", "a==b" })); - Assertions.assertTrue(s.equationsPossible(new String[] { "a==b", "b==c", "a==c" })); - Assertions.assertFalse(s.equationsPossible(new String[] { "a==b", "b!=c", "c==a" })); - Assertions.assertTrue(s.equationsPossible(new String[] { "c==c", "b==d", "x!=z" })); - } - - static class Solution { - - public boolean equationsPossible(String[] equations) { - UF uf = new UF(26); - for (String exp : equations) { - if (exp.contains("==")) { - String[] vals = exp.split("=="); - int a = vals[0].charAt(0) - 'a'; - int b = vals[1].charAt(0) - 'a'; - uf.union(a, b); - } - } - - for (String exp : equations) { - if (exp.contains("!=")) { - String[] vals = exp.split("!="); - int a = vals[0].charAt(0) - 'a'; - int b = vals[1].charAt(0) - 'a'; - if (uf.connected(a, b)) { - return false; - } - } - } - return true; - } - - static class UF { - - // 连通分量个数 - private int count; - // 存储每个节点的父节点 - private int[] parent; - - public UF(int n) { - this.count = n; - parent = new int[n]; - for (int i = 0; i < n; i++) { - parent[i] = i; - } - } - - public void union(int p, int q) { - int rootP = find(p); - int rootQ = find(q); - - if (rootP == rootQ) { return; } - - parent[rootQ] = rootP; - count--; - } - - public boolean connected(int p, int q) { - int rootP = find(p); - int rootQ = find(q); - return rootP == rootQ; - } - - public int find(int x) { - if (parent[x] != x) { - parent[x] = find(parent[x]); - } - return parent[x]; - } - - public int count() { - return count; - } - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" deleted file mode 100644 index ae1114a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/graph/union_find/\350\242\253\345\233\264\347\273\225\347\232\204\345\214\272\345\237\237.java" +++ /dev/null @@ -1,136 +0,0 @@ -package io.github.dunwu.algorithm.graph.union_find; - -import org.junit.jupiter.api.Assertions; - -/** - * 130. 被围绕的区域 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 被围绕的区域 { - - public static void main(String[] args) { - Solution s = new Solution(); - - char[][] input = new char[][] { - { 'X', 'X', 'X', 'X' }, - { 'X', 'O', 'O', 'X' }, - { 'X', 'X', 'O', 'X' }, - { 'X', 'O', 'X', 'X' } - }; - char[][] expect = new char[][] { - { 'X', 'X', 'X', 'X' }, - { 'X', 'X', 'X', 'X' }, - { 'X', 'X', 'X', 'X' }, - { 'X', 'O', 'X', 'X' } - }; - s.solve(input); - Assertions.assertArrayEquals(expect, input); - } - - static class Solution { - - private int m; - private int n; - int[][] direct = new int[][] { { 1, 0 }, { 0, 1 }, { 0, -1 }, { -1, 0 } }; - - public void solve(char[][] board) { - - if (board == null || board.length == 0) return; - m = board.length; - n = board[0].length; - - // 给 dummy 留一个额外位置 - UF uf = new UF(m * n + 1); - int dummy = m * n; - - // 将首列和末列的 O 与 dummy 连通 - for (int i = 0; i < m; i++) { - if (board[i][0] == 'O') { uf.union(index(i, 0), dummy); } - if (board[i][n - 1] == 'O') { uf.union(index(i, n - 1), dummy); } - } - - // 将首行和末行的 O 与 dummy 连通 - for (int j = 0; j < n; j++) { - if (board[0][j] == 'O') { uf.union(index(0, j), dummy); } - if (board[m - 1][j] == 'O') { uf.union(index(m - 1, j), dummy); } - } - - // 方向数组 d 是上下左右搜索的常用手法 - for (int i = 1; i < m - 1; i++) { - for (int j = 1; j < n - 1; j++) { - if (board[i][j] == 'O') { - // 将此 O 与上下左右的 O 连通 - for (int[] d : direct) { - int x = i + d[0], y = j + d[1]; - if (board[x][y] == 'O') { - uf.union(index(x, y), index(i, j)); - } - } - } - } - } - - // 所有不和 dummy 连通的 O,都要被替换 - for (int i = 1; i < m - 1; i++) { - for (int j = 1; j < n - 1; j++) { - int index = index(i, j); - if (!uf.connected(index, dummy)) { - board[i][j] = 'X'; - } - } - } - } - - public int index(int row, int col) { - return row * n + col; - } - - static class UF { - - // 连通分量个数 - private int count; - // 存储每个节点的父节点 - private int[] parent; - - public UF(int n) { - this.count = n; - parent = new int[n]; - for (int i = 0; i < n; i++) { - parent[i] = i; - } - } - - public void union(int p, int q) { - int rootP = find(p); - int rootQ = find(q); - - if (rootP == rootQ) { return; } - - parent[rootQ] = rootP; - count--; - } - - public boolean connected(int p, int q) { - int rootP = find(p); - int rootQ = find(q); - return rootP == rootQ; - } - - public int find(int x) { - if (parent[x] != x) { - parent[x] = find(parent[x]); - } - return parent[x]; - } - - public int count() { - return count; - } - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\346\225\260\347\273\204\346\213\206\345\210\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\346\225\260\347\273\204\346\213\206\345\210\206.java" deleted file mode 100644 index 88d7ee5..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\346\225\260\347\273\204\346\213\206\345\210\206.java" +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.dunwu.algorithm.greedy; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 561. 数组拆分 - * - * @author Zhang Peng - * @since 2018-11-05 - */ -public class 数组拆分 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.arrayPairSum(new int[] { 1, 4, 3, 2 })); - Assertions.assertEquals(9, s.arrayPairSum(new int[] { 6, 2, 6, 5, 1, 2 })); - } - - static class Solution { - - - public int arrayPairSum(int[] nums) { - Arrays.sort(nums); - int sum = 0; - for (int i = 0; i < nums.length; i+=2) { - sum += nums[i]; - } - return sum; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\217.java" deleted file mode 100644 index bae6a44..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\217.java" +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.dunwu.algorithm.greedy; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; - -/** - * 55. 跳跃游戏 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 跳跃游戏 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, s.jump(new int[] { 2, 3, 1, 1, 4 })); - } - - static class Solution { - - int[] memo; - - public int jump(int[] nums) { - if (nums.length <= 1) { - return 0; - } - int n = nums.length; - // 备忘录都初始化为 n,相当于 INT_MAX - // 因为从 0 跳到 n - 1 最多 n - 1 步 - memo = new int[n]; - Arrays.fill(memo, n); - - return dp(nums, 0); - } - - int dp(int[] nums, int p) { - int n = nums.length; - if (p >= n - 1) { - return 0; - } - - int steps = nums[p]; - // 你可以选择跳 1 步,2 步... - for (int i = 1; i <= steps; i++) { - // 穷举每一个选择 - // 计算每一个子问题的结果 - int sub = dp(nums, p + i); - // 取其中最小的作为最终结果 - memo[p] = Math.min(memo[p], sub + 1); - } - return memo[p]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\2172.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\2172.java" deleted file mode 100644 index d1413bb..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/greedy/\350\267\263\350\267\203\346\270\270\346\210\2172.java" +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.dunwu.algorithm.greedy; - -import org.junit.jupiter.api.Assertions; - -/** - * 53. 最大子数组和 - * - * @author Zhang Peng - * @date 2025-11-10 - */ -public class 跳跃游戏2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.canJump(new int[] { 2, 3, 1, 1, 4 })); - } - - static class Solution { - - public boolean canJump(int[] nums) { - int farthest = 0; - for (int i = 0; i < nums.length; i++) { - farthest = Math.max(farthest, i + nums[i]); - if (farthest <= i) return false; - } - return farthest >= nums.length - 1; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/DesignHashmap.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/DesignHashmap.java deleted file mode 100644 index 8105451..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/DesignHashmap.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.github.dunwu.algorithm.hash; - -// 【设计哈希集合】 - -// -// 不使用任何内建的哈希表库设计一个哈希映射 -//// -//// 具体地说,你的设计应该包含以下的功能 -//// -//// put(key, value):向哈希映射中插入(键,值)的数值对。如果键对应的值已经存在,更新这个值。 -//// get(key):返回给定的键所对应的值,如果映射中不包含这个键,返回-1。 -//// remove(key):如果映射中存在这个键,删除这个数值对。 -//// -//// 示例: -//// -//// MyHashMap hashMap = new MyHashMap(); -//// hashMap.put(1, 1); -//// hashMap.put(2, 2); -//// hashMap.get(1); // 返回 1 -//// hashMap.get(3); // 返回 -1 (未找到) -//// hashMap.put(2, 1); // 更新已有的值 -//// hashMap.get(2); // 返回 1 -//// hashMap.remove(2); // 删除键为2的数据 -//// hashMap.get(2); // 返回 -1 (未找到) -//// -//// 注意: -//// -//// 所有的值都在 [1, 1000000]的范围内。 -//// 操作的总数目在[1, 10000]范围内。 -//// 不要使用内建的哈希库。 - -class DesignHashmap { - - private int buckets = 1000; - - private int itemsPerBucket = 1001; - - private boolean[][] table; - - /** - * Initialize your data structure here. - */ - public DesignHashmap() { - table = new boolean[buckets][]; - } - - public void add(int key) { - int hashkey = hash(key); - - if (table[hashkey] == null) { - table[hashkey] = new boolean[itemsPerBucket]; - } - table[hashkey][pos(key)] = true; - } - - public int hash(int key) { - return key % buckets; - } - - public int pos(int key) { - return key / buckets; - } - - public void remove(int key) { - int hashkey = hash(key); - - if (table[hashkey] != null) { - table[hashkey][pos(key)] = false; - } - } - - /** - * Returns true if this set did not already contain the specified element - */ - public boolean contains(int key) { - int hashkey = hash(key); - return table[hashkey] != null && table[hashkey][pos(key)]; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/JewelsAndStones.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/JewelsAndStones.java deleted file mode 100644 index 57f5933..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/JewelsAndStones.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.dunwu.algorithm.hash; - -import java.util.HashSet; - -/* -https://leetcode.com/problems/jewels-and-stones/ - -You're given strings J representing the types of stones that are jewels, and S representing the stones you have. -Each character in S is a type of stone you have. You want to know how many of the stones you have are also jewels. - -The letters in J are guaranteed distinct, and all characters in J and S are letters. -Letters are case sensitive, so "a" is considered a different type of stone from "A". - -Example 1: - -Input: J = "aA", S = "aAAbbbb" -Output: 3 -Example 2: - -Input: J = "z", S = "ZZ" -Output: 0 -Note: - -S and J will consist of letters and have length at most 50. -The characters in J are distinct. -*/ -public class JewelsAndStones { - - public static void main(String[] args) { - JewelsAndStones tmpl = new JewelsAndStones(); - - int result1 = tmpl.numJewelsInStones("aA", "aAAbbbb"); - System.out.println("result1 = [" + result1 + "]"); - - int result2 = tmpl.numJewelsInStones("z", "ZZ"); - System.out.println("result1 = [" + result2 + "]"); - } - - public int numJewelsInStones(String J, String S) { - HashSet set = new HashSet(); - for (int i = 0; i < J.length(); i++) { - set.add(J.charAt(i)); - } - - int count = 0; - for (int i = 0; i < S.length(); i++) { - if (set.contains(S.charAt(i))) { - count++; - } - } - return count; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/MyHashMap.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/MyHashMap.java deleted file mode 100644 index 8cf1e6e..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/MyHashMap.java +++ /dev/null @@ -1,126 +0,0 @@ -package io.github.dunwu.algorithm.hash; - -// 不使用任何内建的哈希表库设计一个哈希映射(HashMap)。 -// -// 实现 MyHashMap 类: -// -// MyHashMap() 用空映射初始化对象 -// void put(int key, int value) 向 HashMap 插入一个键值对 (key, value) 。如果 key 已经存在于映射中,则更新其对应的值 value 。 -// int get(int key) 返回特定的 key 所映射的 value ;如果映射中不包含 key 的映射,返回 -1 。 -// void remove(key) 如果映射中存在 key 的映射,则移除 key 和它所对应的 value 。 -// -// 示例: -// -// 输入: -// ["MyHashMap", "put", "put", "get", "get", "put", "get", "remove", "get"] -// [[], [1, 1], [2, 2], [1], [3], [2, 1], [2], [2], [2]] -// 输出: -// [null, null, null, 1, -1, null, 1, null, -1] -// -// 解释: -// MyHashMap myHashMap = new MyHashMap(); -// myHashMap.put(1, 1); // myHashMap 现在为 [[1,1]] -// myHashMap.put(2, 2); // myHashMap 现在为 [[1,1], [2,2]] -// myHashMap.get(1); // 返回 1 ,myHashMap 现在为 [[1,1], [2,2]] -// myHashMap.get(3); // 返回 -1(未找到),myHashMap 现在为 [[1,1], [2,2]] -// myHashMap.put(2, 1); // myHashMap 现在为 [[1,1], [2,1]](更新已有的值) -// myHashMap.get(2); // 返回 1 ,myHashMap 现在为 [[1,1], [2,1]] -// myHashMap.remove(2); // 删除键为 2 的数据,myHashMap 现在为 [[1,1]] -// myHashMap.get(2); // 返回 -1(未找到),myHashMap 现在为 [[1,1]] -// -// 提示: -// -// 0 <= key, value <= 106 -// 最多调用 104 次 put、get 和 remove 方法 -// -// 链接:https://leetcode-cn.com/leetbook/read/hash-table/xhqwd3/ - -import java.util.LinkedList; - -/** - * 实现 HashMap,使用拉链表法(基于 LinkedList 实现)决哈希冲突 - * - * @author Zhang Peng - * @since 2022-03-20 - */ -public class MyHashMap { - - private final int BUCKET_NUM = 1000; - private final LinkedList[] data; - - public MyHashMap() { - data = new LinkedList[BUCKET_NUM]; - for (int i = 0; i < BUCKET_NUM; ++i) { - data[i] = new LinkedList<>(); - } - } - - public void put(int key, int value) { - int bucket = hash(key); - for (Pair pair : data[bucket]) { - if (pair.key == key) { - pair.value = value; - return; - } - } - data[bucket].add(new Pair(key, value)); - } - - public int get(int key) { - int bucket = hash(key); - for (Pair pair : data[bucket]) { - if (pair.key == key) { - return pair.value; - } - } - return -1; - } - - public void remove(int key) { - int bucket = hash(key); - for (Pair pair : data[bucket]) { - if (pair.key == key) { - data[bucket].remove(pair); - return; - } - } - } - - private int hash(int key) { - return key % BUCKET_NUM; - } - - private static class Pair { - - private final int key; - private int value; - - public Pair(int key, int value) { - this.key = key; - this.value = value; - } - - public int getKey() { - return key; - } - - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = value; - } - - } - - public static void main(String[] args) { - MyHashMap obj = new MyHashMap(); - obj.put(5, 555); - obj.put(1005, 555); - System.out.println("key = 5, value = " + obj.get(5)); - System.out.println("key = 1005, value = " + obj.get(1005)); - // obj.remove(key); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/MyHashSet.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/MyHashSet.java deleted file mode 100644 index 1a864d5..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/MyHashSet.java +++ /dev/null @@ -1,90 +0,0 @@ -// 【设计哈希集合】 -// -// 不使用任何内建的哈希表库设计一个哈希集合 -// -// 具体地说,你的设计应该包含以下的功能 -// -// add(value):向哈希集合中插入一个值。 -// contains(value) :返回哈希集合中是否存在这个值。 -// remove(value):将给定值从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。 -// -// 示例: -// -// MyHashSet hashSet = new MyHashSet(); -// hashSet.add(1); -// hashSet.add(2); -// hashSet.contains(1); // 返回 true -// hashSet.contains(3); // 返回 false (未找到) -// hashSet.add(2); -// hashSet.contains(2); // 返回 true -// hashSet.remove(2); -// hashSet.contains(2); // 返回 false (已经被删除) -// -// 注意: -// -// 所有的值都在 [1, 1000000]的范围内。 -// 操作的总数目在[1, 10000]范围内。 -// 不要使用内建的哈希集合库。 - -package io.github.dunwu.algorithm.hash; - -import java.util.LinkedList; - -/** - * 实现 HashMap,使用拉链表法(基于 LinkedList 实现)决哈希冲突 - * - * @author Zhang Peng - * @since 2022-03-20 - */ -class MyHashSet { - - private final int BUCKET_NUM = 1000; - - private final LinkedList[] data; - - public MyHashSet() { - data = new LinkedList[BUCKET_NUM]; - for (int i = 0; i < BUCKET_NUM; ++i) { - data[i] = new LinkedList<>(); - } - } - - public void add(int key) { - int bucket = hash(key); - for (Integer item : data[bucket]) { - if (item == key) { - return; - } - } - data[bucket].add(key); - } - - public int hash(int key) { - return key % BUCKET_NUM; - } - - public int pos(int key) { - return key / BUCKET_NUM; - } - - public void remove(int key) { - int bucket = hash(key); - for (Integer item : data[bucket]) { - if (item == key) { - data[bucket].remove(item); - return; - } - } - } - - public boolean contains(int key) { - int bucket = hash(key); - for (Integer item : data[bucket]) { - if (item == key) { - return true; - } - } - return false; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/MyHashSet2.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/MyHashSet2.java deleted file mode 100644 index dc60c47..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/MyHashSet2.java +++ /dev/null @@ -1,78 +0,0 @@ -// 【设计哈希集合】 -// -// 不使用任何内建的哈希表库设计一个哈希集合 -// -// 具体地说,你的设计应该包含以下的功能 -// -// add(value):向哈希集合中插入一个值。 -// contains(value) :返回哈希集合中是否存在这个值。 -// remove(value):将给定值从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。 -// -// 示例: -// -// MyHashSet hashSet = new MyHashSet(); -// hashSet.add(1); -// hashSet.add(2); -// hashSet.contains(1); // 返回 true -// hashSet.contains(3); // 返回 false (未找到) -// hashSet.add(2); -// hashSet.contains(2); // 返回 true -// hashSet.remove(2); -// hashSet.contains(2); // 返回 false (已经被删除) -// -// 注意: -// -// 所有的值都在 [1, 1000000]的范围内。 -// 操作的总数目在[1, 10000]范围内。 -// 不要使用内建的哈希集合库。 - -package io.github.dunwu.algorithm.hash; - -/** - * 实现 HashSet,使用开放寻址法决哈希冲突 - * - * @author Zhang Peng - * @since 2022-03-20 - */ -class MyHashSet2 { - - private final int BUCKET_NUM = 1000; - - private final boolean[][] data; - - public MyHashSet2() { - data = new boolean[BUCKET_NUM][]; - } - - public void add(int key) { - int bucket = hash(key); - - if (data[bucket] == null) { - // BUCKET_NUM + 1 是为了防止数组越界 - data[bucket] = new boolean[BUCKET_NUM + 1]; - } - data[bucket][pos(key)] = true; - } - - public int hash(int key) { - return key % BUCKET_NUM; - } - - public int pos(int key) { - return key / BUCKET_NUM; - } - - public void remove(int key) { - int bucket = hash(key); - - if (data[bucket] != null) { - data[bucket][pos(key)] = false; - } - } - - public boolean contains(int key) { - int bucket = hash(key); - return data[bucket] != null && data[bucket][pos(key)]; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/SubdomainVisitCount.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/SubdomainVisitCount.java deleted file mode 100644 index 7d7f733..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/SubdomainVisitCount.java +++ /dev/null @@ -1,85 +0,0 @@ -package io.github.dunwu.algorithm.hash; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/* -https://leetcode.com/problems/subdomain-visit-count/ - -A website domain like "discuss.leetcode.com" consists of various subdomains. At the top level, we have "com", at the -next level, we have "leetcode.com", and at the lowest level, "discuss.leetcode.com". -When we visit a domain like "discuss.leetcode.com", we will also visit the parent domains "leetcode.com" and -"com" implicitly. - -Now, call a "count-paired domain" to be a count (representing the number of visits this domain received), -followed by a space, followed by the address. An example of a count-paired domain might be "9001 discuss.leetcode.com". - -We are given a list cpdomains of count-paired domains. We would like a list of count-paired domains, (in the same format -as the input, and in any order), that explicitly counts the number of visits to each subdomain. - -Example 1: -Input: -["9001 discuss.leetcode.com"] -Output: -["9001 discuss.leetcode.com", "9001 leetcode.com", "9001 com"] -Explanation: -We only have one website domain: "discuss.leetcode.com". As discussed above, the subdomain "leetcode.com" and "com" -will also be visited. So they will all be visited 9001 times. - -Example 2: -Input: -["900 google.mail.com", "50 yahoo.com", "1 intel.mail.com", "5 wiki.org"] -Output: -["901 mail.com","50 yahoo.com","900 google.mail.com","5 wiki.org","5 org","1 intel.mail.com","951 com"] -Explanation: -We will visit "google.mail.com" 900 times, "yahoo.com" 50 times, "intel.mail.com" once and "wiki.org" 5 times. -For the subdomains, we will visit "mail.com" 900 + 1 = 901 times, "com" 900 + 50 + 1 = 951 times, and "org" 5 times. - -Notes: - -The length of cpdomains will not exceed 100. -The length of each domain name will not exceed 100. -Each address will have either 1 or 2 "." characters. -The input count in any count-paired domain will not exceed 10000. -The answer output can be returned in any order. -*/ -public class SubdomainVisitCount { - - public static void main(String[] args) { - SubdomainVisitCount tmpl = new SubdomainVisitCount(); - - String[] s1 = new String[] { "9001 discuss.leetcode.com" }; - String[] s2 = new String[] { "900 google.mail.com", "50 yahoo.com", "1 intel.mail.com", "5 wiki.org" }; - tmpl.subdomainVisits(s1); - tmpl.subdomainVisits(s2); - } - - public List subdomainVisits(String[] cpdomains) { - List result = new ArrayList<>(); - Map map = new HashMap<>(); // key: subdomain, value: frequency - StringBuilder resultStringBuilder = new StringBuilder(); - - for (String cpdomain : cpdomains) { - int indexSpace = cpdomain.indexOf(' '); - int numClicks = Integer.parseInt(cpdomain.substring(0, indexSpace)); - String domain = cpdomain.substring(indexSpace + 1); - resultStringBuilder.setLength(0); - resultStringBuilder.append(domain); - while (true) { - map.put(resultStringBuilder.toString(), - map.getOrDefault(resultStringBuilder.toString(), 0) + numClicks); - int dotPosition = resultStringBuilder.indexOf("."); - if (dotPosition == -1) { break; } - resultStringBuilder.delete(0, dotPosition + 1); - } - } - - for (String domain : map.keySet()) - result.add(map.get(domain) + " " + domain); - - return result; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/ToLowerCase.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/ToLowerCase.java deleted file mode 100644 index 97af3d7..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/hash/ToLowerCase.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.hash; - -/* -https://leetcode.com/problems/to-lower-case/ - -Implement function ToLowerCase() that has a string parameter str, and returns the same string in lowercase. - - - -Example 1: - -Input: "Hello" -Output: "hello" -Example 2: - -Input: "here" -Output: "here" -Example 3: - -Input: "LOVELY" -Output: "lovely" - - */ -public class ToLowerCase { - - public static void main(String[] args) { - ToLowerCase tmpl = new ToLowerCase(); - String result = tmpl.toLowerCase("Hello"); - System.out.println("result = [" + result + "]"); - } - - public String toLowerCase(String str) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < str.length(); i++) { - if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') { - sb.append((char) (str.charAt(i) + 32)); - } else { - sb.append(str.charAt(i)); - } - } - return sb.toString(); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/KthLargest.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/KthLargest.java deleted file mode 100644 index 57a726f..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/KthLargest.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.heap; - -import java.util.PriorityQueue; - -// 703. 数据流中的第K大元素 -// -// 设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。 -// -// 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。 -// -// 示例: -// -// int k = 3; -// int[] arr = [4,5,8,2]; -// KthLargest kthLargest = new KthLargest(3, arr); -// kthLargest.add(3);   // returns 4 -// kthLargest.add(5);   // returns 5 -// kthLargest.add(10);  // returns 5 -// kthLargest.add(9);   // returns 8 -// kthLargest.add(4);   // returns 8 -// 说明: -// 你可以假设 nums 的长度≥ k-1 且k ≥ 1。 - -public class KthLargest> { - - private int size; - - private PriorityQueue queue; - - public KthLargest(int k, T[] nums) { - size = k; - queue = new PriorityQueue<>(k); - for (T num : nums) { - add(num); - } - } - - public T add(T val) { - if (queue.size() < size) { - queue.add(val); - } else if (queue.peek().compareTo(val) < 0) { - queue.poll(); - queue.add(val); - } - return queue.peek(); - } - - public static void main(String[] args) { - Integer[] data = new Integer[] { 4, 5, 8, 2 }; - KthLargest demo = new KthLargest<>(3, data); - System.out.println("args = " + demo.add(3)); - System.out.println("args = " + demo.add(5)); - System.out.println("args = " + demo.add(10)); - System.out.println("args = " + demo.add(9)); - System.out.println("args = " + demo.add(4)); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/KthLeast.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/KthLeast.java deleted file mode 100644 index e2110a8..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/KthLeast.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.heap; - -import java.util.PriorityQueue; - -/** - * @author Zhang Peng - * @since 2020-03-06 - */ -public class KthLeast> { - - private int size; - - private PriorityQueue queue; - - public KthLeast(int k, T[] array) { - this.size = k; - queue = new PriorityQueue<>(k); - for (T v : array) { - add(v); - } - } - - public T add(T val) { - if (queue.size() < size) { - queue.add(val); - } else if (queue.peek().compareTo(val) > 0) { - queue.poll(); - queue.add(val); - } - return queue.peek(); - } - - public T pop() { - return queue.poll(); - } - - public static void main(String[] args) { - Integer[] data = new Integer[] { 3, 2, 1 }; - KthLeast demo = new KthLeast<>(2, data); - System.out.println("args = " + demo.pop()); - System.out.println("args = " + demo.pop()); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/LeastKNum.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/LeastKNum.java deleted file mode 100644 index 9719c08..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/heap/LeastKNum.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.dunwu.algorithm.heap; - -/** - * 面试题40. 最小的k个数 - *

- * 输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。 - *

- *   - *

- * 示例 1: - *

- * 输入:arr = [3,2,1], k = 2 输出:[1,2] 或者 [2,1] 示例 2: - *

- * 输入:arr = [0,1,2,1], k = 1 输出:[0]   - *

- * 限制: - *

- * 0 <= k <= arr.length <= 10000 0 <= arr[i] <= 10000 - * - * @author Zhang Peng - * @since 2020-03-06 - */ -public class LeastKNum { - - // public int[] getLeastNumbers(int[] arr, int k) { - // - // } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/ListNode.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/ListNode.java deleted file mode 100644 index f8868a7..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/ListNode.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public final class ListNode { - - public int val; - public ListNode next; - - public ListNode(int val) { this.val = val; } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ListNode)) return false; - ListNode listNode = (ListNode) o; - return val == listNode.val && - Objects.equals(next, listNode.next); - } - - @Override - public int hashCode() { - return Objects.hash(val, next); - } - - public List toList() { - return ListNode.toList(this); - } - - public static ListNode createLinkedList(int[] arr) { - if (arr == null || arr.length == 0) { - return null; - } - ListNode head = new ListNode(arr[0]); - ListNode cur = head; - for (int i = 1; i < arr.length; i++) { - cur.next = new ListNode(arr[i]); - cur = cur.next; - } - return head; - } - - public static void addLast() { - - } - - public static ListNode buildList(int... list) { - ListNode head = new ListNode(-1); - ListNode node = head; - for (int val : list) { - node.next = new ListNode(val); - node = node.next; - } - return head.next; - } - - public static ListNode buildCycleList(int cyclePoint, int[] list) { - ListNode head = new ListNode(-1); - ListNode node = head; - ListNode cycleBeginNode = null; - for (int val : list) { - ListNode item = new ListNode(val); - if (cyclePoint == 0 && cycleBeginNode == null) { - cycleBeginNode = item; - } else { - cyclePoint--; - } - node.next = item; - node = node.next; - } - if (cycleBeginNode != null) { - node.next = cycleBeginNode; - } - return head.next; - } - - public static List toList(ListNode listNode) { - List list = new ArrayList<>(); - while (listNode != null) { - list.add(listNode.val); - listNode = listNode.next; - } - return list; - } - - public static void buildMetPot(ListNode listA, ListNode listB, int skipA, int skipB) { - ListNode pA = listA; - for (int i = 0; i < skipA; i++) { - pA = pA.next; - } - ListNode pB = listB; - for (int i = 0; i < skipB - 1; i++) { - pB = pB.next; - } - pB.next = pA; - } - - public static void main(String[] args) { - int[] arr = { 1, 2, 3, 4, 5 }; - ListNode head = createLinkedList(arr); - ListNode p = head; - while (p.next != null) { - p = p.next; - } - p.next = new ListNode(6); - while (head != null) { - System.out.println(head.val); - head = head.next; - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" deleted file mode 100644 index 2afe676..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\344\272\214\350\277\233\345\210\266\351\223\276\350\241\250\350\275\254\346\225\264\346\225\260.java" +++ /dev/null @@ -1,34 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.base; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 二进制链表转整数 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 二进制链表转整数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(5, s.getDecimalValue(ListNode.buildList(1, 0, 1))); - Assertions.assertEquals(0, s.getDecimalValue(ListNode.buildList(0))); - } - - static class Solution { - - public int getDecimalValue(ListNode head) { - int res = 0; - ListNode p = head; - while (p != null) { - res = res * 2 + p.val; - p = p.next; - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271.java" deleted file mode 100644 index 97faea6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/base/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\350\212\202\347\202\271.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.base; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * LCR 136. 删除链表的节点 - * - * @author Zhang Peng - * @date 2025-12-18 - */ -public class 删除链表的节点 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(ListNode.buildList(4, 5, 1), s.deleteNode(ListNode.buildList(4, 5, 1, 9), 9)); - Assertions.assertEquals(ListNode.buildList(4, 1, 9), s.deleteNode(ListNode.buildList(4, 5, 1, 9), 5)); - Assertions.assertEquals(ListNode.buildList(4, 5, 9), s.deleteNode(ListNode.buildList(4, 5, 1, 9), 1)); - Assertions.assertEquals(ListNode.buildList(5, 1, 9), s.deleteNode(ListNode.buildList(4, 5, 1, 9), 4)); - } - - static class Solution { - - public ListNode deleteNode(ListNode head, int val) { - ListNode dummy = new ListNode(-1); - dummy.next = head; - ListNode pre = dummy; - while (pre != null && pre.next != null) { - ListNode cur = pre.next; - if (cur.val == val) { - pre.next = cur.next; - pre = cur.next; - } else { - pre = pre.next; - } - } - return dummy.next; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/DoublyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/DoublyLinkedList.java deleted file mode 100644 index 9b4c126..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/DoublyLinkedList.java +++ /dev/null @@ -1,230 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.demo; - -import lombok.Getter; -import lombok.Setter; - -import java.util.ArrayList; -import java.util.List; - -public class DoublyLinkedList { - - private int size = 0; - private Node first = null; - private Node last = null; - - public DoublyLinkedList() { - first = new Node<>(null); - last = new Node<>(null); - first.next = last; - last.prev = first; - } - - public int size() { - return size; - } - - public boolean isEmpty() { - return size == 0; - } - - public int indexOf(E element) { - int pos = 0; - - Node p = first.next; - while (p != null) { - if (p.element.equals(element)) { - return pos; - } - p = p.next; - pos++; - } - return -1; - } - - public E get(int index) { - Node node = node(index); - return node == null ? null : node.element; - } - - Node node(int index) { - int i = 0; - - Node p = first; - while (p != null && i != index) { - p = p.next; - i++; - } - return p; - } - - public void addFirst(E element) { - - Node node = new Node<>(element); - Node temp = first.next; - - node.next = temp; - temp.prev = node; - - node.prev = first; - first.next = node; - - size++; - } - - public void addLast(E element) { - - Node node = new Node<>(element); - Node temp = last.prev; - - temp.next = node; - node.prev = temp; - - last.prev = node; - node.next = last; - - size++; - } - - public boolean add(int index, E element) { - - if (index == 0) { - addFirst(element); - return true; - } - - Node p = node(index); - Node node = new Node<>(element); - node.next = p.next; - p.next.prev = node; - - node.prev = p; - p.next = node; - - size++; - return true; - } - - public boolean remove(E e) { - if (e == null) { - Node p = first; - while (p.next != null) { - Node x = p.next; - if (x.element == null) { - p.next = x.next; - size--; - return true; - } - p = p.next; - } - } else { - Node p = first; - while (p != null && p.next != null) { - Node x = p.next; - if (e.equals(x.element)) { - p.next = x.next; - size--; - return true; - } - p = p.next; - } - } - return false; - } - - public boolean removeAll(E e) { - - if (first.next == null) { - return false; - } - - if (e == null) { - Node p = first; - while (p.next != null) { - Node x = p.next; - if (x.element == null) { - p.next = x.next; - size--; - } - p = p.next; - } - } else { - Node p = first; - while (p != null && p.next != null) { - if (e.equals(p.next.element)) { - p.next = p.next.next; - size--; - } else { - p = p.next; - } - } - } - return true; - } - - public void clear() { - first.next = last; - last.prev = first; - size = 0; - } - - public void printAll() { - Node p = first; - while (p.next != null && p.next != last) { - p = p.next; - System.out.print(p.element + " "); - } - System.out.println(); - } - - public List toList() { - List list = new ArrayList<>(); - Node node = first.next; - while (node != null && node != last) { - list.add(node.element); - node = node.next; - } - return list; - } - - @Getter - @Setter - public static class Node { - - private E element; - private Node next; - private Node prev; - - public Node(E element) { - this.element = element; - this.next = null; - this.prev = null; - } - - public Node(E element, Node prev, Node next) { - this.element = element; - this.prev = prev; - this.next = next; - } - - } - - public static void main(String[] args) { - int[] nums = { 1, 2, 3, 4, 5 }; - DoublyLinkedList list = new DoublyLinkedList<>(); - DoublyLinkedList reverseList = new DoublyLinkedList<>(); - for (int num : nums) { - list.addLast(num); - reverseList.addFirst(num); - } - - list.add(5, 999); - System.out.println("【队尾写入链表】"); - list.printAll(); - System.out.println("【队头写入链表】"); - reverseList.printAll(); - list.printAll(); - System.out.println("999 在队列中的位置:" + list.indexOf(999)); - System.out.println("队列中位置 5 的元素值:" + list.get(5)); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBaseLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBaseLinkedList.java deleted file mode 100644 index de8e751..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBaseLinkedList.java +++ /dev/null @@ -1,177 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.demo; - -import java.util.Scanner; - -/** - * 基于单链表LRU算法(java) - * - * @author hoda - * @create 2018-12-17 - */ -public class LRUBaseLinkedList { - - /** - * 默认链表容量 - */ - private final static Integer DEFAULT_CAPACITY = 10; - - /** - * 头结点 - */ - private Node headNode; - - /** - * 链表长度 - */ - private Integer length; - - /** - * 链表容量 - */ - private Integer capacity; - - public LRUBaseLinkedList() { - this.headNode = new Node<>(); - this.capacity = DEFAULT_CAPACITY; - this.length = 0; - } - - public LRUBaseLinkedList(Integer capacity) { - this.headNode = new Node<>(); - this.capacity = capacity; - this.length = 0; - } - - public void add(T data) { - Node preNode = findPreNode(data); - - // 链表中存在,删除原数据,再插入到链表的头部 - if (preNode != null) { - deleteElemOptim(preNode); - intsertElemAtBegin(data); - } else { - if (length >= this.capacity) { - //删除尾结点 - deleteElemAtEnd(); - } - intsertElemAtBegin(data); - } - } - - /** - * 删除preNode结点下一个元素 - * - * @param preNode - */ - private void deleteElemOptim(Node preNode) { - Node temp = preNode.getNext(); - preNode.setNext(temp.getNext()); - temp = null; - length--; - } - - /** - * 链表头部插入节点 - * - * @param data - */ - private void intsertElemAtBegin(T data) { - Node next = headNode.getNext(); - headNode.setNext(new Node<>(data, next)); - length++; - } - - /** - * 获取查找到元素的前一个结点 - * - * @param data - * @return - */ - private Node findPreNode(T data) { - Node node = headNode; - while (node.getNext() != null) { - if (data.equals(node.getNext().getElement())) { - return node; - } - node = node.getNext(); - } - return null; - } - - /** - * 删除尾结点 - */ - private void deleteElemAtEnd() { - Node ptr = headNode; - // 空链表直接返回 - if (ptr.getNext() == null) { - return; - } - - // 倒数第二个结点 - while (ptr.getNext().getNext() != null) { - ptr = ptr.getNext(); - } - - Node tmp = ptr.getNext(); - ptr.setNext(null); - tmp = null; - length--; - } - - private void printAll() { - Node node = headNode.getNext(); - while (node != null) { - System.out.print(node.getElement() + ","); - node = node.getNext(); - } - System.out.println(); - } - - public static class Node { - - private T element; - - private Node next; - - public Node(T element) { - this.element = element; - } - - public Node(T element, Node next) { - this.element = element; - this.next = next; - } - - public Node() { - this.next = null; - } - - public T getElement() { - return element; - } - - public void setElement(T element) { - this.element = element; - } - - public Node getNext() { - return next; - } - - public void setNext(Node next) { - this.next = next; - } - - } - - public static void main(String[] args) { - LRUBaseLinkedList list = new LRUBaseLinkedList<>(); - Scanner sc = new Scanner(System.in); - while (true) { - list.add(sc.nextInt()); - list.printAll(); - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBasedArray.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBasedArray.java deleted file mode 100644 index cd909e4..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/LRUBasedArray.java +++ /dev/null @@ -1,174 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.demo; - -import java.util.HashMap; -import java.util.Map; -/** - * Created by SpecialYang in 2018/12/7 2:00 PM. - * - * 基于数组实现的LRU缓存 - * 1. 空间复杂度为O(n) - * 2. 时间复杂度为O(n) - * 3. 不支持null的缓存 - */ -public class LRUBasedArray { - - private static final int DEFAULT_CAPACITY = (1 << 3); - - private int capacity; - - private int count; - - private T[] value; - - private Map holder; - - public LRUBasedArray() { - this(DEFAULT_CAPACITY); - } - - public LRUBasedArray(int capacity) { - this.capacity = capacity; - value = (T[]) new Object[capacity]; - count = 0; - holder = new HashMap(capacity); - } - - /** - * 模拟访问某个值 - * @param object - */ - public void offer(T object) { - if (object == null) { - throw new IllegalArgumentException("该缓存容器不支持null!"); - } - Integer index = holder.get(object); - if (index == null) { - if (isFull()) { - removeAndCache(object); - } else { - cache(object, count); - } - } else { - update(index); - } - } - - /** - * 若缓存中有指定的值,则更新位置 - * @param end - */ - public void update(int end) { - T target = value[end]; - rightShift(end); - value[0] = target; - holder.put(target, 0); - } - - /** - * 缓存数据到头部,但要先右移 - * @param object - * @param end 数组右移的边界 - */ - public void cache(T object, int end) { - rightShift(end); - value[0] = object; - holder.put(object, 0); - count++; - } - - /** - * 缓存满的情况,踢出后,再缓存到数组头部 - * @param object - */ - public void removeAndCache(T object) { - T key = value[--count]; - holder.remove(key); - cache(object, count); - } - - /** - * end左边的数据统一右移一位 - * @param end - */ - private void rightShift(int end) { - for (int i = end - 1; i >= 0; i--) { - value[i + 1] = value[i]; - holder.put(value[i], i + 1); - } - } - - public boolean isContain(T object) { - return holder.containsKey(object); - } - - public boolean isEmpty() { - return count == 0; - } - - public boolean isFull() { - return count == capacity; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < count; i++) { - sb.append(value[i]); - sb.append(" "); - } - return sb.toString(); - } - - static class TestLRUBasedArray { - - public static void main(String[] args) { - testDefaultConstructor(); - testSpecifiedConstructor(4); -// testWithException(); - } - - private static void testWithException() { - LRUBasedArray lru = new LRUBasedArray(); - lru.offer(null); - } - - public static void testDefaultConstructor() { - System.out.println("======无参测试========"); - LRUBasedArray lru = new LRUBasedArray(); - lru.offer(1); - lru.offer(2); - lru.offer(3); - lru.offer(4); - lru.offer(5); - System.out.println(lru); - lru.offer(6); - lru.offer(7); - lru.offer(8); - lru.offer(9); - System.out.println(lru); - } - - public static void testSpecifiedConstructor(int capacity) { - System.out.println("======有参测试========"); - LRUBasedArray lru = new LRUBasedArray(capacity); - lru.offer(1); - System.out.println(lru); - lru.offer(2); - System.out.println(lru); - lru.offer(3); - System.out.println(lru); - lru.offer(4); - System.out.println(lru); - lru.offer(2); - System.out.println(lru); - lru.offer(4); - System.out.println(lru); - lru.offer(7); - System.out.println(lru); - lru.offer(1); - System.out.println(lru); - lru.offer(2); - System.out.println(lru); - } - } -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/MyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/MyLinkedList.java deleted file mode 100644 index be76a54..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/MyLinkedList.java +++ /dev/null @@ -1,244 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.demo; - -import java.util.NoSuchElementException; - -public class MyLinkedList { - - // 虚拟头尾节点 - private int size; - final private Node head, tail; - - // 双链表节点 - private static class Node { - - E data; - Node next; - Node prev; - - Node(E data) { - this.data = data; - } - - } - - // 构造函数初始化虚拟头尾节点 - public MyLinkedList() { - this.head = new Node<>(null); - this.tail = new Node<>(null); - head.next = tail; - tail.prev = head; - this.size = 0; - } - - // ***** 增 ***** - - public void addLast(T data) { - Node node = new Node<>(data); - Node temp = tail.prev; - // temp <-> x - temp.next = node; - node.prev = temp; - - node.next = tail; - tail.prev = node; - // temp <-> x <-> tail - size++; - } - - public void addFirst(T e) { - Node x = new Node<>(e); - Node temp = head.next; - // head <-> temp - temp.prev = x; - x.next = temp; - - head.next = x; - x.prev = head; - // head <-> x <-> temp - size++; - } - - public void add(int index, T element) { - checkPositionIndex(index); - if (index == size) { - addLast(element); - return; - } - - // 找到 index 对应的 Node - Node p = getNode(index); - Node temp = p.prev; - // temp <-> p - - // 新要插入的 Node - Node x = new Node<>(element); - - p.prev = x; - temp.next = x; - - x.prev = temp; - x.next = p; - - // temp <-> x <-> p - - size++; - } - - // ***** 删 ***** - - public T removeFirst() { - if (size < 1) { - throw new NoSuchElementException(); - } - // 虚拟节点的存在是我们不用考虑空指针的问题 - Node x = head.next; - Node temp = x.next; - // head <-> x <-> temp - head.next = temp; - temp.prev = head; - - x.prev = null; - x.next = null; - // head <-> temp - - size--; - return x.data; - } - - public T removeLast() { - if (size < 1) { - throw new NoSuchElementException(); - } - Node x = tail.prev; - Node temp = tail.prev.prev; - // temp <-> x <-> tail - - tail.prev = temp; - temp.next = tail; - - x.prev = null; - x.next = null; - // temp <-> tail - - size--; - return x.data; - } - - public T remove(int index) { - checkElementIndex(index); - // 找到 index 对应的 Node - Node x = getNode(index); - Node prev = x.prev; - Node next = x.next; - // prev <-> x <-> next - prev.next = next; - next.prev = prev; - - x.prev = x.next = null; - // prev <-> next - - size--; - - return x.data; - } - - // ***** 查 ***** - - public T get(int index) { - checkElementIndex(index); - // 找到 index 对应的 Node - Node p = getNode(index); - - return p.data; - } - - public T getFirst() { - if (size < 1) { - throw new NoSuchElementException(); - } - - return head.next.data; - } - - public T getLast() { - if (size < 1) { - throw new NoSuchElementException(); - } - - return tail.prev.data; - } - - // ***** 改 ***** - - public T set(int index, T val) { - checkElementIndex(index); - // 找到 index 对应的 Node - Node p = getNode(index); - - T oldVal = p.data; - p.data = val; - - return oldVal; - } - - // ***** 其他工具函数 ***** - - public int size() { - return size; - } - - public boolean isEmpty() { - return size == 0; - } - - private Node getNode(int index) { - checkElementIndex(index); - Node p = head.next; - // TODO: 可以优化,通过 index 判断从 head 还是 tail 开始遍历 - for (int i = 0; i < index; i++) { - p = p.next; - } - return p; - } - - private boolean isElementIndex(int index) { - return index >= 0 && index < size; - } - - private boolean isPositionIndex(int index) { - return index >= 0 && index <= size; - } - - // 检查 index 索引位置是否可以存在元素 - private void checkElementIndex(int index) { - if (!isElementIndex(index)) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); } - } - - // 检查 index 索引位置是否可以添加元素 - private void checkPositionIndex(int index) { - if (!isPositionIndex(index)) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); } - } - - private void display() { - System.out.println("size = " + size); - for (Node p = head.next; p != tail; p = p.next) { - System.out.print(p.data + " <-> "); - } - System.out.println("null"); - System.out.println(); - } - - public static void main(String[] args) { - MyLinkedList list = new MyLinkedList<>(); - list.addLast(1); - list.addLast(2); - list.addLast(3); - list.addFirst(0); - list.add(2, 100); - - list.display(); - // size = 5 - // 0 <-> 1 <-> 100 <-> 2 -> 3 -> null - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/SinglyLinkedList.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/SinglyLinkedList.java deleted file mode 100644 index d519205..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/SinglyLinkedList.java +++ /dev/null @@ -1,264 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.demo; - -import lombok.Getter; -import lombok.Setter; - -import java.util.ArrayList; -import java.util.List; - -public class SinglyLinkedList { - - private int size = 0; - private Node first = null; - - public SinglyLinkedList() { - this.size = 0; - this.first = new Node<>(null); - } - - public SinglyLinkedList(E[] elementArray) { - this.size = 0; - this.first = new Node<>(null); - for (E element : elementArray) { - addLast(element); - } - } - - public int size() { - return size; - } - - public boolean isEmpty() { - return size == 0; - } - - public int indexOf(E element) { - int pos = 0; - Node p = first.next; - while (p != null) { - if (p.element.equals(element)) { - return pos; - } - p = p.next; - pos++; - } - return -1; - } - - public E get(int index) { - Node node = node(index); - return node == null ? null : node.element; - } - - Node node(int index) { - int i = 0; - Node p = first; - while (p != null && i != index) { - p = p.next; - i++; - } - return p; - } - - public void addFirst(E element) { - Node node = new Node<>(element); - node.next = first.next; - first.next = node; - size++; - } - - public void addLast(E element) { - Node node = new Node<>(element); - Node p = first; - while (p.next != null) { - p = p.next; - } - p.next = node; - size++; - } - - public boolean add(int index, E element) { - - checkPositionIndex(index); - - if (index == 0) { - addFirst(element); - return true; - } - - Node p = node(index - 1); - Node node = new Node<>(element); - node.next = p.next; - p.next = node; - size++; - return true; - } - - public void removeFirst() { - first = first.next; - size--; - } - - public void removeLast() { - Node p = first; - while (p.next.next != null) { - p = p.next; - } - p.next = null; - size--; - } - - public boolean remove(int index) { - - checkElementIndex(index); - - if (index == 0) { - removeFirst(); - } - - int pos = 0; - Node p = first; - while (pos < index - 1) { - p = p.next; - pos++; - } - p.next = p.next.next; - size--; - return true; - } - - public boolean remove(E e) { - if (e == null) { - Node p = first; - while (p.next != null) { - Node x = p.next; - if (x.element == null) { - p.next = x.next; - size--; - return true; - } - p = p.next; - } - } else { - Node p = first; - while (p.next != null) { - Node x = p.next; - if (x.element.equals(e)) { - p.next = x.next; - size--; - return true; - } - p = p.next; - } - } - return false; - } - - public boolean removeAll(E e) { - - if (first.next == null) { - return false; - } - - if (e == null) { - Node p = first; - while (p.next != null) { - Node x = p.next; - if (x.element == null) { - p.next = x.next; - size--; - } - p = p.next; - } - } else { - Node p = first; - while (p != null && p.next != null) { - if (p.next.element.equals(e)) { - p.next = p.next.next; - size--; - } else { - p = p.next; - } - } - } - return true; - } - - public void clear() { - first.next = null; - size = 0; - } - - private void checkElementIndex(int index) { - if (index >= 0 && index < size) { return; } - throw new RuntimeException("超出边界!"); - } - - private void checkPositionIndex(int index) { - if (index >= 0 && index <= size) { return; } - throw new RuntimeException("超出边界!"); - } - - public void printAll() { - Node p = first.next; - while (p != null) { - System.out.print(p.element + " "); - p = p.next; - } - System.out.println(); - } - - public List toList() { - List list = new ArrayList<>(); - Node node = first.next; - while (node != null) { - list.add(node.element); - node = node.next; - } - return list; - } - - @Getter - @Setter - private static class Node { - - private E element; - private Node next; - - public Node(E element) { - this.element = element; - this.next = null; - } - - public Node(E element, Node next) { - this.element = element; - this.next = next; - } - - } - - public static void main(String[] args) { - - Integer[] nums = { 1, 2, 3, 4, 5 }; - SinglyLinkedList list = new SinglyLinkedList<>(nums); - SinglyLinkedList reverseList = new SinglyLinkedList<>(); - for (int num : nums) { - reverseList.addFirst(num); - } - - list.add(5, 999); - System.out.println("【队尾写入链表】"); - list.printAll(); - System.out.println("【队头写入链表】"); - reverseList.printAll(); - System.out.println("999 在队列中的位置:" + list.indexOf(999)); - System.out.println("队列中位置 5 的元素值:" + list.get(5)); - - System.out.println("【删除指定位置元素】"); - list.removeLast(); - list.printAll(); - list.remove(new Integer(999)); - list.printAll(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" deleted file mode 100644 index b3ba9ec..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\215\225\351\223\276\350\241\250\347\244\272\344\276\213.java" +++ /dev/null @@ -1,185 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.demo; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-01-26 - */ -public class 单链表示例 { - - /** 头节点 */ - private ListNode head; - - public 单链表示例() { - this.head = new ListNode<>(null, null); - } - - public 单链表示例(ListNode head) { - this.head = head; - } - - /** - * 头插法 - * - * @param value 数据值 - */ - public void addFirst(E value) { - ListNode newNode = new ListNode<>(value, null); - newNode.next = this.head.next; - this.head.next = newNode; - } - - /** - * 尾插法 - * - * @param value 数据值 - */ - public void addLast(E value) { - // init new node - ListNode newNode = new ListNode<>(value, null); - - // find the last node - ListNode node = this.head; - while (node.next != null) { - node = node.next; - } - - // add new node to tail - node.next = newNode; - } - - public void remove(ListNode node) { - ListNode prev = this.head; - while (prev.next != null) { - ListNode curr = prev.next; - if (curr == node) { - prev.next = curr.next; - } - prev = prev.next; - } - } - - /** - * 删除首个值为 value 的节点 - * - * @param value 数据值 - * @return {@link ListNode} - */ - public E removeFirst(E value) { - ListNode prev = this.head; - while (prev.next != null) { - ListNode curr = prev.next; - if (curr.value.equals(value)) { - prev.next = curr.next; - return curr.value; - } - prev = prev.next; - } - return null; - } - - /** - * 删除所有值为 value 的节点 - *

- * 示例: - *

-     * 输入: 1->2->6->3->4->5->6, val = 6
-     * 输出: 1->2->3->4->5
-     * 
- * - * @see 移除链表元素 - */ - public void removeAll(E val) { - if (head.next == null) { - return; - } - - ListNode root = head; - ListNode prev = root; - while (prev != null && prev.next != null) { - if (prev.next.value.equals(val)) { - prev.next = prev.next.next; - } else { - prev = prev.next; - } - } - - head = root; - } - - /** - * 清空除头节点以外的所有节点 - */ - public void clear() { - if (head != null) { - head.next = null; - } - } - - /** - * find element - *

- * 从头开始查找,一旦发现有数值与查找值相等的节点,直接返回此节点。如果遍历结束,表明未找到节点,返回 null。 - * - * @param value 数据值 - * @return {@link ListNode} - */ - public ListNode find(E value) { - ListNode node = this.head.next; - while (node != null) { - if (node.value.equals(value)) { - return node; - } - node = node.next; - } - return null; - } - - /** - * 反转链表 算法实现 - * - * @see 反转链表 - */ - public ListNode reverse() { - if (head == null) { - return null; - } - - ListNode prev = null; - ListNode curr = head; - while (curr != null) { - ListNode temp = curr.next; - curr.next = prev; - prev = curr; - curr = temp; - } - return prev; - } - - public List toList() { - List list = new ArrayList<>(); - ListNode node = head.next; - while (node != null) { - list.add(node.value); - node = node.next; - } - return list; - } - - private static class ListNode { - - E value; - - /** point to next node */ - ListNode next; - - public ListNode(E value, ListNode next) { - this.value = value; - this.next = next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" deleted file mode 100644 index f6db8af..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/demo/\345\217\214\351\223\276\350\241\250\347\244\272\344\276\213.java" +++ /dev/null @@ -1,132 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.demo; - -/** - * @author Zhang Peng - * @since 2020-01-26 - */ -public class 双链表示例 { - - /** 头节点 */ - private DListNode head; - - /** 尾节点 */ - private DListNode tail; - - public 双链表示例() { - this.head = new DListNode<>(); - this.tail = new DListNode<>(); - - this.head.value = null; - this.head.prev = null; - this.head.next = this.tail; - - this.tail.value = null; - this.tail.prev = this.head; - this.tail.next = null; - } - - private static class DListNode { - - E value; - - DListNode prev; - - DListNode next; - - DListNode() {} - - DListNode(DListNode prev, E value, DListNode next) { - this.value = value; - this.next = next; - this.prev = prev; - } - - } - - /** - * 头插法 - * - * @param value 数据值 - */ - public void addHead(E value) { - DListNode newNode = new DListNode<>(null, value, null); - - this.head.next.prev = newNode; - newNode.next = this.head.next; - - this.head.next = newNode; - newNode.prev = this.head; - } - - /** - * 尾插法 - * - * @param value 数据值 - */ - public void addTail(E value) { - DListNode newNode = new DListNode<>(null, value, null); - - this.tail.prev.next = newNode; - newNode.prev = this.tail.prev; - - this.tail.prev = newNode; - newNode.next = this.tail; - } - - /** - * 删除节点 - * - * @param value 数据值 - */ - public void remove(E value) { - DListNode prev = this.head; - while (prev.next != this.tail) { - DListNode curr = prev.next; - if (curr.value.equals(value)) { - prev.next = curr.next; - curr.next.prev = prev; - curr.next = null; - curr.prev = null; - break; - } - prev = prev.next; - } - } - - /** - * 查找节点 - * - * @param value 数据值 - */ - public DListNode find(E value) { - DListNode node = this.head.next; - while (node != this.tail) { - if (node.value.equals(value)) { - return node; - } - node = node.next; - } - return null; - } - - public void printList() { - DListNode node = this.head.next; - while (node != this.tail) { - System.out.println(node.value); - node = node.next; - } - } - - public static void main(String[] args) { - 双链表示例 list = new 双链表示例<>(); - list.addTail(2); - list.addTail(3); - list.addHead(1); - - list.remove(1); - System.out.println("list.find(1) = " + list.find(1)); - System.out.println("list.find(2) = " + list.find(2)); - list.printList(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" deleted file mode 100644 index 9c6a30e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/divide/\346\216\222\345\272\217\351\223\276\350\241\250.java" +++ /dev/null @@ -1,72 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.divide; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 148.排序链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 排序链表 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(ListNode.buildList(1, 2, 3, 4), s.sortList(ListNode.buildList(4, 2, 1, 3))); - Assertions.assertEquals(ListNode.buildList(-1, 0, 3, 4, 5), s.sortList(ListNode.buildList(-1, 5, 3, 4, 0))); - Assertions.assertEquals(ListNode.buildList(), s.sortList(ListNode.buildList())); - } - - public static class Solution { - - public ListNode sortList(ListNode head) { - // 如果链表为空或者只有一个节点,无需排序 - if (head == null || head.next == null) { - return head; - } - // 找到中间节点 head2,并断开 head2 与其前一个节点的连接 - // 比如 head=[4,2,1,3],那么 middleNode 调用结束后 head=[4,2] head2=[1,3] - ListNode mid = middleNode(head); - // 分治 - head = sortList(head); - mid = sortList(mid); - // 合并 - return mergeTwoLists(head, mid); - } - - // 876. 链表的中间结点(快慢指针) - private ListNode middleNode(ListNode head) { - ListNode pre = head; - ListNode slow = head; - ListNode fast = head; - while (fast != null && fast.next != null) { - pre = slow; // 记录 slow 的前一个节点 - slow = slow.next; - fast = fast.next.next; - } - pre.next = null; // 断开 slow 的前一个节点和 slow 的连接 - return slow; - } - - // 21. 合并两个有序链表(双指针) - private ListNode mergeTwoLists(ListNode list1, ListNode list2) { - ListNode dummy = new ListNode(-1); // 用哨兵节点简化代码逻辑 - ListNode cur = dummy; // cur 指向新链表的末尾 - while (list1 != null && list2 != null) { - if (list1.val < list2.val) { - cur.next = list1; // 把 list1 加到新链表中 - list1 = list1.next; - } else { // 注:相等的情况加哪个节点都是可以的 - cur.next = list2; // 把 list2 加到新链表中 - list2 = list2.next; - } - cur = cur.next; - } - cur.next = list1 != null ? list1 : list2; // 拼接剩余链表 - return dummy.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" deleted file mode 100644 index dd4a500..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/palindrome/\345\233\236\346\226\207\351\223\276\350\241\250.java" +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.palindrome; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 234. 回文链表 - * 面试题 02.06. 回文链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 回文链表 { - - public static void main(String[] args) { - Solution s = new Solution(); - ListNode input = ListNode.buildList(1, 2, 2, 1); - Assertions.assertTrue(s.isPalindrome(input)); - ListNode input2 = ListNode.buildList(1, 2); - Assertions.assertFalse(s.isPalindrome(input2)); - } - - static class Solution { - - public boolean isPalindrome(ListNode head) { - List list = new ArrayList<>(); - ListNode p = head; - while (p != null) { - list.add(p.val); - p = p.next; - } - - int left = 0, right = list.size() - 1; - while (left < right) { - if (!list.get(left).equals(list.get(right))) { - return false; - } - left++; - right--; - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" deleted file mode 100644 index 18143c9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/K\344\270\252\344\270\200\347\273\204\347\277\273\350\275\254\351\223\276\350\241\250.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.reverse; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 25. K 个一组翻转链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class K个一组翻转链表 { - - public static void main(String[] args) { - Solution s = new Solution(); - ListNode output = s.reverseKGroup(ListNode.buildList(1, 2, 3, 4, 5), 2); - Assertions.assertEquals(ListNode.buildList(2, 1, 4, 3, 5), output); - ListNode output2 = s.reverseKGroup(ListNode.buildList(1, 2, 3, 4, 5), 3); - Assertions.assertEquals(ListNode.buildList(3, 2, 1, 4, 5), output2); - } - - static class Solution { - - public ListNode reverseKGroup(ListNode head, int k) { - if (head == null || head.next == null) { return head; } - ListNode p = head; - for (int i = 0; i < k; i++) { - if (p == null) { return head; } - p = p.next; - } - ListNode newHead = reverseN(head, k); - head.next = reverseKGroup(p, k); - return newHead; - } - - public ListNode reverseN(ListNode head, int len) { - if (head == null) { return null; } - ListNode pre = null, cur = head; - for (int i = 0; i < len; i++) { - if (cur == null) { break; } - ListNode next = cur.next; - cur.next = pre; - pre = cur; - cur = next; - } - head.next = cur; - return pre; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\250.java" deleted file mode 100644 index ac54c4c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\250.java" +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.reverse; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 206. 反转链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 反转链表 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - ListNode result = s.reverseList(ListNode.buildList(1, 2, 3, 4)); - Assertions.assertEquals(ListNode.buildList(4, 3, 2, 1), result); - - ListNode result2 = s.reverseList(ListNode.buildList(1, 2)); - Assertions.assertEquals(ListNode.buildList(2, 1), result2); - - ListNode result3 = s.reverseList(ListNode.buildList()); - Assertions.assertEquals(ListNode.buildList(), result3); - } - - static class Solution { - - public ListNode reverseList(ListNode head) { - if (head == null || head.next == null) { return head; } - ListNode pre = null, cur = head; - while (cur != null) { - ListNode next = cur.next; - cur.next = pre; - pre = cur; - cur = next; - } - return pre; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" deleted file mode 100644 index 74aca5d..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\345\217\215\350\275\254\351\223\276\350\241\2502.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.reverse; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 92. 反转链表 II - * - * @author Zhang Peng - * @date 2025-01-20 - */ -public class 反转链表2 { - - public static void main(String[] args) { - Solution s = new Solution(); - ListNode result = s.reverseBetween(ListNode.buildList(1, 2, 3, 4, 5), 2, 4); - Assertions.assertEquals(ListNode.buildList(1, 4, 3, 2, 5), result); - ListNode result2 = s.reverseBetween(ListNode.buildList(3, 5), 1, 2); - Assertions.assertEquals(ListNode.buildList(5, 3), result2); - } - - static class Solution { - - public ListNode reverseBetween(ListNode head, int m, int n) { - if (m == 1) { - return reverseN(head, n); - } - // 找到第 m 个节点的前驱 - ListNode pre = head; - for (int i = 1; i < m - 1; i++) { - pre = pre.next; - } - // 从第 m 个节点开始反转 - pre.next = reverseN(pre.next, n - m + 1); - return head; - } - - ListNode reverseN(ListNode head, int n) { - if (head == null || head.next == null) { - return head; - } - ListNode pre, cur, nxt; - pre = null; - cur = head; - nxt = head.next; - while (n > 0) { - cur.next = pre; - pre = cur; - cur = nxt; - if (nxt != null) { - nxt = nxt.next; - } - n--; - } - // 此时的 cur 是第 n + 1 个节点,head 是反转后的尾结点 - head.next = cur; - - // 此时的 pre 是反转后的头结点 - return pre; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\346\227\213\350\275\254\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\346\227\213\350\275\254\351\223\276\350\241\250.java" deleted file mode 100644 index a27b82a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/reverse/\346\227\213\350\275\254\351\223\276\350\241\250.java" +++ /dev/null @@ -1,82 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.reverse; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 61. 旋转链表 - * - * @author Zhang Peng - * @since 2025-11-20 - */ -public class 旋转链表 { - - public static void main(String[] args) { - Solution s = new Solution(); - - ListNode input = ListNode.buildList(1, 2, 3, 4, 5); - ListNode output = s.rotateRight(input, 2); - Assertions.assertEquals(ListNode.buildList(4, 5, 1, 2, 3), output); - - ListNode input2 = ListNode.buildList(0, 1, 2); - ListNode output2 = s.rotateRight(input2, 4); - Assertions.assertEquals(ListNode.buildList(2, 0, 1), output2); - - ListNode input3 = ListNode.buildList(1, 2); - ListNode output3 = s.rotateRight(input3, 1); - Assertions.assertEquals(ListNode.buildList(2, 1), output3); - - ListNode input4 = ListNode.buildList(1, 2); - ListNode output4 = s.rotateRight(input4, 3); - Assertions.assertEquals(ListNode.buildList(2, 1), output4); - } - - static class Solution { - - public ListNode rotateRight(ListNode head, int k) { - if (head == null || head.next == null) { - return head; - } - - ListNode dummy = new ListNode(-1); - dummy.next = head; - - ListNode newLast = lastFromEnd(head, k + 1); - ListNode last = newLast; - while (last.next != null) { - last = last.next; - } - - last.next = head; - dummy.next = newLast.next; - newLast.next = null; - - return dummy.next; - } - - public ListNode lastFromEnd(ListNode head, int k) { - - if (head == null || head.next == null) { - return null; - } - - int i = 0; - ListNode slow = head, fast = head; - while (i < k) { - i++; - if (fast == null) { - fast = head; - } - fast = fast.next; - } - - // fast 先走 k 步后,slow 从 head 开始出发,当 fast 到底,slow 正好是倒数第 k 个节点 - while (fast != null) { - slow = slow.next; - fast = fast.next; - } - return slow; - } - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\240.java" deleted file mode 100644 index 69de0e0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\240.java" +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 2. 两数相加 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 两数相加 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - ListNode output1 = s.addTwoNumbers(ListNode.buildList(2, 4, 3), ListNode.buildList(5, 6, 4)); - Assertions.assertEquals(ListNode.buildList(7, 0, 8), output1); - - ListNode output2 = s.addTwoNumbers(ListNode.buildList(0), ListNode.buildList(0)); - Assertions.assertEquals(ListNode.buildList(0), output2); - - ListNode output3 = s.addTwoNumbers(ListNode.buildList(9, 9, 9, 9, 9, 9, 9), ListNode.buildList(9, 9, 9, 9)); - Assertions.assertEquals(ListNode.buildList(8, 9, 9, 9, 0, 0, 0, 1), output3); - } - - static class Solution { - - public ListNode addTwoNumbers(ListNode l1, ListNode l2) { - // 在两条链表上的指针 - ListNode p1 = l1, p2 = l2; - // 虚拟头结点(构建新链表时的常用技巧) - ListNode dummy = new ListNode(-1); - // 指针 p 负责构建新链表 - ListNode p = dummy; - // 记录进位 - int carry = 0; - // 开始执行加法,两条链表走完且没有进位时才能结束循环 - while (p1 != null || p2 != null || carry > 0) { - - int val = 0; - if (p1 != null) { - val += p1.val; - p1 = p1.next; - } - if (p2 != null) { - val += p2.val; - p2 = p2.next; - } - if (carry > 0) { - val += carry; - } - - carry = val / 10; - val = val % 10; - p.next = new ListNode(val); - p = p.next; - } - return dummy.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\2402.java" deleted file mode 100644 index 445b9d7..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\344\270\244\346\225\260\347\233\270\345\212\2402.java" +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 445. 两数相加 II - * - * @author Zhang Peng - * @date 2025-01-21 - */ -public class 两数相加2 { - - public static void main(String[] args) { - Solution s = new Solution(); - ListNode result = s.addTwoNumbers(ListNode.buildList(7, 2, 4, 3), ListNode.buildList(5, 6, 4)); - Assertions.assertEquals(ListNode.buildList(7, 8, 0, 7), result); - ListNode result2 = s.addTwoNumbers(ListNode.buildList(2, 4, 3), ListNode.buildList(5, 6, 4)); - Assertions.assertEquals(ListNode.buildList(8, 0, 7), result2); - ListNode result3 = s.addTwoNumbers(ListNode.buildList(0), ListNode.buildList(0)); - Assertions.assertEquals(ListNode.buildList(0), result3); - } - - public static class Solution { - - public ListNode addTwoNumbers(ListNode l1, ListNode l2) { - ListNode r1 = reverse(l1); - ListNode r2 = reverse(l2); - ListNode res = doAddTwoNumbers(r1, r2); - return reverse(res); - } - - public ListNode reverse(ListNode head) { - ListNode pre = null, cur = head; - while (cur != null) { - ListNode next = cur.next; - cur.next = pre; - pre = cur; - cur = next; - } - return pre; - } - - public ListNode doAddTwoNumbers(ListNode l1, ListNode l2) { - // 在两条链表上的指针 - ListNode p1 = l1, p2 = l2; - // 虚拟头结点(构建新链表时的常用技巧) - ListNode dummy = new ListNode(-1); - // 指针 p 负责构建新链表 - ListNode p = dummy; - // 记录进位 - int carry = 0; - // 开始执行加法,两条链表走完且没有进位时才能结束循环 - while (p1 != null || p2 != null || carry > 0) { - - int val = 0; - if (p1 != null) { - val += p1.val; - p1 = p1.next; - } - if (p2 != null) { - val += p2.val; - p2 = p2.next; - } - if (carry > 0) { - val += carry; - } - - carry = val / 10; - val = val % 10; - p.next = new ListNode(val); - p = p.next; - } - return dummy.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\206\351\232\224\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\206\351\232\224\351\223\276\350\241\250.java" deleted file mode 100644 index 2ab09c3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\206\351\232\224\351\223\276\350\241\250.java" +++ /dev/null @@ -1,101 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 86. 分隔链表 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 分隔链表 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - Assertions.assertEquals(ListNode.buildList(1, 2, 2, 4, 3, 5), - s.partition(ListNode.buildList(1, 4, 3, 2, 5, 2), 3)); - Assertions.assertEquals(ListNode.buildList(1, 2), s.partition(ListNode.buildList(2, 1), 2)); - Assertions.assertEquals(ListNode.buildList(1, 2, 3), s.partition(ListNode.buildList(3, 1, 2), 3)); - Assertions.assertEquals(ListNode.buildList(1, 0, 4, 3, 5, 2), - s.partition(ListNode.buildList(1, 4, 3, 0, 5, 2), 2)); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(ListNode.buildList(1, 2, 2, 4, 3, 5), - s2.partition(ListNode.buildList(1, 4, 3, 2, 5, 2), 3)); - Assertions.assertEquals(ListNode.buildList(1, 2), s2.partition(ListNode.buildList(2, 1), 2)); - Assertions.assertEquals(ListNode.buildList(1, 2, 3), s2.partition(ListNode.buildList(3, 1, 2), 3)); - Assertions.assertEquals(ListNode.buildList(1, 0, 4, 3, 5, 2), - s2.partition(ListNode.buildList(1, 4, 3, 0, 5, 2), 2)); - } - - static class Solution { - - public ListNode partition(ListNode head, int x) { - - if (head == null) { return null; } - - ListNode dummy = new ListNode(-1); - dummy.next = head; - - // 找到大于等于 x 的节点的前一个节点 - ListNode l = dummy, r = dummy.next; - while (r != null) { - - while (l.next != null && l.next.val < x) { - l = l.next; - } - if (l.next == null) { - break; - } - - r = l.next; - while (r.next != null && r.next.val >= x) { - r = r.next; - } - if (r.next == null) { - break; - } - - // 替换节点 - ListNode tmp = r.next; - r.next = tmp.next; - tmp.next = l.next; - l.next = tmp; - - l = l.next; - r = r.next; - } - - return dummy.next; - } - - } - - static class Solution2 { - - public ListNode partition(ListNode head, int x) { - ListNode dummy1 = new ListNode(-1); - ListNode dummy2 = new ListNode(-1); - - ListNode d1 = dummy1, d2 = dummy2, p = head; - while (p != null) { - if (p.val < x) { - d1.next = p; - d1 = d1.next; - } else { - d2.next = p; - d2 = d2.next; - } - p = p.next; - } - d2.next = null; - d1.next = dummy2.next; - return dummy1.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" deleted file mode 100644 index 8d17469..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\240.java" +++ /dev/null @@ -1,36 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 83. 删除排序链表中的重复元素 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 删除排序链表中的重复元素 { - - public static void main(String[] args) { - Solution s = new Solution(); - ListNode input = ListNode.buildList(1, 1, 2); - Assertions.assertEquals(ListNode.buildList(1, 2), s.deleteDuplicates(input)); - ListNode input2 = ListNode.buildList(1, 1, 2, 3, 3); - Assertions.assertEquals(ListNode.buildList(1, 2, 3), s.deleteDuplicates(input2)); - } - - static class Solution { - - public ListNode deleteDuplicates(ListNode head) { - ListNode pre = head, cur = head.next; - while (cur != null) { - pre.next = cur.next; - pre = cur; - cur = cur.next; - } - return head; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\2402.java" deleted file mode 100644 index 94cc3af..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\346\216\222\345\272\217\351\223\276\350\241\250\344\270\255\347\232\204\351\207\215\345\244\215\345\205\203\347\264\2402.java" +++ /dev/null @@ -1,62 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 82. 删除排序链表中的重复元素 II - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 删除排序链表中的重复元素2 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - ListNode input = ListNode.buildList(1, 2, 3, 3, 4, 4, 5); - Assertions.assertEquals(ListNode.buildList(1, 2, 5), s.deleteDuplicates(input)); - - ListNode input2 = ListNode.buildList(1, 1, 1, 2, 3); - Assertions.assertEquals(ListNode.buildList(2, 3), s.deleteDuplicates(input2)); - - ListNode input3 = ListNode.buildList(1, 2, 2); - Assertions.assertEquals(ListNode.buildList(1), s.deleteDuplicates(input3)); - } - - public static class Solution { - - public ListNode deleteDuplicates(ListNode head) { - // 将原链表分解为两条链表 - // 一条链表存放不重复的节点,另一条链表存放重复的节点 - // 运用虚拟头结点技巧,题目说了 node.val <= 100,所以用 101 作为虚拟头结点 - ListNode dummyUniq = new ListNode(101); - ListNode dummyDup = new ListNode(101); - - ListNode pUniq = dummyUniq, pDup = dummyDup; - ListNode p = head; - - while (p != null) { - if ((p.next != null && p.val == p.next.val) || p.val == pDup.val) { - // 发现重复节点,接到重复链表后面 - pDup.next = p; - pDup = pDup.next; - } else { - // 不是重复节点,接到不重复链表后面 - pUniq.next = p; - pUniq = pUniq.next; - } - - p = p.next; - // 将原链表和新链表断开 - pUniq.next = null; - pDup.next = null; - } - - return dummyUniq.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" deleted file mode 100644 index d3e6e42..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\347\273\223\347\202\271.java" +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 19. 删除链表的倒数第 N 个结点 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 删除链表的倒数第N个结点 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - ListNode input1 = ListNode.buildList(1, 2, 3, 4, 5); - ListNode output1 = s.removeNthFromEnd(input1, 2); - Assertions.assertEquals(ListNode.buildList(1, 2, 3, 5), output1); - - ListNode input2 = ListNode.buildList(1); - ListNode output2 = s.removeNthFromEnd(input2, 1); - Assertions.assertEquals(ListNode.buildList(), output2); - - ListNode input3 = ListNode.buildList(1, 2); - ListNode output3 = s.removeNthFromEnd(input3, 1); - Assertions.assertEquals(ListNode.buildList(1), output3); - } - - static class Solution { - - public ListNode removeNthFromEnd(ListNode head, int n) { - ListNode dummy = new ListNode(-1); - dummy.next = head; - ListNode node = findFromEnd(dummy, n + 1); - node.next = node.next.next; - return dummy.next; - } - - public ListNode findFromEnd(ListNode head, int k) { - ListNode p1 = head; - // p1 先走 k 步 - for (int i = 0; i < k; i++) { - p1 = p1.next; - } - ListNode p2 = head; - // p1 和 p2 同时走 n - k 步 - while (p1 != null) { - p2 = p2.next; - p1 = p1.next; - } - // p2 现在指向第 n - k + 1 个节点,即倒数第 k 个节点 - return p2; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" deleted file mode 100644 index 419f5e2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266K\344\270\252\345\215\207\345\272\217\351\223\276\350\241\250.java" +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 23. 合并 K 个升序链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 合并K个升序链表 { - - public static void main(String[] args) { - - Solution s = new Solution(); - ListNode head1 = ListNode.buildList(1, 4, 5); - ListNode head2 = ListNode.buildList(1, 3, 4); - ListNode head3 = ListNode.buildList(2, 6); - ListNode result = s.mergeKLists(new ListNode[] { head1, head2, head3 }); - Assertions.assertEquals(ListNode.buildList(1, 1, 2, 3, 4, 4, 5, 6), result); - - ListNode[] array2 = new ListNode[] {}; - ListNode result2 = s.mergeKLists(array2); - Assertions.assertEquals(ListNode.buildList(), result2); - } - - static class Solution { - - public ListNode mergeKLists(ListNode[] lists) { - if (lists == null || lists.length == 0) return null; - ListNode l1 = lists[0]; - for (int i = 1; i < lists.length; i++) { - ListNode l2 = lists[i]; - l1 = mergeTwoLists(l1, l2); - } - return l1; - } - - public ListNode mergeTwoLists(ListNode l1, ListNode l2) { - // 虚拟头结点 - ListNode dummy = new ListNode(-1), p = dummy; - ListNode p1 = l1, p2 = l2; - - while (p1 != null && p2 != null) { - // 比较 p1 和 p2 两个指针 - // 将值较小的的节点接到 p 指针 - if (p1.val > p2.val) { - p.next = p2; - p2 = p2.next; - } else { - p.next = p1; - p1 = p1.next; - } - // p 指针不断前进 - p = p.next; - } - - if (p1 != null) { p.next = p1; } - if (p2 != null) { p.next = p2; } - - return dummy.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" deleted file mode 100644 index 8da3bd1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.java" +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 21. 合并两个有序链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 合并两个有序链表 { - - public static void main(String[] args) { - Solution s = new Solution(); - ListNode h1 = ListNode.buildList(1, 2, 4); - ListNode h2 = ListNode.buildList(1, 3, 4); - ListNode result = s.mergeTwoLists(h1, h2); - Assertions.assertEquals(ListNode.buildList(1, 1, 2, 3, 4, 4), result); - } - - static class Solution { - - public ListNode mergeTwoLists(ListNode l1, ListNode l2) { - // 虚拟头结点 - ListNode dummy = new ListNode(-1), p = dummy; - ListNode p1 = l1, p2 = l2; - - while (p1 != null && p2 != null) { - // 比较 p1 和 p2 两个指针 - // 将值较小的的节点接到 p 指针 - if (p1.val > p2.val) { - p.next = p2; - p2 = p2.next; - } else { - p.next = p1; - p1 = p1.next; - } - // p 指针不断前进 - p = p.next; - } - - if (p1 != null) { p.next = p1; } - if (p2 != null) { p.next = p2; } - - return dummy.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\245\207\345\201\266\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\245\207\345\201\266\351\223\276\350\241\250.java" deleted file mode 100644 index 5d3c5be..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\345\245\207\345\201\266\351\223\276\350\241\250.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 328. 奇偶链表 - * - * @author Zhang Peng - * @since 2020-07-08 - */ -public class 奇偶链表 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(ListNode.buildList(1, 3, 5, 2, 4), s.oddEvenList(ListNode.buildList(1, 2, 3, 4, 5))); - Assertions.assertEquals(ListNode.buildList(2, 3, 6, 7, 1, 5, 4), - s.oddEvenList(ListNode.buildList(2, 1, 3, 5, 6, 4, 7))); - } - - static class Solution { - - public ListNode oddEvenList(ListNode head) { - ListNode oddDummy = new ListNode(-1); - ListNode evenDummy = new ListNode(-1); - ListNode p = head, o = oddDummy, e = evenDummy; - int i = 1; - while (p != null) { - if (i % 2 == 0) { - e.next = p; - e = e.next; - } else { - o.next = p; - o = o.next; - } - p = p.next; - i++; - } - e.next = null; - o.next = evenDummy.next; - return oddDummy.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\250.java" deleted file mode 100644 index f73021e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\250.java" +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 141. 环形链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 环形链表 { - - public static void main(String[] args) { - - Solution s = new Solution(); - ListNode head = ListNode.buildList(3, 2, 0, -4); - Assertions.assertFalse(s.hasCycle(head)); - - ListNode head2 = ListNode.buildCycleList(1, new int[] { 3, 2, 0, -4 }); - Assertions.assertTrue(s.hasCycle(head2)); - - ListNode head3 = ListNode.buildCycleList(0, new int[] { 1, 2 }); - Assertions.assertTrue(s.hasCycle(head3)); - - ListNode head4 = ListNode.buildCycleList(1, new int[] { 1 }); - Assertions.assertFalse(s.hasCycle(head4)); - } - - static class Solution { - - public boolean hasCycle(ListNode head) { - // 快慢指针初始化指向 head - ListNode slow = head, fast = head; - // 快指针走到末尾时停止 - while (fast != null && fast.next != null) { - // 慢指针走一步,快指针走两步 - slow = slow.next; - fast = fast.next.next; - // 快慢指针相遇,说明含有环 - if (slow == fast) { - return true; - } - } - return false; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\2502.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\2502.java" deleted file mode 100644 index 1c6abd9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\216\257\345\275\242\351\223\276\350\241\2502.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 142. 环形链表 II - * - * @author Zhang Peng - * @since 2020-07-08 - */ -public class 环形链表2 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - ListNode input = ListNode.buildList(3, 2, 0, -4); - Assertions.assertNull(s.detectCycle(input)); - - ListNode input2 = ListNode.buildList(1); - Assertions.assertNull(s.detectCycle(input2)); - - ListNode input3 = ListNode.buildCycleList(1, new int[] { 3, 2, 0, -4 }); - Assertions.assertEquals(2, s.detectCycle(input3).val); - - ListNode input4 = ListNode.buildCycleList(0, new int[] { 1, 2 }); - Assertions.assertEquals(1, s.detectCycle(input4).val); - } - - static class Solution { - - public ListNode detectCycle(ListNode head) { - ListNode fast, slow; - fast = slow = head; - while (fast != null && fast.next != null) { - fast = fast.next.next; - slow = slow.next; - if (fast == slow) break; - } - - // fast 遇到空指针说明没有环 - if (fast == null || fast.next == null) { - return null; - } - - // 重新指向头结点 - slow = head; - - // 快慢指针同步前进,相交点就是环起点 - while (slow != fast) { - fast = fast.next; - slow = slow.next; - } - return slow; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\233\270\344\272\244\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\233\270\344\272\244\351\223\276\350\241\250.java" deleted file mode 100644 index e222dfe..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\233\270\344\272\244\351\223\276\350\241\250.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 相交链表 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 相交链表 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - ListNode listA = ListNode.buildList(4, 1, 8, 4, 5); - ListNode listB = ListNode.buildList(5, 6, 1, 8, 4, 5); - ListNode.buildMetPot(listA, listB, 2, 3); - ListNode result = s.getIntersectionNode(listA, listB); - Assertions.assertEquals(8, result.val); - - ListNode listA2 = ListNode.buildList(1, 9, 1, 2, 4); - ListNode listB2 = ListNode.buildList(3, 2, 4); - ListNode.buildMetPot(listA2, listB2, 3, 1); - ListNode result2 = s.getIntersectionNode(listA2, listB2); - Assertions.assertEquals(2, result2.val); - - ListNode listA3 = ListNode.buildList(2, 6, 4); - ListNode listB3 = ListNode.buildList(1, 5); - ListNode result3 = s.getIntersectionNode(listA3, listB3); - Assertions.assertNull(result3); - } - - static class Solution { - - public ListNode getIntersectionNode(ListNode headA, ListNode headB) { - // pA 指向 A 链表头结点,pB 指向 B 链表头结点 - ListNode pA = headA, pB = headB; - while (pA != pB) { - // pA 走一步,如果走到 A 链表末尾,转到 B 链表 - if (pA == null) { - pA = headB; - } else { - pA = pA.next; - } - // pB 走一步,如果走到 B 链表末尾,转到 A 链表 - if (pB == null) { - pB = headA; - } else { - pB = pB.next; - } - } - return pA; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" deleted file mode 100644 index 0bba21c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\207\215\345\244\215\350\212\202\347\202\271.java" +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -import java.util.HashSet; -import java.util.Set; - -/** - * 面试题 02.01. 移除重复节点 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 移除重复节点 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(ListNode.buildList(1, 2, 3), - s.removeDuplicateNodes(ListNode.buildList(1, 2, 3, 3, 2, 1))); - Assertions.assertEquals(ListNode.buildList(1, 2), - s.removeDuplicateNodes(ListNode.buildList(1, 1, 1, 1, 2))); - } - - static class Solution { - - public ListNode removeDuplicateNodes(ListNode head) { - Set set = new HashSet<>(); - ListNode dummy = new ListNode(-1); - ListNode p = head, n = dummy; - while (p != null) { - if (!set.contains(p.val)) { - n.next = p; - n = n.next; - set.add(p.val); - } - p = p.next; - } - n.next = null; - return dummy.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" deleted file mode 100644 index 6cb6000..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 203. 移除链表元素 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 移除链表元素 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(ListNode.buildList(1, 2, 3, 4, 5), - s.removeElements(ListNode.buildList(1, 2, 6, 3, 4, 5, 6), 6)); - Assertions.assertEquals(ListNode.buildList(), s.removeElements(ListNode.buildList(), 1)); - Assertions.assertEquals(ListNode.buildList(), s.removeElements(ListNode.buildList(7, 7, 7, 7, 7), 7)); - } - - static class Solution { - - public ListNode removeElements(ListNode head, int val) { - ListNode dummy = new ListNode(0); - ListNode p = head, q = dummy; - while (p != null) { - if (p.val != val) { - q.next = p; - q = q.next; - } - p = p.next; - } - q.next = null; - return dummy.next; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" deleted file mode 100644 index 808ba2b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\350\277\224\345\233\236\345\200\222\346\225\260\347\254\254k\344\270\252\350\212\202\347\202\271.java" +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 面试题 02. 返回倒数第 k 个节点 - * LCR 140. 训练计划 II - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 返回倒数第k个节点 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.kthToLast(ListNode.buildList(1, 2, 3, 4, 5), 2)); - Assertions.assertEquals(1, s.kthToLast(ListNode.buildList(1), 1)); - } - - static class Solution { - - public int kthToLast(ListNode head, int k) { - ListNode slow = head, fast = head; - for (int i = 0; i < k && fast != null; i++) { - fast = fast.next; - } - while (fast != null) { - fast = fast.next; - slow = slow.next; - } - return slow == null ? -1 : slow.val; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" deleted file mode 100644 index f93a67c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/linkedlist/two_pointer/\351\223\276\350\241\250\347\232\204\344\270\255\351\227\264\347\273\223\347\202\271.java" +++ /dev/null @@ -1,35 +0,0 @@ -package io.github.dunwu.algorithm.linkedlist.two_pointer; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -/** - * 876. 链表的中间结点 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 链表的中间结点 { - - public static void main(String[] args) { - Solution s = new Solution(); - ListNode input = ListNode.buildList(1, 2, 3, 4, 5); - Assertions.assertEquals(ListNode.buildList(3, 4, 5), s.middleNode(input)); - ListNode input2 = ListNode.buildList(1, 2, 3, 4, 5, 6); - Assertions.assertEquals(ListNode.buildList(4, 5, 6), s.middleNode(input2)); - } - - static class Solution { - - public ListNode middleNode(ListNode head) { - ListNode slow = head, fast = head; - while (fast != null && fast.next != null) { - slow = slow.next; - fast = fast.next.next; - } - return slow; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\344\270\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\344\270\221\346\225\260.java" deleted file mode 100644 index dace497..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\344\270\221\346\225\260.java" +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.dunwu.algorithm.math; - -import org.junit.jupiter.api.Assertions; - -/** - * 263. 丑数 - * - * @author Zhang Peng - * @date 2025-01-24 - */ -public class 丑数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isUgly(6)); - Assertions.assertTrue(s.isUgly(1)); - Assertions.assertFalse(s.isUgly(14)); - } - - static class Solution { - - public boolean isUgly(int n) { - if (n <= 0) { return false; } - while (n % 2 == 0) { n /= 2; } - while (n % 3 == 0) { n /= 3; } - while (n % 5 == 0) { n /= 5; } - return n == 1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\345\212\240\344\270\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\345\212\240\344\270\200.java" deleted file mode 100644 index 334b604..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/math/\345\212\240\344\270\200.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.math; - -import org.junit.jupiter.api.Assertions; - -/** - * 66. 加一 - * - * @author Zhang Peng - * @since 2018-11-04 - */ -public class 加一 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 1, 2, 4 }, s.plusOne(new int[] { 1, 2, 3 })); - Assertions.assertArrayEquals(new int[] { 4, 3, 2, 2 }, s.plusOne(new int[] { 4, 3, 2, 1 })); - Assertions.assertArrayEquals(new int[] { 1, 0, 0, 0, 0 }, s.plusOne(new int[] { 9, 9, 9, 9 })); - } - - static class Solution { - - public int[] plusOne(int[] digits) { - for (int i = digits.length - 1; i >= 0; i--) { - if (digits[i] == 9) { - digits[i] = 0; - } else { - digits[i]++; - return digits; - } - } - int[] res = new int[digits.length + 1]; - res[0] = 1; - return res; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java deleted file mode 100644 index f75c96b..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/GenericQueue.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.queue; - -/** - * @author Zhang Peng - * @since 2020-06-10 - */ -public class GenericQueue { - - // 队列的队首和队尾 - private Node head = null; - private Node tail = null; - - // 入队 - public void enqueue(T value) { - if (head == null) { - tail = new Node(value, null); - head = tail; - } else { - tail.next = new Node(value, null); - tail = tail.next; - } - } - - // 出队 - public T dequeue() { - if (head == null) { - return null; - } - - T val = head.data; - head = head.next; - if (head == null) { - tail = null; - } - return val; - } - - public void printAll() { - Node p = head; - while (p != null) { - System.out.print(p.data + " "); - p = p.next; - } - System.out.println(); - } - - private static class Node { - - private T data; - private Node next; - - public Node(T data, Node next) { - this.data = data; - this.next = next; - } - - public T getData() { - return data; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" deleted file mode 100644 index f476f99..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\345\212\250\346\200\201\346\211\251\345\256\271\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.queue.demo; - -import java.util.Arrays; - -/** - * Created by wangzheng on 2018/10/9. - */ -public class 动态扩容数组实现的队列 { - - public static void main(String[] args) { - 动态扩容数组实现的队列 queue = new 动态扩容数组实现的队列(3); - queue.enqueue("1"); - queue.enqueue("2"); - queue.enqueue("3"); - queue.enqueue("4"); - queue.printAll(); - System.out.println("dequeue " + queue.dequeue()); - queue.printAll(); - System.out.println("dequeue " + queue.dequeue()); - queue.printAll(); - } - - // 数组:items,数组大小:n - private String[] items; - private int n = 0; - // head表示队头下标,tail表示队尾下标 - private int head = 0; - private int tail = 0; - - // 申请一个大小为capacity的数组 - public 动态扩容数组实现的队列(int capacity) { - items = new String[capacity]; - n = capacity; - } - - // 入队操作,将item放入队尾 - public boolean enqueue(String item) { - // 队列已满,扩容 - if (tail == n) { - n = n * 2; - items = Arrays.copyOf(items, n); - } - - items[tail] = item; - tail++; - return true; - } - - // 出队 - public String dequeue() { - // 如果head == tail 表示队列为空 - if (head == tail) return null; - String val = items[head]; - items = Arrays.copyOfRange(items, 1, tail); - tail--; - return val; - } - - public void printAll() { - for (int i = head; i < tail; ++i) { - System.out.print(items[i] + " "); - } - System.out.println(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" deleted file mode 100644 index 0e321f7..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\346\225\260\347\273\204\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" +++ /dev/null @@ -1,61 +0,0 @@ -package io.github.dunwu.algorithm.queue.demo; - -/** - * 用数组实现的队列 - * Created by wangzheng on 2018/10/9. - */ -public class 数组实现的队列 { - - public static void main(String[] args) { - 数组实现的队列 queue = new 数组实现的队列(3); - queue.enqueue("1"); - queue.enqueue("2"); - queue.enqueue("3"); - queue.enqueue("4"); - queue.printAll(); - System.out.println("dequeue " + queue.dequeue()); - queue.printAll(); - System.out.println("dequeue " + queue.dequeue()); - queue.printAll(); - } - - // 数组:items,数组大小:n - private String[] items; - private int n = 0; - // head表示队头下标,tail表示队尾下标 - private int head = 0; - private int tail = 0; - - // 申请一个大小为capacity的数组 - public 数组实现的队列(int capacity) { - items = new String[capacity]; - n = capacity; - } - - // 入队 - public boolean enqueue(String item) { - // 如果tail == n 表示队列已经满了 - if (tail == n) return false; - items[tail] = item; - ++tail; - return true; - } - - // 出队 - public String dequeue() { - // 如果head == tail 表示队列为空 - if (head == tail) return null; - // 为了让其他语言的同学看的更加明确,把--操作放到单独一行来写了 - String ret = items[head]; - ++head; - return ret; - } - - public void printAll() { - for (int i = head; i < tail; ++i) { - System.out.print(items[i] + " "); - } - System.out.println(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" deleted file mode 100644 index 3117ad2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/demo/\351\223\276\350\241\250\345\256\236\347\216\260\347\232\204\351\230\237\345\210\227.java" +++ /dev/null @@ -1,77 +0,0 @@ -package io.github.dunwu.algorithm.queue.demo; - -/** - * 基于链表实现的队列 - *

- * Author: Zheng - */ -public class 链表实现的队列 { - - public static void main(String[] args) { - 链表实现的队列 queue = new 链表实现的队列(); - queue.enqueue("1"); - queue.enqueue("2"); - queue.enqueue("3"); - queue.enqueue("4"); - queue.printAll(); - System.out.println("dequeue " + queue.dequeue()); - queue.printAll(); - System.out.println("dequeue " + queue.dequeue()); - queue.printAll(); - } - - // 队列的队首和队尾 - private Node head = null; - private Node tail = null; - - // 入队 - public void enqueue(String value) { - if (head == null) { - tail = new Node(value, null); - head = tail; - } else { - tail.next = new Node(value, null); - tail = tail.next; - } - } - - // 出队 - public String dequeue() { - if (head == null) { - return null; - } - - String val = head.data; - head = head.next; - if (head == null) { - tail = null; - } - return val; - } - - public void printAll() { - Node p = head; - while (p != null) { - System.out.print(p.data + " "); - p = p.next; - } - System.out.println(); - } - - private static class Node { - - private String data; - private Node next; - - public Node(String data, Node next) { - this.data = data; - this.next = next; - } - - public String getData() { - return data; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/MonotonicQueue.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/MonotonicQueue.java deleted file mode 100644 index a13cdb2..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/MonotonicQueue.java +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.queue.monotonic; - -import java.util.LinkedList; - -// 单调队列的实现,可以高效维护最大值和最小值 -class MonotonicQueue> { - - // 常规队列,存储所有元素 - LinkedList q = new LinkedList<>(); - // 元素降序排列的单调队列,头部是最大值 - LinkedList maxq = new LinkedList<>(); - // 元素升序排列的单调队列,头部是最小值 - LinkedList minq = new LinkedList<>(); - - public void push(E elem) { - // 维护常规队列,直接在队尾插入元素 - q.addLast(elem); - - // 维护 maxq,将小于 elem 的元素全部删除 - while (!maxq.isEmpty() && maxq.getLast().compareTo(elem) < 0) { - maxq.pollLast(); - } - maxq.addLast(elem); - - // 维护 minq,将大于 elem 的元素全部删除 - while (!minq.isEmpty() && minq.getLast().compareTo(elem) > 0) { - minq.pollLast(); - } - minq.addLast(elem); - } - - public E max() { - // maxq 的头部是最大元素 - return maxq.getFirst(); - } - - public E min() { - // minq 的头部是最大元素 - return minq.getFirst(); - } - - public E pop() { - // 从标准队列头部弹出需要删除的元素 - E deleteVal = q.pollFirst(); - assert deleteVal != null; - - // 由于 push 的时候会删除元素,deleteVal 可能已经被删掉了 - if (deleteVal.equals(maxq.getFirst())) { - maxq.pollFirst(); - } - if (deleteVal.equals(minq.getFirst())) { - minq.pollFirst(); - } - return deleteVal; - } - - public int size() { - // 标准队列的大小即是当前队列的大小 - return q.size(); - } - - public boolean isEmpty() { - return q.isEmpty(); - } - -} \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\346\273\221\345\212\250\347\252\227\345\217\243\346\234\200\345\244\247\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\346\273\221\345\212\250\347\252\227\345\217\243\346\234\200\345\244\247\345\200\274.java" deleted file mode 100644 index 3b9aaf2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\346\273\221\345\212\250\347\252\227\345\217\243\346\234\200\345\244\247\345\200\274.java" +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.dunwu.algorithm.queue.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -/** - * 239. 滑动窗口最大值 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 滑动窗口最大值 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 3, 3, 5, 5, 6, 7 }, - s.maxSlidingWindow(new int[] { 1, 3, -1, -3, 5, 3, 6, 7 }, 3)); - Assertions.assertArrayEquals(new int[] { 1 }, s.maxSlidingWindow(new int[] { 1 }, 1)); - } - - static class Solution { - - public int[] maxSlidingWindow(int[] nums, int k) { - MonotonicQueue window = new MonotonicQueue(); - List res = new ArrayList<>(); - - for (int i = 0; i < nums.length; i++) { - if (i < k - 1) { - window.push(nums[i]); - } else { - window.push(nums[i]); - res.add(window.max()); - window.pop(nums[i - (k - 1)]); - } - } - - int[] arr = new int[res.size()]; - for (int i = 0; i < res.size(); i++) { - arr[i] = res.get(i); - } - return arr; - } - - static class MonotonicQueue { - - LinkedList q = new LinkedList<>(); - - public void push(int n) { - // 将小于 n 的元素全部删除 - while (!q.isEmpty() && q.getLast() < n) { - q.pollLast(); - } - // 然后将 n 加入尾部 - q.addLast(n); - } - - public int max() { - return q.getFirst(); - } - - public void pop(int n) { - if (n == q.getFirst()) { - q.pollFirst(); - } - } - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\350\256\276\350\256\241\350\207\252\345\212\251\347\273\223\347\256\227\347\263\273\347\273\237.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\350\256\276\350\256\241\350\207\252\345\212\251\347\273\223\347\256\227\347\263\273\347\273\237.java" deleted file mode 100644 index 69586cd..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/monotonic/\350\256\276\350\256\241\350\207\252\345\212\251\347\273\223\347\256\227\347\263\273\347\273\237.java" +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.queue.monotonic; - -import org.junit.jupiter.api.Assertions; - -/** - * 739. 每日温度 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 设计自助结算系统 { - - public static void main(String[] args) { - Checkout c = new Checkout(); - c.add(4); - c.add(7); - Assertions.assertEquals(7, c.get_max()); - Assertions.assertEquals(4, c.remove()); - Assertions.assertEquals(7, c.get_max()); - } - - static class Checkout { - - private MonotonicQueue q; - public Checkout() { - q = new MonotonicQueue<>(); - } - - public int get_max() { - return q.isEmpty() ? -1 : q.max(); - } - - public void add(int value) { - q.push(value); - } - - public int remove() { - if (q.isEmpty()) { return -1; } - return q.pop(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\344\271\260\347\245\250\351\234\200\350\246\201\347\232\204\346\227\266\351\227\264.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\344\271\260\347\245\250\351\234\200\350\246\201\347\232\204\346\227\266\351\227\264.java" deleted file mode 100644 index e350c5c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\344\271\260\347\245\250\351\234\200\350\246\201\347\232\204\346\227\266\351\227\264.java" +++ /dev/null @@ -1,36 +0,0 @@ -package io.github.dunwu.algorithm.queue; - -import org.junit.jupiter.api.Assertions; - -/** - * 2073. 买票需要的时间 - * - * @author Zhang Peng - * @since 2025-11-26 - */ -public class 买票需要的时间 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(6, s.timeRequiredToBuy(new int[] { 2, 3, 2 }, 2)); - Assertions.assertEquals(8, s.timeRequiredToBuy(new int[] { 5, 1, 1, 1 }, 0)); - } - - static class Solution { - - public int timeRequiredToBuy(int[] tickets, int k) { - int i = 0; - int seconds = 0; - while (tickets[k] != 0) { - if (tickets[i] != 0) { - tickets[i]--; - seconds++; - } - i = (i + 1) % tickets.length; - } - return seconds; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" deleted file mode 100644 index 00e74d9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\346\234\200\350\277\221\347\232\204\350\257\267\346\261\202\346\254\241\346\225\260.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.queue; - -import java.util.LinkedList; -import java.util.Queue; - -/** - * 933. 最近的请求次数 - * - * @author Zhang Peng - * @since 2020-06-10 - */ -public class 最近的请求次数 { - - public static void main(String[] args) { - RecentCounter recentCounter = new RecentCounter(); - recentCounter.ping(1); // requests = [1],范围是 [-2999,1],返回 1 - recentCounter.ping(100); // requests = [1, 100],范围是 [-2900,100],返回 2 - recentCounter.ping(3001); // requests = [1, 100, 3001],范围是 [1,3001],返回 3 - recentCounter.ping(3002); // requests = [1, 100, 3001, 3002],范围是 [2,3002],返回 3 - } - - static class RecentCounter { - - private Queue queue; - - public RecentCounter() { - queue = new LinkedList<>(); - } - - public int ping(int t) { - queue.offer(t); - while (queue.peek() < t - 3000) { - queue.poll(); - } - return queue.size(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" deleted file mode 100644 index 7628222..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\347\224\250\351\230\237\345\210\227\345\256\236\347\216\260\346\240\210.java" +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.dunwu.algorithm.queue; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.Queue; - -/** - * 225. 用队列实现栈 - * - * @author Zhang Peng - * @since 2020-01-18 - */ -public class 用队列实现栈 { - - public static void main(String[] args) { - MyStack s1 = new MyStack(); - s1.push(1); - s1.push(2); - Assertions.assertEquals(2, s1.top()); - Assertions.assertEquals(2, s1.pop()); - Assertions.assertFalse(s1.empty()); - - int max = 10; - MyStack stack = new MyStack(); - for (int i = 1; i <= max; i++) { - stack.push(i); - } - for (int i = 1; i <= max; i++) { - Assertions.assertEquals(max - i + 1, stack.top()); - Assertions.assertEquals(max - i + 1, stack.pop()); - } - } - - static class MyStack { - - private Integer top; - Queue q; - - public MyStack() { - q = new LinkedList<>(); - } - - public void push(int x) { - q.offer(x); - top = x; - } - - public int pop() { - int size = q.size(); - for (int i = 1; i < size; i++) { - Integer val = q.poll(); - q.offer(val); - top = val; - } - return q.poll(); - } - - public int top() { - return top == null ? 0 : top; - } - - public boolean empty() { - return q.isEmpty(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\345\217\214\347\253\257\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\345\217\214\347\253\257\351\230\237\345\210\227.java" deleted file mode 100644 index 1db2d49..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\256\276\350\256\241\345\276\252\347\216\257\345\217\214\347\253\257\351\230\237\345\210\227.java" +++ /dev/null @@ -1,145 +0,0 @@ -package io.github.dunwu.algorithm.queue; - -/** - * 641. 设计循环双端队列 - * - * @author Zhang Peng - * @since 2020-06-10 - */ -public class 设计循环双端队列 { - - public static void main(String[] args) { - 设计循环双端队列 queue = new 设计循环双端队列(3); - queue.insertFront(1); - queue.insertFront(2); - queue.insertFront(3); - queue.insertFront(4); - queue.printAll(); - queue.deleteFront(); - queue.printAll(); - queue.deleteFront(); - queue.printAll(); - queue.deleteFront(); - queue.printAll(); - - queue.insertLast(1); - queue.insertLast(2); - queue.insertLast(3); - queue.insertLast(4); - queue.printAll(); - queue.deleteLast(); - queue.printAll(); - // System.out.println("rear: " + queue.Rear()); - // System.out.println("full: " + queue.isFull()); - // queue.deQueue(); - // queue.enQueue(4); - // queue.printAll(); - // System.out.println("rear: " + queue.Rear()); - } - - private int[] data; - private int head; - // head表示队头下标,tail表示队尾下标 - private int tail; - private int capacity; - - /** Initialize your data structure here. Set the size of the deque to be k. */ - public 设计循环双端队列(int k) { - this.capacity = k + 1; - this.data = new int[this.capacity]; - } - - /** Adds an item at the front of Deque. Return true if the operation is successful. */ - public boolean insertFront(int value) { - if (isFull()) { - return false; - } - - head = (head - 1 + capacity) % capacity; - data[head] = value; - return true; - } - - /** Adds an item at the rear of Deque. Return true if the operation is successful. */ - public boolean insertLast(int value) { - if (isFull()) { - return false; - } - - this.data[tail] = value; - tail = (tail + 1) % capacity; - return true; - } - - /** Deletes an item from the front of Deque. Return true if the operation is successful. */ - public boolean deleteFront() { - if (isEmpty()) { - return false; - } - - head = (head + 1) % capacity; - return true; - } - - /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ - public boolean deleteLast() { - if (isEmpty()) { - return false; - } - - tail = (tail - 1 + capacity) % capacity; - return true; - } - - /** Get the front item from the deque. */ - public int getFront() { - if (isEmpty()) { - return -1; - } - - return data[head]; - } - - /** Get the last item from the deque. */ - public int getRear() { - if (isEmpty()) { - return -1; - } - - int temp = (tail - 1 + capacity) % capacity; - return data[temp]; - } - - /** Checks whether the circular deque is empty or not. */ - public boolean isEmpty() { - if (head == tail) { - return true; - } - return false; - } - - /** Checks whether the circular deque is full or not. */ - public boolean isFull() { - if ((tail + 1) % capacity == head) { - return true; - } - return false; - } - - public void printAll() { - if (head == tail) { - System.out.println("队列已空"); - return; - } - for (int i = head; i != tail; ) { - System.out.print(data[i] + "\t"); - if (i == capacity - 1) { - i = 0; - } else { - i++; - } - } - System.out.println(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\266\205\347\272\247\344\270\221\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\266\205\347\272\247\344\270\221\346\225\260.java" deleted file mode 100644 index ab5b321..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/\350\266\205\347\272\247\344\270\221\346\225\260.java" +++ /dev/null @@ -1,73 +0,0 @@ -package io.github.dunwu.algorithm.queue; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashSet; -import java.util.PriorityQueue; -import java.util.Set; - -/** - * 313. 超级丑数 - * - * @author Zhang Peng - * @date 2025-01-24 - */ -public class 超级丑数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(32, s.nthSuperUglyNumber(12, new int[] { 2, 7, 13, 19 })); - Assertions.assertEquals(1, s.nthSuperUglyNumber(1, new int[] { 2, 3, 5 })); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(32, s2.nthSuperUglyNumber(12, new int[] { 2, 7, 13, 19 })); - Assertions.assertEquals(1, s2.nthSuperUglyNumber(1, new int[] { 2, 3, 5 })); - } - - // 优先队列(堆)方案 - static class Solution { - - public int nthSuperUglyNumber(int n, int[] primes) { - Set set = new HashSet<>(); - PriorityQueue queue = new PriorityQueue<>(); - set.add(1L); - queue.add(1L); - for (int i = 1; i <= n; i++) { - long curVal = queue.poll(); - if (i == n) { return (int) curVal; } - for (int prime : primes) { - long nextVal = curVal * prime; - if (!set.contains(nextVal)) { - set.add(nextVal); - queue.add(nextVal); - } - } - } - return -1; - } - - } - - // 多路归并方案 - static class Solution2 { - - public int nthSuperUglyNumber(int n, int[] nums) { - int m = nums.length; - PriorityQueue q = new PriorityQueue<>((a, b) -> a[0] - b[0]); - for (int i = 0; i < m; i++) { - q.add(new int[] { nums[i], i, 0 }); - } - int[] dp = new int[n]; - dp[0] = 1; - for (int j = 1; j < n; ) { - int[] poll = q.poll(); - int num = poll[0], i = poll[1], idx = poll[2]; - if (num != dp[j - 1]) dp[j++] = num; - q.add(new int[] { dp[idx + 1] * nums[i], i, idx + 1 }); - } - return dp[n - 1]; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/HashDemo.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/HashDemo.java deleted file mode 100644 index 30f43e1..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/HashDemo.java +++ /dev/null @@ -1,163 +0,0 @@ -package io.github.dunwu.algorithm.search; - -/** - * 为了精简示例代码,所有参数都用 public - */ -@SuppressWarnings("all") -class HashTable { - - public int key = 0; // 关键字 - - public int data = 0; // 数值 - - public int count = 0; // 探查次数 - -} - -/** - * Hash 表查找示例 - * - * @author Zhang Peng - */ -public class HashDemo { - - private final static int MAXSIZE = 13; - - private final static int MODULO = 13; - - private final static int NULLKEY = 1; - - private final static int DELKEY = 2; - - private final static int SUCCESS = 0; - - private final static int FAILED = 0xFFFFFFFF; - - public static void main(String[] args) { - // int[] list = {3, 112, 245, 27, 44, 19, 76, 29, 90} - int[] list = { 1, 9, 25, 11, 12, 35, 17, 29 }; - HashTable[] ha = new HashTable[MAXSIZE]; - for (int i = 0; i < ha.length; i++) { - ha[i] = new HashTable(); - } - - HashDemo search = new HashDemo(); - search.createHashTable(ha, list, MODULO, MAXSIZE); - search.displayHashTable(ha); - } - - /** - * 创建哈希表 先将哈希表中各关键字清空,使其地址为开放的,然后调用插入算法将给定的关键字序列依次插入。 - */ - public void createHashTable(HashTable[] ha, int[] list, int p, int size) { - int i = 0; - - // 将哈希表中的所有关键字清空 - for (i = 0; i < ha.length; i++) { - ha[i].key = NULLKEY; - ha[i].count = 0; - } - - // 将关键字序列依次插入哈希表中 - for (i = 0; i < list.length; i++) { - this.insertHashTable(ha, p, size, list[i]); - } - } - - /** - * 输出哈希表 - */ - private void displayHashTable(HashTable[] ha) { - int i = 0; - System.out.format("pos:\t", "pos"); - for (i = 0; i < ha.length; i++) { - System.out.format("%4d", i); - } - System.out.println(); - - System.out.format("key:\t"); - for (i = 0; i < ha.length; i++) { - if (ha[i].key != NULLKEY) { - System.out.format("%4d", ha[i].key); - } else { - System.out.format(" "); - } - } - System.out.println(); - - System.out.format("count:\t"); - for (i = 0; i < ha.length; i++) { - if (0 != ha[i].count) { - System.out.format("%4d", ha[i].count); - } else { - System.out.format(" "); - } - } - System.out.println(); - } - - /** - * 将待插入的关键字key插入哈希表 先调用查找算法,若在表中找到待插入的关键字,则插入失败; 若在表中找到一个开放地址,则将待插入的结点插入到其中,则插入成功。 - */ - private void insertHashTable(HashTable[] ha, int p, int size, int key) { - int i = 1; - int addr = 0; - // 通过哈希函数获取哈希地址 - addr = key % p; - // 如果没有冲突,直接插入 - if (ha[addr].key == NULLKEY || ha[addr].key == DELKEY) { - ha[addr].key = key; - ha[addr].count = 1; - // 如果有冲突,使用开放定址法处理冲突 - } else { - do { - // 寻找下一个哈希地址 - addr = (addr + 1) % size; - i++; - } - while (ha[addr].key != NULLKEY && ha[addr].key != DELKEY); - - ha[addr].key = key; - ha[addr].count = i; - } - } - - /** - * 删除哈希表中关键字为key的记录 找到要删除的记录,将关键字置为删除标记DELKEY - */ - public int deleteHashTable(HashTable[] ha, int p, int size, int key) { - int addr = 0; - addr = searchHashTable(ha, p, size, key); - if (FAILED != addr) { - // 将该位置的关键字置为DELKEY - ha[addr].key = DELKEY; - return SUCCESS; - } else { - // 查找不到记录,直接返回NULLKEY - return NULLKEY; - } - } - - /** - * 查找哈希表 构造哈希表采用除留取余法,即f(key) = key mod p (p ≤ size) 解决冲突采用开放定址法,即f2(key) = (f(key) + i) mod p (1 ≤ i ≤ size-1) - * ha为哈希表,p为模,size为哈希表大小,key为要查找的关键字 - */ - private int searchHashTable(HashTable[] ha, int p, int size, int key) { - // 采用除留取余法找哈希地址 - int addr = key % p; - - // 若发生冲突,用开放定址法找下一个哈希地址 - while (ha[addr].key != NULLKEY && ha[addr].key != key) { - addr = (addr + 1) % size; - } - - if (ha[addr].key == key) { - // 查找成功 - return addr; - } else { - // 查找失败 - return FAILED; - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/Search.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/Search.java deleted file mode 100644 index f4a8b0d..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/Search.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.dunwu.algorithm.search; - -/** - * @author Zhang Peng - */ -public interface Search { - - /** - * @param array 要查找的数组 - * @param key 要查找的 key - * @return 返回第一个匹配 key 值的数组元素所在位置 - */ - > int find(T[] array, T key); - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/SearchStrategy.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/SearchStrategy.java deleted file mode 100644 index 31afa41..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/SearchStrategy.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.dunwu.algorithm.search; - -import cn.hutool.core.util.ArrayUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * 使用策略模式,对算法进行包装 - * - * @author Zhang Peng - */ -public class SearchStrategy { - - private static final Logger logger = LoggerFactory.getLogger(SearchStrategy.class); - - private Search search; - - public SearchStrategy(Search search) { - search = search; - } - - public int find(Integer[] list, int key) { - logger.info(search.getClass().getSimpleName() + " 查找开始:"); - logger.info("要查找的线性表:{}", ArrayUtil.toString(list)); - logger.info("要查找的 key:{}", key); - - int index = search.find(list, key); - logger.info("{} 的位置是:{}", key, index); - return index; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/strategy/BinarySearch.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/strategy/BinarySearch.java deleted file mode 100644 index 1a95b3a..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/strategy/BinarySearch.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.search.strategy; - -import io.github.dunwu.algorithm.search.Search; - -/** - * 二分查找又称折半查找,它是一种效率较高的查找方法。 二分查找需要两个前提:(1) 必须是顺序存储结构。(2) 必须是有序的表。 算法: 从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功; - * 若扫描结束仍没有找到等于关键字的结点,表示查找失败。 算法分析: 最坏情况 O(log n) 最好情况 O(1) 平均情况 O(log n) 最坏情况下的空间复杂性 O(1) - * - * @author Zhang Peng - */ -public class BinarySearch implements Search { - - /** - * 查找方法 - * - * @param array 被查找的线性表 - * @param key 被查找的 key - * @return 成功返回 key 的位置;失败返回 -1 - */ - @Override - public > int find(T[] array, T key) { - return search(array, key, 0, array.length); - } - - private > int search(T[] array, T key, int left, int right) { - // this means that the key not found - if (right < left) { - return -1; - } - - int mid = (left + right) >>> 1; - int comp = key.compareTo(array[mid]); - - if (comp < 0) { - return search(array, key, left, mid - 1); - } - - if (comp > 0) { - return search(array, key, mid + 1, right); - } - - return mid; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/strategy/OrderSearch.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/strategy/OrderSearch.java deleted file mode 100644 index 04d1181..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/strategy/OrderSearch.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.dunwu.algorithm.search.strategy; - -import io.github.dunwu.algorithm.search.Search; - -/** - * 顺序查找是一种最简单的查找算法。它的查找效率不高。 算法: 从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功; 若扫描结束仍没有找到关键字等于k的结点,表示查找失败。 算法分析: - * 最坏情况 O(n) 最好情况 O(1) 平均情况 O(n) 最坏情况下的空间复杂性 - * - * @author Zhang Peng - */ -public class OrderSearch implements Search { - - /** - * 查找方法 - * - * @param array 被查找的线性表 - * @param key 被查找的 key - * @return 成功返回 key 的位置;失败返回 -1 - */ - @Override - public > int find(T[] array, T key) { - for (int i = 0; i < array.length; i++) { - if (array[i].compareTo(key) == 0) { - return i; - } - } - return -1; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/x\347\232\204\345\271\263\346\226\271\346\240\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/x\347\232\204\345\271\263\346\226\271\346\240\271.java" deleted file mode 100644 index ebdb8a1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/x\347\232\204\345\271\263\346\226\271\346\240\271.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.search; - -import org.junit.jupiter.api.Assertions; - -import java.math.BigDecimal; - -/** - * @author Zhang Peng - * @since 2020-07-04 - */ -public class x的平方根 { - - public static void main(String[] args) { - Assertions.assertEquals(2, mySqrt(4)); - Assertions.assertEquals(3, mySqrt(9)); - Assertions.assertEquals(2, mySqrt(8)); // 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。 - Assertions.assertEquals(2.8285f, mySqrt2(8, 4)); // 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。 - } - - // 利用二分法实现求平发根 - public static int mySqrt(int x) { - if (x == 0 || x == 1) return x; - int l = 1, r = x, res = x; - while (l <= r) { - int m = (l + r) / 2; - if (m == x / m) { - return m; - } else if (m > x / m) { - r = m - 1; - } else { - l = m + 1; - res = m; - } - } - return res; - } - - // 利用二分法实现求浮点数平发根,支持指定精度 e (小数点位数) - public static float mySqrt2(float x, int e) { - if (x == 0 || Float.compare(x, 1f) == 0) return x; - float l = 1f, r = x, res = x; - while (l <= r) { - float m = (l + r) / 2; - if (m == x / m) { - BigDecimal decimal = new BigDecimal(m).setScale(e, BigDecimal.ROUND_UP); - return decimal.floatValue(); - } else if (m > x / m) { - r = m; - } else { - l = m; - res = m; - } - } - BigDecimal decimal = new BigDecimal(res).setScale(e, BigDecimal.ROUND_UP); - return decimal.floatValue(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.java" deleted file mode 100644 index 2cb89b6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.java" +++ /dev/null @@ -1,61 +0,0 @@ -package io.github.dunwu.algorithm.search; - -import org.junit.jupiter.api.Assertions; - -/** - * https://leetcode-cn.com/problems/search-insert-position/ - * - * @author Zhang Peng - * @since 2020-07-13 - */ -public class 搜索二维矩阵 { - - public static void main(String[] args) { - int[][] metrix = { - { 1, 3, 5, 7 }, - { 10, 11, 16, 20 }, - { 23, 30, 34, 50 } - }; - Assertions.assertTrue(searchMatrix(metrix, 3)); - Assertions.assertFalse(searchMatrix(metrix, 13)); - // Assertions.assertEquals(1, searchMatrix(metrix, 2)); - // Assertions.assertEquals(4, searchMatrix(metrix, 7)); - } - - public static boolean searchMatrix(int[][] matrix, int target) { - int rowLen = matrix.length; - int columnLen = matrix[0].length; - - // 剪枝 - if (matrix[rowLen - 1][columnLen - 1] < target) { - return false; - } - - int rbegin = 0, rend = rowLen - 1; - while (rbegin < rend) { - int rmid = rbegin + (rend - rbegin) / 2; - if (matrix[rmid][columnLen - 1] == target) { - return true; - } else if (matrix[rmid][columnLen - 1] < target) { - rbegin = rmid + 1; - } else { - rend = rmid; - } - } - - int cbegin = 0, cend = columnLen - 1; - while (cbegin < cend) { - int cmid = cbegin + (cend - cbegin) / 2; - if (matrix[rbegin][cmid] == target) { - return true; - } else if (matrix[rbegin][cmid] < target) { - cbegin = cmid + 1; - } else { - cend = cmid; - } - } - - return false; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" deleted file mode 100644 index d24c13c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/\346\220\234\347\264\242\346\217\222\345\205\245\344\275\215\347\275\256.java" +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.dunwu.algorithm.search; - -import org.junit.jupiter.api.Assertions; - -/** - * https://leetcode-cn.com/problems/search-insert-position/ - * - * @author Zhang Peng - * @since 2020-07-13 - */ -public class 搜索插入位置 { - - public static void main(String[] args) { - int[] nums = { 1, 3, 5, 6 }; - Assertions.assertEquals(2, searchInsert2(nums, 5)); - Assertions.assertEquals(1, searchInsert2(nums, 2)); - Assertions.assertEquals(4, searchInsert2(nums, 7)); - } - - public static int searchInsert(int[] nums, int target) { - - int len = nums.length; - int left = 0; - int right = len - 1; - if (nums[len - 1] < target) { - return len; - } - while (left < right) { - int mid = left + (right - left) / 2; - if (nums[mid] < target) { - left = mid + 1; - } else { - right = mid; - } - } - return left; - } - - public static int searchInsert2(int[] nums, int target) { - int N = nums.length; - if (target < nums[0]) return 0; - if (target > nums[N - 1]) return N; - int left = 0, right = N - 1; - - while (left < right) { - int mid = left + (right - left) / 2; - if (nums[mid] < target) { - left = mid + 1; - } else { - right = mid; - } - } - return left; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/\347\254\254\344\270\200\344\270\252\351\224\231\350\257\257\347\232\204\347\211\210\346\234\254.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/\347\254\254\344\270\200\344\270\252\351\224\231\350\257\257\347\232\204\347\211\210\346\234\254.java" deleted file mode 100644 index 788a232..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/search/\347\254\254\344\270\200\344\270\252\351\224\231\350\257\257\347\232\204\347\211\210\346\234\254.java" +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.dunwu.algorithm.search; - -/** - * @author Zhang Peng - * @since 2020-07-13 - */ -public class 第一个错误的版本 { - - public static void main(String[] args) { - - } - - public static int firstBadVersion(int n) { - int begin = 1, end = n; - while (begin < end) { - int mid = begin + (end - begin) / 2; - if (isBadVersion(mid)) { - end = mid; - } else { - begin = mid; - } - } - return begin; - } - - public static boolean isBadVersion(int n) { - return true; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/Sort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/Sort.java deleted file mode 100644 index bfbe8ca..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/Sort.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.github.dunwu.algorithm.sort; - -/** - * 排序通用泛型接口 - * - * @author Zhang Peng - */ -public interface Sort { - - /** - * 排序接口 - * - * @param list 要排序的数组 - */ - > void sort(T[] list); - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/SortStrategy.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/SortStrategy.java deleted file mode 100644 index 5e2f7ef..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/SortStrategy.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.github.dunwu.algorithm.sort; - -import io.github.dunwu.algorithm.util.ArrayUtil; -import lombok.extern.slf4j.Slf4j; - -/** - * 使用策略模式,对算法进行包装 - * - * @author Zhang Peng - */ -@Slf4j -public class SortStrategy { - - private final Sort sort; - - public SortStrategy(Sort sort) { - this.sort = sort; - } - - public void sort(Integer[] list) { - System.out.printf("=================== %s 排序开始 ===================\n", this.sort.getClass().getSimpleName()); - System.out.printf("【排序前】\n%s\n", ArrayUtil.getArrayString(list, 0, list.length - 1)); - this.sort.sort(list); - System.out.printf("【排序后】\n%s\n", ArrayUtil.getArrayString(list, 0, list.length - 1)); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort.java deleted file mode 100644 index 3c10699..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.dunwu.algorithm.sort.strategy; - -import io.github.dunwu.algorithm.sort.Sort; -import io.github.dunwu.algorithm.util.ArrayUtil; - -/** - * 冒泡排序算法 - * - * @author Zhang Peng - */ -public class BubbleSort implements Sort { - - @Override - public > void sort(T[] list) { - // 要遍历的次数 - for (int i = 0; i < list.length - 1; i++) { - // 从后向前依次的比较相邻两个数的大小,遍历一次后,把数组中第i小的数放在第i个位置上 - for (int j = list.length - 1; j > i; j--) { - // 比较相邻的元素,如果前面的数大于后面的数,则交换 - if (list[j - 1].compareTo(list[j]) > 0) { - T temp = list[j - 1]; - list[j - 1] = list[j]; - list[j] = temp; - } - } - ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟", i + 1)); - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort2.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort2.java deleted file mode 100644 index 7bebb12..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/BubbleSort2.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.sort.strategy; - -import io.github.dunwu.algorithm.sort.Sort; -import io.github.dunwu.algorithm.util.ArrayUtil; - -/** - * 冒泡排序的优化算法 - * - * @author Zhang Peng - */ -public class BubbleSort2 implements Sort { - - @Override - public > void sort(T[] list) { - - // 要遍历的次数 - for (int i = 0; i < list.length - 1; i++) { - // 交换标志 - boolean changed = false; - // 从后向前依次的比较相邻两个数的大小,遍历一次后,把数组中第i小的数放在第i个位置上 - for (int j = list.length - 1; j > i; j--) { - // 比较相邻的元素,如果前面的数大于后面的数,则交换 - if (list[j - 1].compareTo(list[j]) > 0) { - T temp = list[j - 1]; - list[j - 1] = list[j]; - list[j] = temp; - changed = true; - } - } - - // 如果标志为false,说明本轮遍历没有交换,已经是有序数列,可以结束排序 - if (!changed) { - break; - } - - ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟", i + 1)); - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/HeapSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/HeapSort.java deleted file mode 100644 index d403207..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/HeapSort.java +++ /dev/null @@ -1,62 +0,0 @@ -package io.github.dunwu.algorithm.sort.strategy; - -import io.github.dunwu.algorithm.sort.Sort; -import io.github.dunwu.algorithm.util.ArrayUtil; - -/** - * 堆排序算法 - * - * @author Zhang Peng - */ -public class HeapSort implements Sort { - - @Override - public > void sort(T[] list) { - // 循环建立初始堆 - for (int i = list.length / 2; i >= 0; i--) { - adjustHeat(list, i, list.length); - } - - // 进行n-1次循环,完成排序 - for (int i = list.length - 1; i > 0; i--) { - // 最后一个元素和第一元素进行交换 - T temp = list[i]; - list[i] = list[0]; - list[0] = temp; - - // 筛选 R[0] 结点,得到i-1个结点的堆 - adjustHeat(list, 0, i); - - ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟", list.length - i)); - } - } - - private static > void adjustHeat(T[] array, int parent, int length) { - // temp保存当前父节点 - T temp = array[parent]; - // 先获得左孩子 - int child = 2 * parent + 1; - - while (child < length) { - // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点 - if (child + 1 < length && array[child].compareTo(array[child + 1]) < 0) { - child++; - } - - // 如果父结点的值已经大于孩子结点的值,则直接结束 - if (temp.compareTo(array[child]) >= 0) { - break; - } - - // 把孩子结点的值赋给父结点 - array[parent] = array[child]; - - // 选取孩子结点的左孩子结点,继续向下筛选 - parent = child; - child = 2 * child + 1; - } - - array[parent] = temp; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/InsertSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/InsertSort.java deleted file mode 100644 index 9d1d49b..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/InsertSort.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.dunwu.algorithm.sort.strategy; - -import io.github.dunwu.algorithm.sort.Sort; -import io.github.dunwu.algorithm.util.ArrayUtil; - -/** - * 插入排序算法 - * - * @author Zhang Peng - */ -public class InsertSort implements Sort { - - @Override - public > void sort(T[] list) { - // 第1个数肯定是有序的,从第2个数开始遍历,依次插入有序序列 - for (int i = 1; i < list.length; i++) { - int j = 0; - // 取出第i个数,和前i-1个数比较后,插入合适位置 - T temp = list[i]; - - // 因为前i-1个数都是从小到大的有序序列,所以只要当前比较的数(list[j])比temp大,就把这个数后移一位 - for (j = i - 1; j >= 0 && temp.compareTo(list[j]) < 0; j--) { - list[j + 1] = list[j]; - } - list[j + 1] = temp; - - ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟", i)); - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/MergeSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/MergeSort.java deleted file mode 100644 index 56d36ac..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/MergeSort.java +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.dunwu.algorithm.sort.strategy; - -import io.github.dunwu.algorithm.sort.Sort; -import io.github.dunwu.algorithm.util.ArrayUtil; - -public class MergeSort implements Sort { - - @Override - public > void sort(T[] list) { - for (int gap = 1; gap < list.length; gap = 2 * gap) { - mergeSort(list, gap, list.length); - ArrayUtil.printArray(list, 0, list.length - 1, String.format("gap = %d", gap)); - } - } - - private > void mergeSort(T[] array, int gap, int length) { - int i = 0; - - // 归并gap长度的两个相邻子表 - for (i = 0; i + 2 * gap - 1 < length; i = i + 2 * gap) { - merge(array, i, i + gap - 1, i + 2 * gap - 1); - } - - // 余下两个子表,后者长度小于gap - if (i + gap - 1 < length) { - merge(array, i, i + gap - 1, length - 1); - } - } - - private > void merge(T[] array, int low, int mid, int high) { - // i是第一段序列的下标 - int i = low; - // j是第二段序列的下标 - int j = mid + 1; - // k是临时存放合并序列的下标 - int k = 0; - // array2是临时合并序列 - T[] array2 = (T[]) new Comparable[high - low + 1]; - - // 扫描第一段和第二段序列,直到有一个扫描结束 - while (i <= mid && j <= high) { - // 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描 - if (array[i].compareTo(array[j]) <= 0) { - array2[k] = array[i]; - i++; - k++; - } else { - array2[k] = array[j]; - j++; - k++; - } - } - - // 若第一段序列还没扫描完,将其全部复制到合并序列 - while (i <= mid) { - array2[k] = array[i]; - i++; - k++; - } - - // 若第二段序列还没扫描完,将其全部复制到合并序列 - while (j <= high) { - array2[k] = array[j]; - j++; - k++; - } - - // 将合并序列复制到原始序列中 - for (k = 0, i = low; i <= high; i++, k++) { - array[i] = array2[k]; - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/QuickSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/QuickSort.java deleted file mode 100644 index 03ee815..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/QuickSort.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.sort.strategy; - -import io.github.dunwu.algorithm.sort.Sort; -import io.github.dunwu.algorithm.util.ArrayUtil; - -/** - * 快速排序算法 - * - * @author Zhang Peng - */ -public class QuickSort implements Sort { - - private > int division(T[] list, int left, int right) { - // 以最左边的数(left)为基准 - T base = list[left]; - while (left < right) { - // 从序列右端开始,向左遍历,直到找到小于base的数 - while (left < right && list[right].compareTo(base) >= 0) { - right--; - } - // 找到了比base小的元素,将这个元素放到最左边的位置 - list[left] = list[right]; - - // 从序列左端开始,向右遍历,直到找到大于base的数 - while (left < right && list[left].compareTo(base) <= 0) { - left++; - } - // 找到了比base大的元素,将这个元素放到最右边的位置 - list[right] = list[left]; - } - - // 最后将base放到left位置。此时,left位置的左侧数值应该都比left小; - // 而left位置的右侧数值应该都比left大。 - list[left] = base; - return left; - } - - private > void quickSort(T[] list, int left, int right) { - - // 左下标一定小于右下标,否则就越界了 - if (left < right) { - // 对数组进行分割,取出下次分割的基准标号 - int base = division(list, left, right); - - ArrayUtil.printArray(list, left, right, String.format("base = %d: ", list[base])); - - // 对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序 - quickSort(list, left, base - 1); - - // 对“基准标号“右侧的一组数值进行递归的切割,以至于将这些数值完整的排序 - quickSort(list, base + 1, right); - } - } - - @Override - public > void sort(T[] list) { - quickSort(list, 0, list.length - 1); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/SelectionSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/SelectionSort.java deleted file mode 100644 index 319cc81..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/SelectionSort.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.dunwu.algorithm.sort.strategy; - -import io.github.dunwu.algorithm.sort.Sort; -import io.github.dunwu.algorithm.util.ArrayUtil; - -/** - * 选择排序算法 - * - * @author Zhang Peng - */ -public class SelectionSort implements Sort { - - @Override - public > void sort(T[] list) { - // 需要遍历获得最小值的次数 - // 要注意一点,当要排序 N 个数,已经经过 N-1 次遍历后,已经是有序数列 - for (int i = 0; i < list.length - 1; i++) { - // 用来保存最小值得索引 - int index = i; - - // 寻找第i个小的数值 - for (int j = i + 1; j < list.length; j++) { - if (list[index].compareTo(list[j]) > 0) { - index = j; - } - } - - // 将找到的第i个小的数值放在第i个位置上 - T temp = list[index]; - list[index] = list[i]; - list[i] = temp; - - ArrayUtil.printArray(list, 0, list.length - 1, String.format("第 %02d 趟:", i + 1)); - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/ShellSort.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/ShellSort.java deleted file mode 100644 index 7b32584..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/sort/strategy/ShellSort.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.github.dunwu.algorithm.sort.strategy; - -import io.github.dunwu.algorithm.sort.Sort; -import io.github.dunwu.algorithm.util.ArrayUtil; - -/** - * 希尔排序算法 - * - * @author Zhang Peng - */ -public class ShellSort implements Sort { - - @Override - public > void sort(T[] list) { - int gap = list.length / 2; - - while (1 <= gap) { - // 把距离为 gap 的元素编为一个组,扫描所有组 - for (int i = gap; i < list.length; i++) { - int j = 0; - T temp = list[i]; - - // 对距离为 gap 的元素组进行排序 - for (j = i - gap; j >= 0 && temp.compareTo(list[j]) < 0; j = j - gap) { - list[j + gap] = list[j]; - } - list[j + gap] = temp; - } - - ArrayUtil.printArray(list, 0, list.length - 1, String.format("gap = %d:", gap)); - // 减小增量 - gap = gap / 2; - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java deleted file mode 100644 index ac5bd96..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/GenericStack.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -/** - * 简化版泛型栈 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class GenericStack { - - private int size = 0; - private Node top = null; - - public void push(T value) { - Node node = new Node<>(value, null); - if (top == null) { - top = node; - } else { - node.next = top; - top = node; - } - size++; - } - - public T pop() { - if (top == null) { - return null; - } - T val = top.data; - top = top.next; - size--; - return val; - } - - public T peek() { - if (top == null) { - return null; - } - return top.data; - } - - public int getSize() { - return size; - } - - public boolean isEmpty() { - return size == 0; - } - - public void printAll() { - Node p = top; - while (p != null) { - System.out.print(p.data + " "); - p = p.next; - } - System.out.println(); - } - - private static class Node { - - private T data; - private Node next; - - public Node(T data, Node next) { - this.data = data; - this.next = next; - } - - public T getData() { - return data; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java deleted file mode 100644 index 6a2fefd..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 通过「单调栈」解决「下一个更大元素」,「上一个更小元素」等类型问题 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -package io.github.dunwu.algorithm.stack.monotonic; \ No newline at end of file diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" deleted file mode 100644 index d18dd54..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\240.java" +++ /dev/null @@ -1,48 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; -import java.util.Stack; - -/** - * 496. 下一个更大元素 I - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 下一个更大元素 { - - public static void main(String[] args) { - Solution s = new Solution(); - int[] output1 = s.nextGreaterElement(new int[] { 4, 1, 2 }, new int[] { 1, 3, 4, 2 }); - Assertions.assertArrayEquals(new int[] { -1, 3, -1 }, output1); - int[] output2 = s.nextGreaterElement(new int[] { 2, 4 }, new int[] { 1, 2, 3, 4 }); - Assertions.assertArrayEquals(new int[] { 3, -1 }, output2); - } - - // 采用单调栈解决问题,算法复杂度:O(n) - static class Solution { - - public int[] nextGreaterElement(int[] nums1, int[] nums2) { - Stack stack = new Stack<>(); - Map map = new HashMap<>(); - for (int i = nums2.length - 1; i >= 0; i--) { - while (!stack.isEmpty() && stack.peek() <= nums2[i]) { - stack.pop(); - } - int largerVal = stack.isEmpty() ? -1 : stack.peek(); - map.put(nums2[i], largerVal); - stack.push(nums2[i]); - } - - for (int i = 0; i < nums1.length; i++) { - nums1[i] = map.get(nums1[i]); - } - return nums1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" deleted file mode 100644 index b2fe027..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\345\205\203\347\264\2402.java" +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 503. 下一个更大元素 II - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 下一个更大元素2 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 2, -1, 2 }, s.nextGreaterElements(new int[] { 1, 2, 1 })); - Assertions.assertArrayEquals(new int[] { 2, 3, 4, -1, 4 }, s.nextGreaterElements(new int[] { 1, 2, 3, 4, 3 })); - } - - static class Solution { - - public int[] nextGreaterElements(int[] nums) { - int n = nums.length; - int[] res = new int[n]; - Stack s = new Stack<>(); - for (int i = 2 * n - 1; i >= 0; i--) { - int index = i % n; - // 遍历栈,将小于当前元素的值都踢了 - while (!s.isEmpty() && s.peek() <= nums[index]) { - s.pop(); - } - // nums[i] 下一个更大元素在栈顶 - res[index] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[index]); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\345\225\206\345\223\201\346\212\230\346\211\243\345\220\216\347\232\204\346\234\200\347\273\210\344\273\267\346\240\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\345\225\206\345\223\201\346\212\230\346\211\243\345\220\216\347\232\204\346\234\200\347\273\210\344\273\267\346\240\274.java" deleted file mode 100644 index 9243ec1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\345\225\206\345\223\201\346\212\230\346\211\243\345\220\216\347\232\204\346\234\200\347\273\210\344\273\267\346\240\274.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 1475. 商品折扣后的最终价格 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 商品折扣后的最终价格 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 4, 2, 4, 2, 3 }, s.finalPrices(new int[] { 8, 4, 6, 2, 3 })); - Assertions.assertArrayEquals(new int[] { 1, 2, 3, 4, 5 }, s.finalPrices(new int[] { 1, 2, 3, 4, 5 })); - Assertions.assertArrayEquals(new int[] { 9, 0, 1, 6 }, s.finalPrices(new int[] { 10, 1, 1, 6 })); - } - - static class Solution { - - public int[] finalPrices(int[] prices) { - int[] res = new int[prices.length]; - Stack stack = new Stack<>(); - for (int i = prices.length - 1; i >= 0; i--) { - while (!stack.isEmpty() && stack.peek() > prices[i]) { - stack.pop(); - } - res[i] = stack.isEmpty() ? prices[i] : prices[i] - stack.peek(); - stack.push(prices[i]); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" deleted file mode 100644 index 077f1c8..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\234\200\347\237\255\346\227\240\345\272\217\350\277\236\347\273\255\345\255\220\346\225\260\347\273\204.java" +++ /dev/null @@ -1,89 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.Stack; - -/** - * 581. 最短无序连续子数组 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 最短无序连续子数组 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(5, s.findUnsortedSubarray(new int[] { 2, 6, 4, 8, 10, 9, 15 })); - Assertions.assertEquals(0, s.findUnsortedSubarray(new int[] { 1, 2, 3, 4 })); - Assertions.assertEquals(0, s.findUnsortedSubarray(new int[] { 1 })); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(5, s2.findUnsortedSubarray(new int[] { 2, 6, 4, 8, 10, 9, 15 })); - Assertions.assertEquals(0, s2.findUnsortedSubarray(new int[] { 1, 2, 3, 4 })); - Assertions.assertEquals(0, s2.findUnsortedSubarray(new int[] { 1 })); - } - - // 排序解法 - static class Solution { - - public int findUnsortedSubarray(int[] nums) { - int[] temp = Arrays.copyOf(nums, nums.length); - Arrays.sort(temp); - int left = Integer.MAX_VALUE, right = Integer.MIN_VALUE; - for (int i = 0; i < nums.length; i++) { - if (temp[i] != nums[i]) { - left = i; - break; - } - } - for (int i = nums.length - 1; i >= 0; i--) { - if (temp[i] != nums[i]) { - right = i; - break; - } - } - if (left == Integer.MAX_VALUE && right == Integer.MIN_VALUE) { - // nums 本来就是有序的 - return 0; - } - return right - left + 1; - } - - } - - // 单调栈解法 - static class Solution2 { - - public int findUnsortedSubarray(int[] nums) { - int n = nums.length; - int left = Integer.MAX_VALUE, right = Integer.MIN_VALUE; - // 递增栈,存储元素索引 - Stack incrStk = new Stack<>(); - for (int i = 0; i < n; i++) { - while (!incrStk.isEmpty() && nums[incrStk.peek()] > nums[i]) { - // 弹出的元素都是乱序元素,其中最小的索引就是乱序子数组的左边界 - left = Math.min(left, incrStk.pop()); - } - incrStk.push(i); - } - // 递减栈,存储元素索引 - Stack decrStk = new Stack<>(); - for (int i = n - 1; i >= 0; i--) { - while (!decrStk.isEmpty() && nums[decrStk.peek()] < nums[i]) { - // 弹出的元素都是乱序元素,其中最大的索引就是乱序子数组的右边界 - right = Math.max(right, decrStk.pop()); - } - decrStk.push(i); - } - if (left == Integer.MAX_VALUE && right == Integer.MIN_VALUE) { - // 说明单调栈没有弹出任何元素,即 nums 本来就是有序的 - return 0; - } - return right - left + 1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\257\217\346\227\245\346\270\251\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\257\217\346\227\245\346\270\251\345\272\246.java" deleted file mode 100644 index 774fe37..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\346\257\217\346\227\245\346\270\251\345\272\246.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 739. 每日温度 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 每日温度 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 1, 1, 4, 2, 1, 1, 0, 0 }, - s.dailyTemperatures(new int[] { 73, 74, 75, 71, 69, 72, 76, 73 })); - Assertions.assertArrayEquals(new int[] { 1, 1, 1, 0 }, - s.dailyTemperatures(new int[] { 30, 40, 50, 60 })); - } - - static class Solution { - - public int[] dailyTemperatures(int[] t) { - int[] res = new int[t.length]; - Stack s = new Stack<>(); - for (int i = t.length - 1; i >= 0; i--) { - while (!s.isEmpty() && s.peek()[1] <= t[i]) { - s.pop(); - } - res[i] = s.isEmpty() ? 0 : s.peek()[0] - i; - s.push(new int[] { i, t[i] }); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" deleted file mode 100644 index aeb64a5..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\347\247\273\346\216\211K\344\275\215\346\225\260\345\255\227.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 402. 移掉 K 位数字 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 移掉K位数字 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals("1219", s.removeKdigits("1432219", 3)); - Assertions.assertEquals("200", s.removeKdigits("10200", 1)); - Assertions.assertEquals("0", s.removeKdigits("10", 2)); - } - - static class Solution { - - public String removeKdigits(String num, int k) { - Stack s = new Stack<>(); - for (char c : num.toCharArray()) { - // 单调栈代码模板 - while (!s.isEmpty() && c < s.peek() && k > 0) { - s.pop(); - k--; - } - // 防止 0 作为数字的开头 - if (s.isEmpty() && c == '0') { continue; } - s.push(c); - } - - // 此时栈中元素单调递增,若 k 还没用完的话删掉栈顶元素 - while (!s.isEmpty() && k > 0) { - s.pop(); - k--; - } - // 若最后没剩下数字,就是 0 - if (s.isEmpty()) { return "0"; } - // 将栈中字符转化成字符串 - StringBuilder sb = new StringBuilder(); - while (!s.isEmpty()) { sb.append(s.pop()); } - // 出栈顺序和字符串顺序是反的 - return sb.reverse().toString(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" deleted file mode 100644 index 4852eb3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\202\241\347\245\250\344\273\267\346\240\274\350\267\250\345\272\246.java" +++ /dev/null @@ -1,83 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -/** - * 901. 股票价格跨度 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 股票价格跨度 { - - public static void main(String[] args) { - StockSpanner stock = new StockSpanner(); - Assertions.assertEquals(1, stock.next(100)); - Assertions.assertEquals(1, stock.next(80)); - Assertions.assertEquals(1, stock.next(60)); - Assertions.assertEquals(2, stock.next(70)); - Assertions.assertEquals(1, stock.next(60)); - Assertions.assertEquals(4, stock.next(75)); - Assertions.assertEquals(6, stock.next(85)); - - StockSpanner2 stock2 = new StockSpanner2(); - Assertions.assertEquals(1, stock2.next(100)); - Assertions.assertEquals(1, stock2.next(80)); - Assertions.assertEquals(1, stock2.next(60)); - Assertions.assertEquals(2, stock2.next(70)); - Assertions.assertEquals(1, stock2.next(60)); - Assertions.assertEquals(4, stock2.next(75)); - Assertions.assertEquals(6, stock2.next(85)); - } - - static class StockSpanner { - - private final List l; - - public StockSpanner() { - l = new ArrayList<>(); - } - - public int next(int price) { - int count = 1; - for (int i = l.size() - 1; i >= 0; i--) { - if (l.get(i) > price) { - break; - } - count++; - } - l.add(price); - return count; - } - - } - - static class StockSpanner2 { - - // int[] 记录 {价格,小于等于该价格的天数} 二元组 - private final Stack s; - - public StockSpanner2() { - s = new Stack<>(); - } - - public int next(int price) { - // 算上当天 - int count = 1; - // 单调栈模板 - while (!s.isEmpty() && s.peek()[0] <= price) { - // 挤掉价格低于 price 的记录 - int[] prev = s.pop(); - count += prev[1]; - } - s.push(new int[] { price, count }); - return count; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" deleted file mode 100644 index 8005fcc..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\350\275\246\344\275\215.java" +++ /dev/null @@ -1,70 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.Stack; - -/** - * 853. 车队 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 车位 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.carFleet(12, new int[] { 10, 8, 0, 5, 3 }, new int[] { 2, 4, 1, 1, 3 })); - Assertions.assertEquals(1, s.carFleet(10, new int[] { 3 }, new int[] { 3 })); - Assertions.assertEquals(1, s.carFleet(100, new int[] { 0, 2, 4 }, new int[] { 4, 2, 1 })); - } - - static class Solution { - - public int carFleet(int target, int[] position, int[] speed) { - - int n = position.length; - int[][] cars = new int[n][2]; - for (int i = 0; i < n; i++) { - cars[i][0] = position[i]; - cars[i][1] = speed[i]; - } - - // 按照初始位置,从小到大排序 - Arrays.sort(cars, (int[] a, int[] b) -> { - return Integer.compare(a[0], b[0]); - }); - - // 计算每辆车到达终点的时间 - double[] times = new double[n]; - for (int i = 0; i < n; i++) { - int[] car = cars[i]; - times[i] = (double) (target - car[0]) / car[1]; - } - - // 使用单调栈计算车队的数量 - Stack s = new Stack<>(); - for (double t : times) { - while (!s.isEmpty() && t >= s.peek()) { - s.pop(); - } - s.push(t); - } - return s.size(); - - // 避免使用栈模拟,倒序遍历取递增序列就是答案 - // int res = 0; - // double maxTime = 0; - // for (int i = n - 1; i >= 0; i--) { - // if (time[i] > maxTime) { - // maxTime = time[i]; - // res++; - // } - // } - // return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\223\276\350\241\250\344\270\255\347\232\204\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\223\276\350\241\250\344\270\255\347\232\204\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\350\212\202\347\202\271.java" deleted file mode 100644 index cd746cc..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\223\276\350\241\250\344\270\255\347\232\204\344\270\213\344\270\200\344\270\252\346\233\264\345\244\247\350\212\202\347\202\271.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Stack; - -/** - * 1019. 链表中的下一个更大节点 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 链表中的下一个更大节点 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 5, 5, 0 }, - s.nextLargerNodes(ListNode.buildList(2, 1, 5))); - Assertions.assertArrayEquals(new int[] { 7, 0, 5, 5, 0 }, - s.nextLargerNodes(ListNode.buildList(2, 7, 4, 3, 5))); - } - - static class Solution { - - public int[] nextLargerNodes(ListNode head) { - // 把单链表转化成数组,方便通过索引访问 - ArrayList nums = new ArrayList<>(); - ListNode p = head; - while (p != null) { - nums.add(p.val); - p = p.next; - } - - // 存放答案的数组 - int[] res = new int[nums.size()]; - Stack stack = new Stack<>(); - // 单调栈模板,求下一个更大元素,从后往前遍历 - for (int i = nums.size() - 1; i >= 0; i--) { - while (!stack.isEmpty() && stack.peek() <= nums.get(i)) { - stack.pop(); - } - // 本题要求没有下一个更大元素时返回 0 - res[i] = stack.isEmpty() ? 0 : stack.peek(); - stack.push(nums.get(i)); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\230\237\345\210\227\344\270\255\345\217\257\344\273\245\347\234\213\345\210\260\347\232\204\344\272\272\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\230\237\345\210\227\344\270\255\345\217\257\344\273\245\347\234\213\345\210\260\347\232\204\344\272\272\346\225\260.java" deleted file mode 100644 index 8257b94..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/monotonic/\351\230\237\345\210\227\344\270\255\345\217\257\344\273\245\347\234\213\345\210\260\347\232\204\344\272\272\346\225\260.java" +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.stack.monotonic; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 1944. 队列中可以看到的人数 - * - * @author Zhang Peng - * @date 2025-12-19 - */ -public class 队列中可以看到的人数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(new int[] { 3, 1, 2, 1, 1, 0 }, s.canSeePersonsCount(new int[] { 10, 6, 8, 5, 11, 9 })); - Assertions.assertEquals(new int[] { 4, 1, 1, 1, 0 }, s.canSeePersonsCount(new int[] { 5, 1, 2, 3, 10 })); - } - - static class Solution { - - public int[] canSeePersonsCount(int[] heights) { - int n = heights.length; - int[] res = new int[n]; - // int[] 记录 {身高,小于等于该身高的人数} 二元组 - Stack stk = new Stack<>(); - for (int i = n - 1; i >= 0; i--) { - // 记录右侧比自己矮的人 - int count = 0; - // 单调栈模板,计算下一个更大或相等元素(身高) - while (!stk.isEmpty() && heights[i] > stk.peek()) { - stk.pop(); - count++; - } - // 不仅可以看到比自己矮的人,如果后面存在更高的的人,也可以看到这个高人 - res[i] = stk.isEmpty() ? count : count + 1; - stk.push(heights[i]); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/template/\345\215\225\350\260\203\346\240\210\347\256\227\346\263\225\346\250\241\346\235\277.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/template/\345\215\225\350\260\203\346\240\210\347\256\227\346\263\225\346\250\241\346\235\277.java" deleted file mode 100644 index 99192ab..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/template/\345\215\225\350\260\203\346\240\210\347\256\227\346\263\225\346\250\241\346\235\277.java" +++ /dev/null @@ -1,172 +0,0 @@ -package io.github.dunwu.algorithm.stack.template; - -import java.util.Stack; - -/** - * 单调栈算法模板 - * - * @author Zhang Peng - * @date 2025-12-19 - */ -public class 单调栈算法模板 { - - /** - * 下一个更大的元素:计算 nums 中每个元素的下一个更大元素 - */ - int[] nextGreaterElement(int[] nums) { - int n = nums.length; - // 存放答案的数组 - int[] res = new int[n]; - Stack s = new Stack<>(); - // 因为是求 nums[i] 后面的元素,所以倒着往栈里放 - for (int i = n - 1; i >= 0; i--) { - // 删掉 nums[i] 后面较小的元素 - while (!s.isEmpty() && s.peek() <= nums[i]) { - s.pop(); - } - // 现在栈顶就是 nums[i] 身后的更大元素 - res[i] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[i]); - } - return res; - } - - /** - * 下一个更大或相等的元素:计算 nums 中每个元素的下一个更大或相等的元素 - */ - int[] nextGreaterOrEqualElement(int[] nums) { - int n = nums.length; - int[] res = new int[n]; - Stack s = new Stack<>(); - for (int i = n - 1; i >= 0; i--) { - // 把这里改成 < 号 - while (!s.isEmpty() && s.peek() < nums[i]) { - s.pop(); - } - // 现在栈顶就是 nums[i] 身后的大于等于 nums[i] 的元素 - res[i] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[i]); - } - return res; - } - - /** - * 下一个更小的元素:计算 nums 中每个元素的下一个更小的元素 - */ - int[] nextLessElement(int[] nums) { - int n = nums.length; - // 存放答案的数组 - int[] res = new int[n]; - Stack s = new Stack<>(); - // 倒着往栈里放 - for (int i = n - 1; i >= 0; i--) { - // 删掉 nums[i] 后面较大的元素 - while (!s.isEmpty() && s.peek() >= nums[i]) { - s.pop(); - } - // 现在栈顶就是 nums[i] 身后的更小元素 - res[i] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[i]); - } - return res; - } - - /** - * 下一个更小或相等的元素:计算 nums 中每个元素的下一个更小或相等的元素 - */ - int[] nextLessOrEqualElement(int[] nums) { - int n = nums.length; - // 存放答案的数组 - int[] res = new int[n]; - Stack s = new Stack<>(); - // 倒着往栈里放 - for (int i = n - 1; i >= 0; i--) { - // 删掉 nums[i] 后面较大的元素 - while (!s.isEmpty() && s.peek() > nums[i]) { - s.pop(); - } - // 现在栈顶就是 nums[i] 身后的更小或相等元素 - res[i] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[i]); - } - return res; - } - - /** - * 上一个更大元素:计算 nums 中每个元素的上一个更大元素 - */ - int[] prevGreaterElement(int[] nums) { - int n = nums.length; - int[] res = new int[n]; - Stack s = new Stack<>(); - // 因为是求 nums[i] 前面的元素,所以正着往栈里放 - for (int i = 0; i < n; i++) { - // 删掉 nums[i] 前面较小的元素 - while (!s.isEmpty() && s.peek() <= nums[i]) { - s.pop(); - } - // 现在栈顶就是 nums[i] 前面的更大元素 - res[i] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[i]); - } - return res; - } - - /** - * 上一个更大或相等的元素:计算 nums 中每个元素的上一个更大或相等元素 - */ - int[] prevGreaterOrEqualElement(int[] nums) { - int n = nums.length; - int[] res = new int[n]; - Stack s = new Stack<>(); - for (int i = 0; i < n; i++) { - // 注意不等号 - while (!s.isEmpty() && s.peek() < nums[i]) { - s.pop(); - } - // 现在栈顶就是 nums[i] 前面的更大或相等元素 - res[i] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[i]); - } - return res; - } - - /** - * 上一个更小的元素:计算 nums 中每个元素的上一个更小的元素 - */ - int[] prevLessElement(int[] nums) { - int n = nums.length; - int[] res = new int[n]; - Stack s = new Stack<>(); - for (int i = 0; i < n; i++) { - // 把 nums[i] 之前的较大元素删除 - while (!s.isEmpty() && s.peek() >= nums[i]) { - s.pop(); - } - // 现在栈顶就是 nums[i] 前面的更小元素 - res[i] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[i]); - } - return res; - } - - /** - * 上一个更小或相等的元素:计算 nums 中每个元素的上一个更小或相等元素 - */ - int[] prevLessOrEqualElement(int[] nums) { - int n = nums.length; - int[] res = new int[n]; - Stack s = new Stack<>(); - for (int i = 0; i < n; i++) { - // 注意不等号 - while (!s.isEmpty() && s.peek() > nums[i]) { - s.pop(); - } - // 现在栈顶就是 nums[i] 前面的更小或相等元素 - res[i] = s.isEmpty() ? -1 : s.peek(); - s.push(nums[i]); - } - return res; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" deleted file mode 100644 index e0bde55..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\226\207\344\273\266\347\232\204\346\234\200\351\225\277\347\273\235\345\257\271\350\267\257\345\276\204.java" +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Deque; -import java.util.LinkedList; - -/** - * 150. 逆波兰表达式求值 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 文件的最长绝对路径 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(20, s.lengthLongestPath("dir\\n\\tsubdir1\\n\\tsubdir2\\n\\t\\tfile.ext")); - Assertions.assertEquals(32, s.lengthLongestPath( - "dir\\n\\tsubdir1\\n\\t\\tfile1.ext\\n\\t\\tsubsubdir1\\n\\tsubdir2\\n\\t\\tsubsubdir2\\n\\t\\t\\tfile2.ext")); - Assertions.assertEquals(0, s.lengthLongestPath("a")); - Assertions.assertEquals(12, s.lengthLongestPath("file1.txt\\nfile2.txt\\nlongfile.txt")); - } - - static class Solution { - - public int lengthLongestPath(String input) { - // 这个栈存储之前的父路径。实际上这里只用存父路径的长度就够了,这个优化留给你吧 - Deque stack = new LinkedList<>(); - int maxLen = 0; - for (String part : input.split("\n")) { - int level = part.lastIndexOf("\t") + 1; - // 让栈中只保留当前目录的父路径 - while (level < stack.size()) { - stack.removeLast(); - } - stack.addLast(part.substring(level)); - // 如果是文件,就计算路径长度 - if (part.contains(".")) { - int sum = stack.stream().mapToInt(String::length).sum(); - // 加上父路径的分隔符 - sum += stack.size() - 1; - maxLen = Math.max(maxLen, sum); - } - } - return maxLen; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" deleted file mode 100644 index 9f6ec25..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\244\247\351\242\221\347\216\207\346\240\210.java" +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Stack; -import java.util.TreeMap; - -/** - * 895. 最大频率栈 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 最大频率栈 { - - public static void main(String[] args) { - FreqStack s1 = new FreqStack(); - s1.push(5);//堆栈为 [5] - s1.push(7);//堆栈是 [5,7] - s1.push(5);//堆栈是 [5,7,5] - s1.push(7);//堆栈是 [5,7,5,7] - s1.push(4);//堆栈是 [5,7,5,7,4] - s1.push(5);//堆栈是 [5,7,5,7,4,5] - Assertions.assertEquals(5, s1.pop()); //返回 5 ,因为 5 出现频率最高。堆栈变成 [5,7,5,7,4] - Assertions.assertEquals(7, s1.pop()); //返回 7 ,因为 5 和 7 出现频率最高,但7最接近顶部。堆栈变成 [5,7,5,4]。 - Assertions.assertEquals(5, s1.pop()); //返回 5 ,因为 5 出现频率最高。堆栈变成 [5,7,4]。 - Assertions.assertEquals(4, s1.pop()); //返回 4 ,因为 4, 5 和 7 出现频率最高,但 4 是最接近顶部的。堆栈变成 [5,7]。 - } - - static class FreqStack { - - private HashMap valToFreq; - private TreeMap> freqToValStack; - - public FreqStack() { - valToFreq = new HashMap<>(); - freqToValStack = new TreeMap<>(); - } - - public void push(int val) { - valToFreq.put(val, valToFreq.getOrDefault(val, 0) + 1); - Integer freq = this.valToFreq.get(val); - freqToValStack.putIfAbsent(freq, new Stack<>()); - freqToValStack.get(freq).push(val); - } - - public int pop() { - Integer maxFreq = freqToValStack.lastKey(); - Stack stack = freqToValStack.get(maxFreq); - Integer val = stack.pop(); - if (stack.empty()) { freqToValStack.remove(maxFreq); } - valToFreq.put(val, valToFreq.getOrDefault(val, 0) - 1); - return val; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" deleted file mode 100644 index 6775a69..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\200\345\260\217\346\240\210.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 面试题 03.02. 栈的最小值 - * - * @author Zhang Peng - * @date 2025-10-20 - */ -public class 最小栈 { - - public static void main(String[] args) { - MinStack minStack = new MinStack(); - minStack.push(-2); - minStack.push(0); - minStack.push(-3); - Assertions.assertEquals(-3, minStack.getMin()); - minStack.pop(); - Assertions.assertEquals(0, minStack.top()); - Assertions.assertEquals(-2, minStack.getMin()); - } - - static class MinStack { - - Stack stack; - Stack minStack; - - public MinStack() { - stack = new Stack<>(); - minStack = new Stack<>(); - } - - public void push(int val) { - stack.push(val); - if (minStack.isEmpty() || val < minStack.peek()) { - minStack.push(val); - } else { - minStack.push(minStack.peek());; - } - } - - public void pop() { - stack.pop(); - minStack.pop(); - } - - public int top() { - return stack.peek(); - } - - public int getMin() { - return minStack.peek(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" deleted file mode 100644 index 1601e5f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 20. 有效的括号 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 有效的括号 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isValid("()")); - Assertions.assertTrue(s.isValid("{[]}")); - Assertions.assertFalse(s.isValid("([)]")); - Assertions.assertFalse(s.isValid("([)")); - Assertions.assertFalse(s.isValid("((")); - Assertions.assertTrue(s.isValid("(())")); - } - - static class Solution { - - public boolean isValid(String s) { - Stack stack = new Stack<>(); - for (char c : s.toCharArray()) { - switch (c) { - case ')': - if (stack.isEmpty()) { return false; } - if (stack.pop() != '(') { return false; } - break; - case ']': - if (stack.isEmpty()) { return false; } - if (stack.pop() != '[') { return false; } - break; - case '}': - if (stack.isEmpty()) { return false; } - if (stack.pop() != '{') { return false; } - break; - default: - stack.push(c); - break; - } - } - return stack.isEmpty(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" deleted file mode 100644 index 40e5a99..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\240\210\346\216\222\345\272\217.java" +++ /dev/null @@ -1,71 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 面试题 03.05. 栈排序 - * - * @author Zhang Peng - * @date 2025-11-26 - */ -public class 栈排序 { - - public static void main(String[] args) { - SortedStack s = new SortedStack(); - s.push(1); - s.push(2); - Assertions.assertEquals(1, s.peek()); - s.pop(); - Assertions.assertEquals(2, s.peek()); - - SortedStack s2 = new SortedStack(); - s2.pop(); - s2.pop(); - s2.push(1); - s2.pop(); - Assertions.assertTrue(s2.isEmpty()); - } - - static class SortedStack { - - private Stack s; - private Stack t; - - public SortedStack() { - s = new Stack<>(); - t = new Stack<>(); - } - - public void push(int val) { - if (s.isEmpty()) { - s.push(val); - return; - } - while (!s.isEmpty() && s.peek() < val) { - t.push(s.pop()); - } - s.push(val); - while (!t.isEmpty()) { - s.push(t.pop()); - } - } - - public void pop() { - if (!s.isEmpty()) { - s.pop(); - } - } - - public int peek() { - return s.isEmpty() ? -1 : s.peek(); - } - - public boolean isEmpty() { - return s.isEmpty(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" deleted file mode 100644 index 3ae17cf..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\243\222\347\220\203\346\257\224\350\265\233.java" +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 682. 棒球比赛 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 棒球比赛 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(30, s.calPoints(new String[] { "5", "2", "C", "D", "+" })); - Assertions.assertEquals(27, s.calPoints(new String[] { "5", "-2", "4", "C", "D", "9", "+", "+" })); - } - - static class Solution { - - public int calPoints(String[] operations) { - Stack stack = new Stack<>(); - for (String op : operations) { - switch (op) { - case "C": - stack.pop(); - break; - case "D": - stack.push(stack.peek() * 2); - break; - case "+": - int cur = stack.pop(); - int prev = stack.pop(); - int next = prev + cur; - stack.push(prev); - stack.push(cur); - stack.push(next); - break; - default: - stack.push(Integer.valueOf(op)); - break; - } - } - - int res = 0; - while (!stack.isEmpty()) { - res += stack.pop(); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" deleted file mode 100644 index 5fee00b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 844. 比较含退格的字符串 - * - * @author Zhang Peng - * @since 2020-06-09 - */ -public class 比较含退格的字符串 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.backspaceCompare("ab#c", "ad#c")); - Assertions.assertTrue(s.backspaceCompare("ab##", "c#d#")); - Assertions.assertTrue(s.backspaceCompare("a##c", "#a#c")); - Assertions.assertFalse(s.backspaceCompare("a#c", "b")); - } - - static class Solution { - - public boolean backspaceCompare(String s, String t) { - Stack a = new Stack<>(); - Stack b = new Stack<>(); - for (char c : s.toCharArray()) { - if (c == '#') { - if (!a.isEmpty()) { a.pop(); } - } else { - a.push(c); - } - } - for (char c : t.toCharArray()) { - if (c == '#') { - if (!b.isEmpty()) { b.pop(); } - } else { - b.push(c); - } - } - - if (a.size() != b.size()) { return false; } - while (!a.isEmpty()) { - if (a.pop() != b.pop()) { return false; } - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\346\265\217\350\247\210\345\231\250\347\232\204\345\211\215\350\277\233\345\220\216\351\200\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\346\265\217\350\247\210\345\231\250\347\232\204\345\211\215\350\277\233\345\220\216\351\200\200.java" deleted file mode 100644 index c12f789..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\346\265\217\350\247\210\345\231\250\347\232\204\345\211\215\350\277\233\345\220\216\351\200\200.java" +++ /dev/null @@ -1,192 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -/** - * 使用前后栈实现浏览器的前进后退。 - * - * @author chinalwb - */ -public class 用栈实现浏览器的前进后退 { - - public static void main(String[] args) { - 用栈实现浏览器的前进后退 browser = new 用栈实现浏览器的前进后退(); - browser.open("http://www.baidu.com"); - browser.open("http://news.baidu.com/"); - browser.open("http://news.baidu.com/ent"); - browser.goBack(); - browser.goBack(); - browser.goForward(); - browser.open("http://www.qq.com"); - browser.goForward(); - browser.goBack(); - browser.goForward(); - browser.goBack(); - browser.goBack(); - browser.goBack(); - browser.goBack(); - browser.checkCurrentPage(); - } - - private String currentPage; - private LinkedListBasedStack backStack; - private LinkedListBasedStack forwardStack; - - public 用栈实现浏览器的前进后退() { - this.backStack = new LinkedListBasedStack(); - this.forwardStack = new LinkedListBasedStack(); - } - - public void open(String url) { - if (this.currentPage != null) { - this.backStack.push(this.currentPage); - this.forwardStack.clear(); - } - showUrl(url, "Open"); - } - - public boolean canGoBack() { - return this.backStack.size() > 0; - } - - public boolean canGoForward() { - return this.forwardStack.size() > 0; - } - - public String goBack() { - if (this.canGoBack()) { - this.forwardStack.push(this.currentPage); - String backUrl = this.backStack.pop(); - showUrl(backUrl, "Back"); - return backUrl; - } - - System.out.println("* Cannot go back, no pages behind."); - return null; - } - - public String goForward() { - if (this.canGoForward()) { - this.backStack.push(this.currentPage); - String forwardUrl = this.forwardStack.pop(); - showUrl(forwardUrl, "Foward"); - return forwardUrl; - } - - System.out.println("** Cannot go forward, no pages ahead."); - return null; - } - - public void showUrl(String url, String prefix) { - this.currentPage = url; - System.out.println(prefix + " page == " + url); - } - - public void checkCurrentPage() { - System.out.println("Current page is: " + this.currentPage); - } - - /** - * A LinkedList based Stack implementation. - */ - public static class LinkedListBasedStack { - - // public static void main(String[] args) { - // LinkedListBasedStack stack = new LinkedListBasedStack(); - // stack.push("A"); - // stack.push("B"); - // stack.push("C"); - // stack.pop(); - // stack.push("D"); - // stack.push("E"); - // stack.pop(); - // stack.push("F"); - // stack.print(); - // - //// String data = stack.getTopData(); - //// System.out.println("Top data == " + data); - // } - - private int size; - private Node top; - - static Node createNode(String data, Node next) { - return new Node(data, next); - } - - public void clear() { - this.top = null; - this.size = 0; - } - - public void push(String data) { - Node node = createNode(data, null); - if (top == null) top = node; - node.next = top; - top = node; - size++; - } - - public String pop() { - if (top == null) { - return null; - } - - String val = top.data; - top = top.next; - return val; - } - - public String getTopData() { - if (top == null) return null; - return top.data; - } - - public int size() { - return this.size; - } - - public void print() { - System.out.println("Print stack:"); - Node currentNode = this.top; - while (currentNode != null) { - String data = currentNode.getData(); - System.out.print(data + "\t"); - currentNode = currentNode.next; - } - System.out.println(); - } - - public static class Node { - - private String data; - private Node next; - - public Node(String data) { - this(data, null); - } - - public Node(String data, Node next) { - this.data = data; - this.next = next; - } - - public void setData(String data) { - this.data = data; - } - - public String getData() { - return this.data; - } - - public void setNext(Node next) { - this.next = next; - } - - public Node getNext() { - return this.next; - } - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" deleted file mode 100644 index 3051ecf..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\224\250\346\240\210\345\256\236\347\216\260\351\230\237\345\210\227.java" +++ /dev/null @@ -1,81 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 232. 用栈实现队列 - * - * @author Zhang Peng - * @since 2020-01-18 - */ -public class 用栈实现队列 { - - public static void main(String[] args) { - - MyQueue q1 = new MyQueue(); - q1.push(1); // queue is: [1] - q1.push(2); // queue is: [1, 2] (leftmost is front of the queue) - Assertions.assertEquals(1, q1.peek()); - Assertions.assertEquals(1, q1.pop()); - Assertions.assertFalse(q1.empty()); - Assertions.assertEquals(2, q1.pop()); - Assertions.assertTrue(q1.empty()); - - MyQueue q2 = new MyQueue(); - q2.push(1); - q2.push(2); - Assertions.assertEquals(1, q2.pop()); - q2.push(3); - q2.push(4); - Assertions.assertEquals(2, q2.pop()); - Assertions.assertEquals(3, q2.peek()); - - MyQueue q3 = new MyQueue(); - int max = 10; - for (int i = 1; i <= max; i++) { - q3.push(i); - } - for (int i = 1; i <= max; i++) { - Assertions.assertEquals(i, q3.peek()); - Assertions.assertEquals(i, q3.pop()); - } - } - - static class MyQueue { - - private Stack s1; - private Stack s2; - - public MyQueue() { - s1 = new Stack<>(); - s2 = new Stack<>(); - } - - public void push(int x) { - s1.push(x); - } - - public int pop() { - peek(); - Integer top = s2.pop(); - return top == null ? 0 : top; - } - - public int peek() { - if (s2.isEmpty()) { - while (!s1.isEmpty()) { - s2.push(s1.pop()); - } - } - return s2.isEmpty() ? 0 : s2.peek(); - } - - public boolean empty() { - return s1.isEmpty() && s2.isEmpty(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" deleted file mode 100644 index aa7357b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\347\256\200\345\214\226\350\267\257\345\276\204.java" +++ /dev/null @@ -1,50 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 71. 简化路径 - * - * @author Zhang Peng - * @since 2025-08-08 - */ -public class 简化路径 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals("/home", s.simplifyPath("/home/")); - Assertions.assertEquals("/home/foo", s.simplifyPath("/home//foo/")); - Assertions.assertEquals("/home/user/Pictures", s.simplifyPath("/home/user/Documents/../Pictures")); - Assertions.assertEquals("/", s.simplifyPath("/../")); - Assertions.assertEquals("/.../b/d", s.simplifyPath("/.../a/../b/c/../d/./")); - } - - static class Solution { - - public String simplifyPath(String path) { - String[] parts = path.split("/"); - Stack stk = new Stack<>(); - // 借助栈计算最终的文件夹路径 - for (String part : parts) { - if (part.isEmpty() || part.equals(".")) { - continue; - } - if (part.equals("..")) { - if (!stk.isEmpty()) stk.pop(); - continue; - } - stk.push(part); - } - // 栈中存储的文件夹组成路径 - String res = ""; - while (!stk.isEmpty()) { - res = "/" + stk.pop() + res; - } - return res.isEmpty() ? "/" : res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" deleted file mode 100644 index e83ae8f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import org.junit.jupiter.api.Assertions; - -import java.util.Stack; - -/** - * 150. 逆波兰表达式求值 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 逆波兰表达式求值 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(9, s.evalRPN(new String[] { "2", "1", "+", "3", "*" })); - Assertions.assertEquals(6, s.evalRPN(new String[] { "4", "13", "5", "/", "+" })); - Assertions.assertEquals(22, - s.evalRPN(new String[] { "10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+" })); - } - - static class Solution { - - public int evalRPN(String[] tokens) { - Stack stack = new Stack<>(); - for (String token : tokens) { - if ("+".equals(token)) { - Integer numB = stack.pop(); - Integer numA = stack.pop(); - stack.push(numA + numB); - } else if ("-".equals(token)) { - Integer numB = stack.pop(); - Integer numA = stack.pop(); - stack.push(numA - numB); - } else if ("*".equals(token)) { - Integer numB = stack.pop(); - Integer numA = stack.pop(); - stack.push(numA * numB); - } else if ("/".equals(token)) { - Integer numB = stack.pop(); - Integer numA = stack.pop(); - stack.push(numA / numB); - } else { - stack.push(Integer.parseInt(token)); - } - } - return stack.pop(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" deleted file mode 100644 index 48cdd0e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/\351\207\215\346\216\222\351\223\276\350\241\250.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.stack; - -import io.github.dunwu.algorithm.linkedlist.ListNode; -import org.junit.jupiter.api.Assertions; - -import java.util.List; -import java.util.Stack; - -/** - * 143. 重排链表 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 重排链表 { - - public static void main(String[] args) { - - Solution s = new Solution(); - ListNode input = ListNode.buildList(1, 2, 3, 4); - s.reorderList(input); - List list = ListNode.toList(input); - Assertions.assertArrayEquals(new Integer[] { 1, 4, 2, 3 }, list.toArray()); - - ListNode input2 = ListNode.buildList(1, 2, 3, 4, 5); - s.reorderList(input2); - List list2 = ListNode.toList(input2); - Assertions.assertArrayEquals(new Integer[] { 1, 5, 2, 4, 3 }, list2.toArray()); - } - - static class Solution { - - public void reorderList(ListNode head) { - Stack stack = new Stack<>(); - // 先把所有节点装进栈里,得到倒序结果 - ListNode p = head; - while (p != null) { - stack.push(p); - p = p.next; - } - - p = head; - while (p != null) { - // 链表尾部的节点 - ListNode last = stack.pop(); - ListNode next = p.next; - if (last == next || last.next == next) { - // 结束条件,链表节点数为奇数或偶数时均适用 - last.next = null; - break; - } - p.next = last; - last.next = next; - p = next; - } - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/AddBinary.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/AddBinary.java deleted file mode 100644 index 2691220..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/AddBinary.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.github.dunwu.algorithm.str; - -// 【二进制求和】 - -// -// 给定两个二进制字符串,返回他们的和(用二进制表示)。 -// -// 输入为非空字符串且只包含数字 1 和 0。 -// -// 示例 1: -// -// 输入: a = "11", b = "1" -// 输出: "100" -// 示例 2: -// -// 输入: a = "1010", b = "1011" -// 输出: "10101" - -/** - * @author Zhang Peng - * @since 2018-11-04 - */ -public class AddBinary { - - public static String addBinary(String a, String b) { - StringBuilder sb = new StringBuilder(); - int i = a.length() - 1, j = b.length() - 1, carry = 0; - while (i >= 0 || j >= 0) { - int sum = carry; - if (j >= 0) { - sum += b.charAt(j--) - '0'; - } - if (i >= 0) { - sum += a.charAt(i--) - '0'; - } - sb.append(sum % 2); - carry = sum / 2; - } - if (carry != 0) { - sb.append(carry); - } - return sb.reverse().toString(); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ImplementStrstr.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ImplementStrstr.java deleted file mode 100644 index 7b18d18..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ImplementStrstr.java +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.str; - -// 【实现 strStr() 函数】 -// -// 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。 -// -// 示例 1: -// -// 输入: haystack = "hello", needle = "ll" -// 输出: 2 -// 示例 2: -// -// 输入: haystack = "aaaaa", needle = "bba" -// 输出: -1 -// 说明: -// -// 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 -// -// 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class ImplementStrstr { - - public static int strStr(String haystack, String needle) { - if (haystack.equals(needle)) { - return 0; - } - - if (haystack == null || haystack.length() == 0) { - return -1; - } - - if (needle == null || needle.length() == 0) { - return 0; - } - - if (haystack.length() < needle.length()) { - return -1; - } - - int begin = 0; - int i = 0; - int j = 0; - while (i < haystack.length() && begin < haystack.length()) { - if (j == needle.length()) { - return begin; - } else if (haystack.charAt(i) == needle.charAt(j)) { - i++; - j++; - } else { - j = 0; - begin++; - i = begin; - } - } - - if (i == haystack.length() && j == needle.length()) { - return begin; - } - return -1; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/LongestCommonPrefix.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/LongestCommonPrefix.java deleted file mode 100644 index 4e76d0d..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/LongestCommonPrefix.java +++ /dev/null @@ -1,61 +0,0 @@ -package io.github.dunwu.algorithm.str; - -// 【最长公共前缀】 - -// -// 编写一个函数来查找字符串数组中的最长公共前缀。 -// -// 如果不存在公共前缀,返回空字符串 ""。 -// -// 示例 1: -// -// 输入: ["flower","flow","flight"] -// 输出: "fl" -// 示例 2: -// -// 输入: ["dog","racecar","car"] -// 输出: "" -// 解释: 输入不存在公共前缀。 -// 说明: -// -// 所有输入只包含小写字母 a-z 。 - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class LongestCommonPrefix { - - public static String longestCommonPrefix(String[] strs) { - if (strs == null || strs.length == 0) { - return ""; - } - - int index = 0; - StringBuilder sb = new StringBuilder(); - - while (index < strs[0].length()) { - char c = strs[0].charAt(index); - boolean flag = true; - for (String str : strs) { - if (index >= str.length()) { - flag = false; - break; - } - if (str.charAt(index) != c) { - flag = false; - break; - } - } - - if (flag) { - sb.append(c); - index++; - } else { - break; - } - } - return sb.toString(); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseString.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseString.java deleted file mode 100644 index 88400f0..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseString.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.github.dunwu.algorithm.str; - -// 【反转字符串】 - -// -// 编写一个函数,其作用是将输入的字符串反转过来。 -// -// 示例 1: -// -// 输入: "hello" -// 输出: "olleh" -// 示例 2: -// -// 输入: "A man, a plan, a canal: Panama" -// 输出: "amanaP :lanac a ,nalp a ,nam A" - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class ReverseString { - - public static String reverseString(String s) { - StringBuilder sb = new StringBuilder(); - - for (int i = s.length() - 1; i >= 0; i--) { - sb.append(s.charAt(i)); - } - - return sb.toString(); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseWordsInAString.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseWordsInAString.java deleted file mode 100644 index ebceee6..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseWordsInAString.java +++ /dev/null @@ -1,87 +0,0 @@ -package io.github.dunwu.algorithm.str; - -// 【反转字符串中的单词】 - -// -// 给定一个字符串,逐个翻转字符串中的每个单词。 -// -// 示例: -// -// 输入: "the sky is blue", -// 输出: "blue is sky the". -// 说明: -// -// 无空格字符构成一个单词。 -// 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 -// 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 -// 进阶: 请选用C语言的用户尝试使用 O(1) 空间复杂度的原地解法。 - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class ReverseWordsInAString { - - public static String reverseWords(String s) { - if (s == null) { - return null; - } - - char[] a = s.toCharArray(); - int n = a.length; - - // step 1. reverse the whole string - reverse(a, 0, n - 1); - // step 2. reverse each word - reverseWords(a, n); - // step 3. clean up spaces - return cleanSpaces(a, n); - } - - // reverse a[] from a[i] to a[j] - private static void reverse(char[] a, int i, int j) { - while (i < j) { - char t = a[i]; - a[i++] = a[j]; - a[j--] = t; - } - } - - private static void reverseWords(char[] a, int n) { - int i = 0, j = 0; - - while (i < n) { - while (i < j || i < n && a[i] == ' ') { - i++; // skip spaces - } - while (j < i || j < n && a[j] != ' ') { - j++; // skip non spaces - } - // reverse the word - reverse(a, i, j - 1); - } - } - - // trim leading, trailing and multiple spaces - private static String cleanSpaces(char[] a, int n) { - int i = 0, j = 0; - - while (j < n) { - while (j < n && a[j] == ' ') { - j++; // skip spaces - } - while (j < n && a[j] != ' ') { - a[i++] = a[j++]; // keep non spaces - } - while (j < n && a[j] == ' ') { - j++; // skip spaces - } - if (j < n) { - a[i++] = ' '; // keep only one space - } - } - - return new String(a).substring(0, i); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseWordsInAString3.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseWordsInAString3.java deleted file mode 100644 index 2e2ab6b..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ReverseWordsInAString3.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dunwu.algorithm.str; - -// 【反转字符串中的单词 III】 - -// -// 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 -// -// 示例 1: -// -// 输入: "Let's take LeetCode contest" -// 输出: "s'teL ekat edoCteeL tsetnoc" -// 注意:在字符串中,每个单词由单个空格分隔,并且字符串中不会有任何额外的空格。 - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class ReverseWordsInAString3 { - - public static String reverseWords(String s) { - StringBuilder sb = new StringBuilder(); - String[] strs = s.split(" "); - for (int index = 0; index < strs.length; index++) { - int i = 0; - int j = strs[index].length() - 1; - - char[] a = strs[index].toCharArray(); - while (i < j) { - char t = a[i]; - a[i++] = a[j]; - a[j--] = t; - } - - sb.append(a); - if (index != strs.length - 1) { - sb.append(" "); - } - } - - return sb.toString(); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/StringAlgorithm.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/StringAlgorithm.java deleted file mode 100644 index b0a3d12..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/StringAlgorithm.java +++ /dev/null @@ -1,293 +0,0 @@ -package io.github.dunwu.algorithm.str; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author Zhang Peng - * @since 2020-01-18 - */ -public class StringAlgorithm { - - /** - * 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 - *

- * 示例 1: - *

- * 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 示例 2: - *

- * 输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 示例 3: - *

- * 输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 - *

- * 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 - * - * @see 无重复字符的最长子串 - */ - public static int lengthOfLongestSubstring(String s) { - if (null == s || s.length() == 0) { - return 0; - } - - int max = 0; - int left = 0; - Map map = new HashMap<>(); - for (int i = 0; i < s.length(); i++) { - if (map.containsKey(s.charAt(i))) { - left = Math.max(left, map.get(s.charAt(i)) + 1); - } - map.put(s.charAt(i), i); - max = Math.max(max, i - left + 1); - } - return max; - } - - /** - * 编写一个函数来查找字符串数组中的最长公共前缀。 - *

- * 如果不存在公共前缀,返回空字符串 ""。 - *

- * 示例 1: - *

- * 输入: ["flower","flow","flight"] 输出: "fl" 示例 2: - *

- * 输入: ["dog","racecar","car"] 输出: "" 解释: 输入不存在公共前缀。 说明: - *

- * 所有输入只包含小写字母 a-z 。 - * - * @see 最长公共前缀 - */ - public static String longestCommonPrefix(String[] array) { - if (array == null || array.length == 0) { - return ""; - } else if (array.length == 1) { - return array[0]; - } else { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < array[0].length(); i++) { - char c = array[0].charAt(i); - boolean end = false; - for (int index = 1; index < array.length; index++) { - if (array[index].length() - 1 < i) { - end = true; - break; - } - - if (array[index].charAt(i) != c) { - end = true; - break; - } - } - if (end) { - break; - } else { - sb.append(c); - } - } - return sb.toString(); - } - } - - /** - * 给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。 - *

- * 换句话说,第一个字符串的排列之一是第二个字符串的子串。 - *

- * 示例1: 输入: s1 = "ab" s2 = "eidbaooo" 输出: True 解释: s2 包含 s1 的排列之一 ("ba"). - *

- * 示例2: 输入: s1= "ab" s2 = "eidboaoo" 输出: False - *

- * 注意:输入的字符串只包含小写字母,两个字符串的长度都在 [1, 10,000] 之间 - * - * @see 字符串的排列 - */ - public static boolean checkInclusion(String s1, String s2) { - if (s1 == null || s1.length() == 0 || s2 == null || s2.length() == 0) { - return false; - } - - int len1 = s1.length(); - int len2 = s2.length(); - - // 字母命中数统计 - int[] count1 = new int[26]; - int[] count2 = new int[26]; - - for (char c : s1.toCharArray()) { - count1[c - 'a']++; - } - - for (int i = 0; i < len2; i++) { - if (i >= len1) { - count2[s2.charAt(i - len1) - 'a']--; - } - - count2[s2.charAt(i) - 'a']++; - if (Arrays.equals(count1, count2)) { - return true; - } - } - return false; - } - - /** - * 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。 - *

- * 示例 1: - *

- * 输入: num1 = "2", num2 = "3" 输出: "6" 示例 2: - *

- * 输入: num1 = "123", num2 = "456" 输出: "56088" - *

- * 说明:num1 和 num2 的长度小于110。 num1 和 num2 只包含数字 0-9。 num1 和 num2 均不以零开头,除非是数字 0 本身。 - *

- * 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。 - * - * @see 字符串相乘 - */ - public static String multiply(String num1, String num2) { - if (num1.equals("0") || num2.equals("0")) { - return "0"; - } - - String result = "0"; - for (int i = num1.length() - 1; i >= 0; i--) { - - int carry = 0; - - StringBuilder tempBuilder = new StringBuilder(); - int value1 = num1.charAt(i) - '0'; - - for (int temp = i; temp < num1.length() - 1; temp++) { - tempBuilder.append("0"); - } - - for (int j = num2.length() - 1; j >= 0; j--) { - int value2 = num2.charAt(j) - '0'; - int value = value1 * value2 + carry; - int current = value % 10; - carry = value / 10; - tempBuilder.append(current); - } - - if (carry > 0) { - tempBuilder.append(carry); - } - - result = add(result, tempBuilder.reverse().toString()); - } - - return result; - } - - public static String add(String num1, String num2) { - StringBuilder builder = new StringBuilder(); - int carry = 0; - - for (int i = num1.length() - 1, j = num2.length() - 1; - i >= 0 || j >= 0; - i--, j--) { - - int result = carry; - if (i >= 0) { - result += num1.charAt(i) - '0'; - } - if (j >= 0) { - result += num2.charAt(j) - '0'; - } - carry = result / 10; - int current = result % 10; - builder.append(current); - } - if (carry > 0) { - builder.append(carry); - } - return builder.reverse().toString(); - } - - /** - * 给定一个字符串,逐个翻转字符串中的每个单词。 - *

- * 示例 1: 输入: "the sky is blue" 输出: "blue is sky the" - *

- * 示例 2: 输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 - *

- * 示例 3: 输入: "a good example" 输出: "example good a" 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 - *

- * 说明: 无空格字符构成一个单词。 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 - *

- * 进阶: 请选用 C 语言的用户尝试使用 O(1) 额外空间复杂度的原地解法。 - * - * @see 翻转字符串里的单词 - */ - public static String reverseWords(String s) { - StringBuilder builder = new StringBuilder(); - List list = new ArrayList<>(); - for (char c : s.toCharArray()) { - if (c != ' ') { - builder.append(c); - } else { - if (!builder.toString().equals("")) { - list.add(builder.toString()); - } - builder = new StringBuilder(); - } - } - if (!builder.toString().equals("")) { - list.add(builder.toString()); - } - - builder = new StringBuilder(); - for (int i = list.size() - 1; i >= 0; i--) { - - builder.append(list.get(i)); - if (i != 0) { - builder.append(" "); - } - } - return builder.toString(); - } - - /** - * 以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。 - *

- * 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs - * 相对路径 - *

- * 请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。 - *

- * 示例 1: 输入:"/home/" 输出:"/home" 解释:注意,最后一个目录名后面没有斜杠。 - *

- * 示例 2: 输入:"/../" 输出:"/" 解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。 - *

- * 示例 3: 输入:"/home//foo/" 输出:"/home/foo" 解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。 - *

- * 示例 4: 输入:"/a/./b/../../c/" 输出:"/c" - *

- * 示例 5: 输入:"/a/../../b/../c//.//" 输出:"/c" - *

- * 示例 6: 输入:"/a//b////c/d//././/.." 输出:"/a/b/c" - * - * @see 简化路径 - */ - public static String simplifyPath(String path) { - if (path.equals("/")) { - return path; - } - - if (path.endsWith("/")) { - path = path.substring(0, path.length() - 1); - } - - if (path.startsWith("/../")) { - path = path.replaceFirst("/../", "/"); - } - - path = path.replaceAll("//", "/"); - return path; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ValidAnagram.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ValidAnagram.java deleted file mode 100644 index 1dd91de..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/str/ValidAnagram.java +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.str; - -import java.util.HashMap; -import java.util.Map; - -/* -@see https://leetcode.com/problems/valid-anagram/ - -Given two strings s and t , write a function to determine if t is an anagram of s. - -Example 1: - -Input: s = "anagram", t = "nagaram" -Output: true -Example 2: - -Input: s = "rat", t = "car" -Output: false -Note: -You may assume the string contains only lowercase alphabets. - -Follow up: -What if the inputs contain unicode characters? How would you adapt your solution to such case? -*/ -public class ValidAnagram { - - public static void main(String[] args) { - boolean result1 = isAnagram("anagram", "nagaram"); - boolean result2 = isAnagram("rat", "car"); - boolean result3 = isAnagram("a", "ab"); - System.out.println("result:" + result1); - System.out.println("result:" + result2); - System.out.println("result:" + result3); - } - - public static boolean isAnagram(String s, String t) { - if (s == null && t == null) { return true; } else if (s == null || t == null) { - return false; - } else if (s.length() != t.length()) { return false; } - - Map map = new HashMap(); - for (int i = 0; i < s.length(); i++) { - if (map.containsKey(s.charAt(i))) { - Integer count = map.get(s.charAt(i)); - ++count; - map.remove(s.charAt(i)); - map.put(s.charAt(i), count); - } else { - map.put(s.charAt(i), 1); - } - } - - Map map2 = new HashMap(); - for (int j = 0; j < t.length(); j++) { - if (map2.containsKey(t.charAt(j))) { - Integer count = map2.get(t.charAt(j)); - ++count; - map2.remove(t.charAt(j)); - map2.put(t.charAt(j), count); - } else { - map2.put(t.charAt(j), 1); - } - } - - if (map.size() != map2.size()) { - return false; - } - - for (Map.Entry entry1 : map.entrySet()) { - Integer m1value = entry1.getValue() == null ? 0 : entry1.getValue(); - Integer m2value = map2.get(entry1.getKey()) == null ? 0 : map2.get(entry1.getKey()); - if (!m1value.equals(m2value)) { - return false; - } - } - return true; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java deleted file mode 100644 index cac20fd..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BTree.java +++ /dev/null @@ -1,370 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; -import java.util.Queue; - -/** - * 二叉树 - * - * @author Zhang Peng - * @since 2020-01-28 - */ -public class BTree> { - - /** - * 二叉树根节点 - */ - private TreeNode root; - - public BTree() { - this.root = null; - } - - public BTree(TreeNode root) { - this.root = root; - } - - public static > BTree build(T... array) { - BTree tree = new BTree<>(); - List> list = new ArrayList<>(); - - for (T value : array) { - // 创建结点,每一个结点的左结点和右结点为null - TreeNode node; - if (value == null) { - node = null; - } else { - node = new TreeNode<>(value, null, null); - } - // list中存着每一个结点 - list.add(node); - } - - // 构建二叉树 - if (list.size() > 0) { - // i表示的是根节点的索引,从0开始 - for (int i = 0; i < array.length / 2 - 1; i++) { - if (list.get(2 * i + 1) != null) { - // 左结点 - list.get(i).left = list.get(2 * i + 1); - } - if (list.get(2 * i + 2) != null) { - // 右结点 - list.get(i).right = list.get(2 * i + 2); - } - } - // 判断最后一个根结点:因为最后一个根结点可能没有右结点,所以单独拿出来处理 - int lastIndex = array.length / 2 - 1; - // 左结点 - list.get(lastIndex).left = list.get(lastIndex * 2 + 1); - // 右结点,如果数组的长度为奇数才有右结点 - if (array.length % 2 == 1) { - list.get(lastIndex).right = list.get(lastIndex * 2 + 2); - } - - tree.root = list.get(0); - } else { - tree.root = null; - } - return tree; - } - - /** - * 判断两颗二叉树是否完全一致 - *

- * 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 - * - * @param tree1 {@link BTree} - * @param tree2 {@link BTree} - * @param 元素类型 - * @return true / false - */ - public static > boolean isEquals(final BTree tree1, final BTree tree2) { - return TreeNode.isEquals(tree1.root, tree2.root); - } - - /** - * 判断两颗二叉树的叶子节点是否相似 - * - * @param tree1 {@link BTree} - * @param tree2 {@link BTree} - * @return true / false - * @see 叶子相似的树 - */ - public static > boolean isLeafSimilar(final BTree tree1, final BTree tree2) { - List leafs1 = TreeNode.getLeafNodes(tree1.root); - List leafs2 = TreeNode.getLeafNodes(tree2.root); - return Arrays.equals(leafs1.toArray(), leafs2.toArray()); - } - - /** - * 获取叶子节点 - */ - public List getLeafNodes() { - return TreeNode.getLeafNodes(this.root); - } - - /** - * 返回二叉树的最大深度 - * - * @return 二叉树的最大深度 - */ - public int maxDepth() { - return TreeNode.maxDepth(this.root); - } - - /** - * 返回二叉树的最小深度 - * - * @return 二叉树的最小深度 - */ - public int minDepth() { - return TreeNode.minDepth(this.root); - } - - // ------------------------------------------------------------- 遍历元素 - - /** - * 将二叉树按层次遍历顺序转换为列表,即广度优先搜索(BFS) - * - * @return {@link List>} - */ - public List> levelOrderLists() { - return TreeNode.levelOrderLists(this.root); - } - - public static class TreeNode> { - - T val; - - TreeNode left; - - TreeNode right; - - public TreeNode(T val) { - this.val = val; - } - - public TreeNode(T val, TreeNode left, TreeNode right) { - this.val = val; - this.left = left; - this.right = right; - } - - @Override - public String toString() { - return String.valueOf(val); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof TreeNode)) return false; - TreeNode treeNode = (TreeNode) o; - return Objects.equals(val, treeNode.val) && - Objects.equals(left, treeNode.left) && - Objects.equals(right, treeNode.right); - } - - @Override - public int hashCode() { - return Objects.hash(val, left, right); - } - - public static > TreeNode build(T... values) { - - if (values == null || values.length == 0 || values[0] == null) { - return null; - } - - Queue> queue = new LinkedList<>(); - TreeNode root = new TreeNode<>(values[0]); - queue.offer(root); - - int i = 1; - while (!queue.isEmpty()) { - TreeNode current = queue.poll(); - - // 处理左子节点 - if (i < values.length && values[i] != null) { - current.left = new TreeNode(values[i]); - queue.offer(current.left); - } - i++; - - // 处理右子节点 - if (i < values.length && values[i] != null) { - current.right = new TreeNode(values[i]); - queue.offer(current.right); - } - i++; - } - - return root; - } - - public static > TreeNode find(TreeNode root, T val) { - if (root == null || Objects.equals(root.val, val)) { return root; } - TreeNode left = find(root.left, val); - if (left != null) return left; - return find(root.right, val); - } - - public static > List> toList(TreeNode root) { - List> list = new ArrayList<>(); - if (root == null) { - return list; - } - - Queue> queue = new LinkedList<>(); - queue.add(root); - while (!queue.isEmpty()) { - TreeNode node = queue.poll(); - list.add(node); - if (node == null) continue; - queue.add(node.left); - queue.add(node.right); - } - - // 删除队列尾部的所有 null - int last = list.size() - 1; - while (last > 0 && list.get(last) == null) { - last--; - } - return list.subList(0, last + 1); - } - - public static > List toValueList(TreeNode root) { - List list = new ArrayList<>(); - if (root == null) { - return list; - } - - Queue> queue = new LinkedList<>(); - queue.add(root); - while (!queue.isEmpty()) { - TreeNode node = queue.poll(); - if (node == null) { - list.add(null); - continue; - } else { - list.add(node.val); - } - - queue.add(node.left); - queue.add(node.right); - } - - // 删除队列尾部的所有 null - int last = list.size() - 1; - while (last > 0 && list.get(last) == null) { - last--; - } - return list.subList(0, last + 1); - } - - /** - * 判断两颗二叉树是否完全一致 - * - * @param root1 二叉树根节点,类型:{@link BTree#root} - * @param root2 二叉树根节点,类型:{@link BTree#root} - * @param 元素类型 - * @return true / false - * @see 相同的树 - */ - private static > boolean isEquals(TreeNode root1, TreeNode root2) { - if (root1 == null && root2 == null) { return true; } - if (root1 == null || root2 == null) { return false; } - if (!root1.val.equals(root2.val)) { return false; } - return isEquals(root1.left, root2.left) && isEquals(root1.right, root2.right); - } - - /** - * 获取叶子节点 - * - * @param root {@link TreeNode} - * @param 元素类型 - */ - public static > List getLeafNodes(TreeNode root) { - List res = new ArrayList<>(); - getLeafNodes(root, res); - return res; - } - - /** - * 获取叶子节点 - * - * @param root {@link TreeNode} - * @param leafs [出参]叶子节点列表{@link List} - * @param 元素类型 - */ - private static > void getLeafNodes(TreeNode root, List leafs) { - if (root == null) { return; } - if (root.left == null && root.right == null) { leafs.add(root.val); } - getLeafNodes(root.left, leafs); - getLeafNodes(root.right, leafs); - } - - /** - * 采用递归方法获取二叉树的最大深度 - * - * @param root 二叉树根节点,类型:{@link BTree#root} - * @return 二叉树的最大深度 - * @see 二叉树的最大深度 - */ - public static > int maxDepth(TreeNode root) { - if (root == null) { return 0; } - int left = maxDepth(root.left); - int right = maxDepth(root.right); - return Math.max(left, right) + 1; - } - - /** - * 采用递归方法获取二叉树的最小深度 - * - * @param root 二叉树根节点,类型:{@link BTree#root} - * @return 二叉树的最小深度 - * @see 二叉树的最小深度 - */ - public static > int minDepth(TreeNode root) { - if (root == null) { return 0; } - int left = minDepth(root.left); - int right = minDepth(root.right); - if (left == 0 || right == 0) { - return left + right + 1; - } - return Math.min(left, right) + 1; - } - - /** - * 将二叉树按层次遍历顺序转换为列表,即广度优先搜索(BFS) - * - * @return {@link List>} - * @see 二叉树的层次遍历 II - */ - public static > List> levelOrderLists(TreeNode root) { - List> lists = new ArrayList<>(); - if (root == null) { return lists; } - Queue> queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - List list = new ArrayList<>(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - list.add(node.val); - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - } - lists.add(list); - } - return lists; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java deleted file mode 100644 index 8da17c6..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/BaseCase.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import java.util.List; - -/** - * 基本示例 - * - * @author Zhang Peng - * @date 2025-10-27 - */ -public class BaseCase { - - public static class Node extends NTree { - - public Node(int val) { - super(val); - } - - public Node(int val, List children) { - super(val, children); - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NTree.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NTree.java deleted file mode 100644 index 664e896..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/NTree.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import java.util.LinkedList; -import java.util.List; - -/** - * N 叉树 - * - * @author Zhang Peng - * @date 2025-10-27 - */ -public class NTree> { - - public int val; - public List children; - - public NTree() { - val = -1; - children = new LinkedList<>(); - } - - public NTree(int val) { - this.val = val; - this.children = new LinkedList<>(); - } - - public NTree(int val, List children) { - this.val = val; - this.children = children; - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java deleted file mode 100644 index 8c295ec..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/Node.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import java.util.LinkedList; -import java.util.List; - -// 多叉树节点 -public class Node { - - public int val; - public List children; - - public Node() { - val = -1; - children = new LinkedList<>(); - } - - public Node(int val) { - this.val = val; - this.children = new LinkedList<>(); - } - - public Node(int val, List children) { - this.val = val; - this.children = children; - } - -} \ No newline at end of file diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/State.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/State.java deleted file mode 100644 index 9f19b02..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/State.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -// 多叉树的层序遍历 -// 每个节点自行维护 State 类,记录深度等信息 -public class State { - - public Node node; - public int depth; - - public State(Node node, int depth) { - this.node = node; - this.depth = depth; - } - -} \ No newline at end of file diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java deleted file mode 100644 index 632d59e..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeNode.java +++ /dev/null @@ -1,187 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; -import java.util.Queue; - -/** - * 二叉树节点 - * - * @author Zhang Peng - * @since 2020-01-28 - */ -public class TreeNode { - - public int val; - - public TreeNode left; - - public TreeNode right; - - public TreeNode(int val) { this.val = val; } - - public TreeNode(int val, TreeNode left, TreeNode right) { - this.val = val; - this.left = left; - this.right = right; - } - - @Override - public String toString() { - return String.valueOf(val); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof TreeNode)) return false; - TreeNode treeNode = (TreeNode) o; - return val == treeNode.val && - Objects.equals(left, treeNode.left) && - Objects.equals(right, treeNode.right); - } - - @Override - public int hashCode() { - return Objects.hash(val, left, right); - } - - public static String serialize(TreeNode root) { - return serialize(root, "NULL", ","); - } - - public static String serialize(TreeNode root, String nullFlag, String sepFlag) { - StringBuilder sb = new StringBuilder(); - doSerialize(root, sb, nullFlag, sepFlag); - return sb.toString(); - } - - static void doSerialize(TreeNode root, StringBuilder sb, String nullFlag, String sepFlag) { - if (root == null) { - sb.append(nullFlag).append(sepFlag); - return; - } - sb.append(root.val).append(sepFlag); - doSerialize(root.left, sb, nullFlag, sepFlag); - doSerialize(root.right, sb, nullFlag, sepFlag); - } - - public static TreeNode deserialize(String data) { - return deserialize(data, "NULL", ","); - } - - public static TreeNode deserialize(String data, String nullFlag, String sepFlag) { - LinkedList nodes = new LinkedList<>(Arrays.asList(data.split(sepFlag))); - return doDeserialize(nodes, nullFlag); - } - - static TreeNode doDeserialize(LinkedList nodes, String nullFlag) { - if (nodes.isEmpty()) return null; - - // =============== 前序遍历处理 =============== - String val = nodes.removeFirst(); - if (nullFlag.equals(val)) { return null; } - TreeNode root = new TreeNode(Integer.parseInt(val)); - // ========================================== - - root.left = doDeserialize(nodes, nullFlag); - root.right = doDeserialize(nodes, nullFlag); - return root; - } - - public static TreeNode buildTree(Integer... values) { - - if (values == null || values.length == 0 || values[0] == null) { - return null; - } - - Queue queue = new LinkedList<>(); - TreeNode root = new TreeNode(values[0]); - queue.offer(root); - - int i = 1; - while (!queue.isEmpty() && i < values.length) { - TreeNode current = queue.poll(); - - // 处理左子节点 - if (i < values.length && values[i] != null) { - current.left = new TreeNode(values[i]); - queue.offer(current.left); - } - i++; - - // 处理右子节点 - if (i < values.length && values[i] != null) { - current.right = new TreeNode(values[i]); - queue.offer(current.right); - } - i++; - } - - return root; - } - - public static TreeNode find(TreeNode root, int val) { - if (root == null || root.val == val) { return root; } - TreeNode left = find(root.left, val); - if (left != null) return left; - return find(root.right, val); - } - - public static List toList(TreeNode root) { - List list = new ArrayList<>(); - if (root == null) { - return list; - } - - Queue queue = new LinkedList<>(); - queue.add(root); - while (!queue.isEmpty()) { - TreeNode node = queue.poll(); - list.add(node); - if (node == null) continue; - queue.add(node.left); - queue.add(node.right); - } - - // 删除队列尾部的所有 null - int last = list.size() - 1; - while (last > 0 && list.get(last) == null) { - last--; - } - return list.subList(0, last + 1); - } - - public static List toValueList(TreeNode root) { - List list = new ArrayList<>(); - if (root == null) { - return list; - } - - Queue queue = new LinkedList<>(); - queue.add(root); - while (!queue.isEmpty()) { - TreeNode node = queue.poll(); - if (node == null) { - list.add(null); - continue; - } else { - list.add(node.val); - } - - queue.add(node.left); - queue.add(node.right); - } - - // 删除队列尾部的所有 null - int last = list.size() - 1; - while (last > 0 && list.get(last) == null) { - last--; - } - return list.subList(0, last + 1); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/package-info.java deleted file mode 100644 index e48ff20..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 二叉搜索树算法 - * - * @author Zhang Peng - * @since 2020-07-07 - */ -package io.github.dunwu.algorithm.tree.bstree; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" deleted file mode 100644 index c2d9a86..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import org.junit.jupiter.api.Assertions; - -/** - * 96. 不同的二叉搜索树 - * - * @author Zhang Peng - * @date 2025-10-22 - */ -public class 不同的二叉搜索树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(5, s.numTrees(3)); - Assertions.assertEquals(1, s.numTrees(1)); - } - - static class Solution { - - // 备忘录 - int[][] memo; - - // 主函数 - public int numTrees(int n) { - // 备忘录的值初始化 - memo = new int[n + 1][n + 1]; - // 计算闭区间 [1, n] 组成的 BST 个数 - return count(1, n); - } - - // 计算闭区间 [lo, hi] 组成的 BST 个数 - int count(int low, int high) { - // base case - if (low > high) { return 1; } - if (memo[low][high] != 0) { return memo[low][high]; } - - int res = 0; - for (int i = low; i <= high; i++) { - // i 的值作为根节点 root - int left = count(low, i - 1); - int right = count(i + 1, high); - // 左右子树的组合数乘积是 BST 的总数 - res += left * right; - } - memo[low][high] = res; - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" deleted file mode 100644 index 19d183b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\270\215\345\220\214\347\232\204\344\272\214\345\217\211\346\220\234\347\264\242\346\240\2212.java" +++ /dev/null @@ -1,85 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * 95. 不同的二叉搜索树 II - * - * @author Zhang Peng - * @date 2025-10-22 - */ -public class 不同的二叉搜索树2 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - List output1 = s.generateTrees(3); - LinkedList> expectList1 = new LinkedList<>(); - expectList1.add(new LinkedList<>(Arrays.asList(1, null, 2, null, 3))); - expectList1.add(new LinkedList<>(Arrays.asList(1, null, 3, 2))); - expectList1.add(new LinkedList<>(Arrays.asList(2, 1, 3))); - expectList1.add(new LinkedList<>(Arrays.asList(3, 1, null, null, 2))); - expectList1.add(new LinkedList<>(Arrays.asList(3, 2, null, 1))); - Assertions.assertEquals(expectList1.size(), output1.size()); - output1.forEach(tree -> { - List expect = expectList1.poll(); - Assertions.assertArrayEquals(expect.toArray(), TreeNode.toValueList(tree).toArray()); - }); - - List output2 = s.generateTrees(1); - LinkedList> expectList2 = new LinkedList<>(); - expectList2.add(new LinkedList<>(Collections.singletonList(1))); - Assertions.assertEquals(expectList2.size(), output2.size()); - output2.forEach(tree -> { - List expect = expectList2.poll(); - Assertions.assertArrayEquals(expect.toArray(), TreeNode.toValueList(tree).toArray()); - }); - } - - static class Solution { - - // 主函数 - public List generateTrees(int n) { - if (n == 0) return new LinkedList<>(); - // 构造闭区间 [1, n] 组成的 BST - return build(1, n); - } - - // 构造闭区间 [low, high] 组成的 BST - List build(int low, int high) { - List res = new LinkedList<>(); - // base case - if (low > high) { - res.add(null); - return res; - } - - // 1、穷举 root 节点的所有可能。 - for (int i = low; i <= high; i++) { - // 2、递归构造出左右子树的所有合法 BST。 - List leftTree = build(low, i - 1); - List rightTree = build(i + 1, high); - // 3、给 root 节点穷举所有左右子树的组合。 - for (TreeNode left : leftTree) { - for (TreeNode right : rightTree) { - // i 作为根节点 root 的值 - TreeNode root = new TreeNode(i); - root.left = left; - root.right = right; - res.add(root); - } - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" deleted file mode 100644 index 42aa113..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\345\255\220\346\240\221\347\232\204\346\234\200\345\244\247\351\224\256\345\200\274\345\222\214.java" +++ /dev/null @@ -1,76 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 96. 不同的二叉搜索树 - * - * @author Zhang Peng - * @date 2025-10-22 - */ -public class 二叉搜索子树的最大键值和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(20, - s.maxSumBST(TreeNode.buildTree(1, 4, 3, 2, 4, 2, 5, null, null, null, null, null, null, 4, 6))); - Assertions.assertEquals(2, s.maxSumBST(TreeNode.buildTree(4, 3, null, 1, 2))); - Assertions.assertEquals(0, s.maxSumBST(TreeNode.buildTree(-4, -2, -5))); - Assertions.assertEquals(6, s.maxSumBST(TreeNode.buildTree(2, 1, 3))); - Assertions.assertEquals(7, s.maxSumBST(TreeNode.buildTree(5, 4, 8, 3, null, 6, 3))); - } - - static class Solution { - - // 记录 BST 最大节点之和 - private int maxSum = 0; - - public int maxSumBST(TreeNode root) { - maxSum = 0; - findMaxMinSum(root); - return maxSum; - } - - // 计算以 root 为根的二叉树的最大值、最小值、节点和 - int[] findMaxMinSum(TreeNode root) { - // base case - if (root == null) { - return new int[] { - 1, Integer.MAX_VALUE, Integer.MIN_VALUE, 0 - }; - } - - // 递归计算左右子树 - int[] left = findMaxMinSum(root.left); - int[] right = findMaxMinSum(root.right); - - // ******* 后序位置 ******* - // 通过 left 和 right 推导返回值 - // 并且正确更新 maxSum 变量 - int[] res = new int[4]; - // 这个 if 在判断以 root 为根的二叉树是不是 BST - if (left[0] == 1 && right[0] == 1 && - root.val > left[2] && root.val < right[1]) { - // 以 root 为根的二叉树是 BST - res[0] = 1; - // 计算以 root 为根的这棵 BST 的最小值 - res[1] = Math.min(left[1], root.val); - // 计算以 root 为根的这棵 BST 的最大值 - res[2] = Math.max(right[2], root.val); - // 计算以 root 为根的这棵 BST 所有节点之和 - res[3] = left[3] + right[3] + root.val; - // 更新全局变量 - maxSum = Math.max(maxSum, res[3]); - } else { - // 以 root 为根的二叉树不是 BST - res[0] = 0; - // 其他的值都没必要计算了,因为用不到 - } - - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" deleted file mode 100644 index 9a6925c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\217\222\345\205\245\346\223\215\344\275\234.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 701. 二叉搜索树中的插入操作 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 二叉搜索树中的插入操作 { - - public static void main(String[] args) { - TreeNode input1 = TreeNode.buildTree(4, 2, 7, 1, 3); - TreeNode output1 = insertIntoBST(input1, 5); - Assertions.assertArrayEquals(new Integer[] { 4, 2, 7, 1, 3, 5 }, TreeNode.toValueList(output1).toArray()); - - TreeNode input2 = TreeNode.buildTree(40, 20, 60, 10, 30, 50, 70); - TreeNode output2 = insertIntoBST(input2, 25); - Assertions.assertArrayEquals(new Integer[] { 40, 20, 60, 10, 30, 50, 70, null, null, 25 }, - TreeNode.toValueList(output2).toArray()); - - TreeNode input3 = TreeNode.buildTree(4, 2, 7, 1, 3, null, null, null, null, null, null); - TreeNode output3 = insertIntoBST(input3, 5); - Assertions.assertArrayEquals(new Integer[] { 4, 2, 7, 1, 3, 5 }, - TreeNode.toValueList(output3).toArray()); - } - - public static TreeNode insertIntoBST(TreeNode root, int val) { - if (root == null) { return new TreeNode(val); } - if (root.val < val) { - root.right = (root.right == null) ? new TreeNode(val) : insertIntoBST(root.right, val); - } else { - root.left = (root.left == null) ? new TreeNode(val) : insertIntoBST(root.left, val); - } - return root; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.java" deleted file mode 100644 index 9650df6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\346\220\234\347\264\242.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 538. 把二叉搜索树转换为累加树 - * - * @author Zhang Peng - * @date 2025-10-22 - */ -public class 二叉搜索树中的搜索 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - TreeNode input1 = TreeNode.buildTree(4, 2, 7, 1, 3); - TreeNode output1 = s.searchBST(input1, 2); - Assertions.assertArrayEquals(new Integer[] { 2, 1, 3 }, TreeNode.toValueList(output1).toArray()); - - TreeNode output2 = s.searchBST(input1, 5); - Assertions.assertNull(output2); - } - - static class Solution { - - public TreeNode searchBST(TreeNode root, int val) { - if (root == null) { return null; } - if (root.val == val) { - return root; - } else if (root.val < val) { - return searchBST(root.right, val); - } else { - return searchBST(root.left, val); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" deleted file mode 100644 index 5ce506e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.java" +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 98. 验证二叉搜索树 - * - * @author Zhang Peng - * @date 2025-10-22 - */ -public class 二叉搜索树中第K小的元素 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(1, s.kthSmallest(TreeNode.buildTree(3, 1, 4, null, 2), 1)); - Assertions.assertEquals(3, s.kthSmallest(TreeNode.buildTree(5, 3, 6, 2, 4, null, null, 1), 3)); - } - - static class Solution { - - private int rank = 1; - private int res = 0; - - public int kthSmallest(TreeNode root, int k) { - rank = 1; - res = 0; - dfs(root, k); - return res; - } - - void dfs(TreeNode root, int k) { - if (root == null) { return; } - dfs(root.left, k); - if (rank++ == k) { - res = root.val; - return; - } - dfs(root.right, k); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" deleted file mode 100644 index 5b8039e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 235. 二叉搜索树的最近公共祖先 - * - * @author Zhang Peng - * @date 2025-10-22 - */ -public class 二叉搜索树的最近公共祖先 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - TreeNode root = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); - - TreeNode node1 = s.lowestCommonAncestor(root, TreeNode.find(root, 2), TreeNode.find(root, 8)); - Assertions.assertNotNull(node1); - Assertions.assertEquals(6, node1.val); - - TreeNode node2 = s.lowestCommonAncestor(root, TreeNode.find(root, 2), TreeNode.find(root, 4)); - Assertions.assertNotNull(node2); - Assertions.assertEquals(2, node2.val); - } - - static class Solution { - - public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { - if (root == null) return null; - if (p.val > q.val) { - // 保证 p.val <= q.val,便于后续情况讨论 - return lowestCommonAncestor(root, q, p); - } - if (root.val >= p.val && root.val <= q.val) { - // p <= root <= q - // 即 p 和 q 分别在 root 的左右子树,那么 root 就是 LCA - return root; - } - if (root.val > q.val) { - // p 和 q 都在 root 的左子树,那么 LCA 在左子树 - return lowestCommonAncestor(root.left, p, q); - } else { - // p 和 q 都在 root 的右子树,那么 LCA 在右子树 - return lowestCommonAncestor(root.right, p, q); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" deleted file mode 100644 index 884b648..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\212\202\347\202\271\346\234\200\345\260\217\350\267\235\347\246\273.java" +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 783. 二叉搜索树节点最小距离 - * - * @author Zhang Peng - * @date 2020-06-18 - */ -public class 二叉搜索树节点最小距离 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(1, s.minDiffInBST(TreeNode.buildTree(4, 2, 6, 1, 3))); - Assertions.assertEquals(1, s.minDiffInBST(TreeNode.buildTree(1, 0, 48, null, null, 12, 49))); - } - - static class Solution { - - private int pre; - private int res; - - public int minDiffInBST(TreeNode root) { - pre = -1; - res = Integer.MAX_VALUE; - dfs(root); - return res; - } - - public void dfs(TreeNode root) { - // base case - if (root == null) { return; } - - // 【前序】 - dfs(root.left); - - // 【中序】中序保证递增有序 - if (pre != -1) { - res = Math.min(res, Math.abs(root.val - pre)); - } - pre = root.val; - - // 【后序】 - dfs(root.right); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221.java" deleted file mode 100644 index e76ff50..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221.java" +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 538. 把二叉搜索树转换为累加树 - * - * @author Zhang Peng - * @date 2025-10-22 - */ -public class 从二叉搜索树到更大和树 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - TreeNode input1 = TreeNode.buildTree(4, 1, 6, 0, 2, 5, 7, null, null, null, 3, null, null, null, 8); - TreeNode output1 = s.bstToGst(input1); - TreeNode expect1 = TreeNode.buildTree(30, 36, 21, 36, 35, 26, 15, null, null, null, 33, null, null, null, 8); - Assertions.assertEquals(expect1, output1); - - Assertions.assertEquals(TreeNode.buildTree(1, null, 1), s.bstToGst(TreeNode.buildTree(0, null, 1))); - } - - static class Solution { - - private int sum = 0; - - public TreeNode bstToGst(TreeNode root) { - sum = 0; - dfs(root); - return root; - } - - public void dfs(TreeNode root) { - if (root == null) { return; } - dfs(root.right); - sum += root.val; - root.val = sum; - // System.out.printf("%s\n", root.val); - dfs(root.left); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" deleted file mode 100644 index e088862..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271.java" +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 701. 二叉搜索树中的插入操作 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 删除二叉搜索树中的节点 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - TreeNode output1 = s.deleteNode(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), 3); - Assertions.assertEquals(TreeNode.buildTree(5, 4, 6, 2, null, null, 7), output1); - - TreeNode output2 = s.deleteNode(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), 0); - Assertions.assertEquals(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), output2); - - TreeNode output3 = s.deleteNode(TreeNode.buildTree(5, 3, 6, 2, 4, null, 7), 5); - Assertions.assertEquals(TreeNode.buildTree(6, 3, 7, 2, 4), output3); - - Assertions.assertEquals(TreeNode.buildTree(1), s.deleteNode(TreeNode.buildTree(2, 1), 2)); - - Assertions.assertNull(s.deleteNode(TreeNode.buildTree(), 0)); - Assertions.assertNull(s.deleteNode(TreeNode.buildTree(0), 0)); - } - - static class Solution { - - public TreeNode deleteNode(TreeNode root, int key) { - if (root == null) { return null; } - if (root.val == key) { - if (root.left == null) { return root.right; } - if (root.right == null) { return root.left; } - // 获得右子树最小的节点 - TreeNode minRightNode = getMin(root.right); - // 删除右子树最小的节点 - root.right = deleteNode(root.right, minRightNode.val); - // 用右子树最小的节点替换 root 节点 - minRightNode.left = root.left; - minRightNode.right = root.right; - root = minRightNode; - } else if (root.val > key) { - // 去左子树找 - root.left = deleteNode(root.left, key); - } else if (root.val < key) { - // 去右子树找 - root.right = deleteNode(root.right, key); - } - return root; - } - - public TreeNode getMin(TreeNode root) { - if (root == null) { return null; } - if (root.left != null) { return getMin(root.left); } - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" deleted file mode 100644 index 2ba0983..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\346\215\242\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 108. 将有序数组转换为二叉搜索树 - * - * @author Zhang Peng - * @since 2020-07-07 - */ -public class 将有序数组转换为二叉搜索树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(TreeNode.buildTree(0, -3, 9, -10, null, 5), - s.sortedArrayToBST(new int[] { -10, -3, 0, 5, 9 })); - Assertions.assertEquals(TreeNode.buildTree(3, 1), s.sortedArrayToBST(new int[] { 1, 3 })); - } - - static class Solution { - - public TreeNode sortedArrayToBST(int[] nums) { - return sortedArrayToBST(nums, 0, nums.length - 1); - } - - // 将闭区间 [left, right] 中的元素转化成 BST,返回根节点 - TreeNode sortedArrayToBST(int[] nums, int left, int right) { - if (left > right) { - // 区间为空 - return null; - } - // 构造根节点 - // BST 节点左小右大,中间的元素就是根节点 - int mid = (left + right) / 2; - TreeNode root = new TreeNode(nums[mid]); - // 递归构建左子树 - root.left = sortedArrayToBST(nums, left, mid - 1); - // 递归构造右子树 - root.right = sortedArrayToBST(nums, mid + 1, right); - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\346\212\212\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\275\254\346\215\242\344\270\272\347\264\257\345\212\240\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\346\212\212\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\275\254\346\215\242\344\270\272\347\264\257\345\212\240\346\240\221.java" deleted file mode 100644 index 2b0c161..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\346\212\212\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\350\275\254\346\215\242\344\270\272\347\264\257\345\212\240\346\240\221.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 538. 把二叉搜索树转换为累加树 - * - * @author Zhang Peng - * @date 2025-10-22 - */ -public class 把二叉搜索树转换为累加树 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - TreeNode input1 = TreeNode.buildTree(4, 1, 6, 0, 2, 5, 7, null, null, null, 3, null, null, null, 8); - TreeNode output1 = s.convertBST(input1); - Assertions.assertArrayEquals( - new Integer[] { 30, 36, 21, 36, 35, 26, 15, null, null, null, 33, null, null, null, 8 }, - TreeNode.toValueList(output1).toArray()); - - TreeNode input2 = TreeNode.buildTree(0, null, 1); - TreeNode output2 = s.convertBST(input2); - Assertions.assertArrayEquals(new Integer[] { 1, null, 1 }, TreeNode.toValueList(output2).toArray()); - - TreeNode input3 = TreeNode.buildTree(1, 0, 2); - TreeNode output3 = s.convertBST(input3); - Assertions.assertArrayEquals(new Integer[] { 3, 3, 2 }, TreeNode.toValueList(output3).toArray()); - - TreeNode input4 = TreeNode.buildTree(3, 2, 4, 1); - TreeNode output4 = s.convertBST(input4); - Assertions.assertArrayEquals(new Integer[] { 7, 9, 4, 10 }, TreeNode.toValueList(output4).toArray()); - } - - static class Solution { - - int sum = 0; - - public TreeNode convertBST(TreeNode root) { - sum = 0; // 重置 - traverse(root); - return root; - } - - public void traverse(TreeNode root) { - if (root == null) return; - traverse(root.right); - sum += root.val; - root.val = sum; - // System.out.printf("val: %d\n", root.val); - traverse(root.left); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" deleted file mode 100644 index 1177d66..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/\351\252\214\350\257\201\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.java" +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dunwu.algorithm.tree.bstree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 98. 验证二叉搜索树 - * - * @author Zhang Peng - * @since 2020-07-02 - */ -public class 验证二叉搜索树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isValidBST(TreeNode.buildTree(2, 1, 3))); - Assertions.assertFalse(s.isValidBST(TreeNode.buildTree(5, 1, 4, null, null, 3, 6))); - Assertions.assertFalse(s.isValidBST(TreeNode.buildTree(2, 2, 2))); - Assertions.assertFalse(s.isValidBST(TreeNode.buildTree(5, 4, 6, null, null, 3, 7))); - Assertions.assertTrue(s.isValidBST(TreeNode.buildTree(3, 1, 5, 0, 2, 4, 6))); - } - - static class Solution { - - public boolean isValidBST(TreeNode root) { - return isValidBST(root, null, null); - } - - // 限定以 root 为根的子树节点必须满足 max.val > root.val > min.val - boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) { - // base case - if (root == null) return true; - // 若 root.val 不符合 max 和 min 的限制,说明不是合法 BST - if (min != null && root.val <= min.val) return false; - if (max != null && root.val >= max.val) return false; - // 限定左子树的最大值是 root.val,右子树的最小值是 root.val - return isValidBST(root.left, min, root) - && isValidBST(root.right, root, max); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\344\270\255\346\211\200\346\234\211\350\267\235\347\246\273\344\270\272K\347\232\204\347\273\223\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\344\270\255\346\211\200\346\234\211\350\267\235\347\246\273\344\270\272K\347\232\204\347\273\223\347\202\271.java" deleted file mode 100644 index c9c6a89..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\344\270\255\346\211\200\346\234\211\350\267\235\347\246\273\344\270\272K\347\232\204\347\273\223\347\202\271.java" +++ /dev/null @@ -1,87 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - -/** - * 863. 二叉树中所有距离为 K 的结点 - * - * @author Zhang Peng - * @date 2025-12-01 - */ -public class 二叉树中所有距离为K的结点 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode input = TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7); - TreeNode target = TreeNode.find(input, 5); - Assertions.assertArrayEquals(new Integer[] { 7, 4, 1 }, s.distanceK(input, target, 2).toArray()); - } - - static class Solution { - - // 记录父节点:node.val -> parentNode - // 题目说了树中所有节点值都是唯一的,所以可以用 node.val 代表 TreeNode - HashMap parent = new HashMap<>(); - - public List distanceK(TreeNode root, TreeNode target, int k) { - // 遍历所有节点,记录每个节点的父节点 - traverse(root, null); - - // 开始从 target 节点施放 BFS 算法,找到距离为 k 的节点 - LinkedList q = new LinkedList<>(); - HashSet visited = new HashSet<>(); - q.offer(target); - visited.add(target.val); - // 记录离 target 的距离 - int dist = 0; - List res = new LinkedList<>(); - - while (!q.isEmpty()) { - int sz = q.size(); - for (int i = 0; i < sz; i++) { - TreeNode cur = q.poll(); - if (dist == k) { - // 找到距离起点 target 距离为 k 的节点 - res.add(cur.val); - } - // 向父节点、左右子节点扩散 - TreeNode parentNode = parent.get(cur.val); - if (parentNode != null && !visited.contains(parentNode.val)) { - visited.add(parentNode.val); - q.offer(parentNode); - } - if (cur.left != null && !visited.contains(cur.left.val)) { - visited.add(cur.left.val); - q.offer(cur.left); - } - if (cur.right != null && !visited.contains(cur.right.val)) { - visited.add(cur.right.val); - q.offer(cur.right); - } - } - // 向外扩展一圈 - dist++; - } - - return res; - } - - private void traverse(TreeNode root, TreeNode parentNode) { - if (root == null) { - return; - } - parent.put(root.val, parentNode); - // 二叉树递归框架 - traverse(root.left, root); - traverse(root.right, root); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" deleted file mode 100644 index d27f609..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\256\214\345\205\250\346\200\247\346\243\200\351\252\214.java" +++ /dev/null @@ -1,71 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 958. 二叉树的完全性检验 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 二叉树的完全性检验 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isCompleteTree(TreeNode.buildTree(1, 2, 3, 4, 5, 6))); - Assertions.assertTrue(s.isCompleteTree( - TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33))); - Assertions.assertFalse(s.isCompleteTree(TreeNode.buildTree(1, 2, 3, 4, 5, null, 7))); - Assertions.assertFalse(s.isCompleteTree(TreeNode.buildTree(1, 2, 3, 5, null, 7, 8))); - Assertions.assertFalse(s.isCompleteTree(TreeNode.buildTree(1, null, 7))); - } - - static class Solution { - - static class NodeInfo { - - public int id; - public TreeNode node; - - public NodeInfo(int id, TreeNode node) { - this.id = id; - this.node = node; - } - - } - - public boolean isCompleteTree(TreeNode root) { - - if (root == null) { return false; } - - int expect = 1; - LinkedList queue = new LinkedList<>(); - queue.offer(new NodeInfo(1, root)); - while (!queue.isEmpty()) { - int size = queue.size(); - for (int i = 0; i < size; i++) { - NodeInfo info = queue.poll(); - if (expect != info.id) { return false; } - if (info.node.left == null && info.node.right != null) { - return false; - } - if (info.node.left != null) { - queue.offer(new NodeInfo(info.id * 2, info.node.left)); - } - if (info.node.right != null) { - queue.offer(new NodeInfo(info.id * 2 + 1, info.node.right)); - } - expect++; - } - } - - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" deleted file mode 100644 index 71b0a95..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\271\263\345\235\207\345\200\274.java" +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 637. 二叉树的层平均值 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 二叉树的层平均值 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new Double[] { 3.00000, 14.50000, 11.00000 }, - s.averageOfLevels(TreeNode.buildTree(3, 9, 20, null, null, 15, 7)).toArray()); - Assertions.assertArrayEquals(new Double[] { 3.00000, 14.50000, 11.00000 }, - s.averageOfLevels(TreeNode.buildTree(3, 9, 20, 15, 7)).toArray()); - } - - static class Solution { - - public List averageOfLevels(TreeNode root) { - if (root == null) { return new LinkedList<>(); } - - LinkedList res = new LinkedList<>(); - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - double sum = 0.0; - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - sum += node.val; - if (node.left != null) queue.offer(node.left); - if (node.right != null) queue.offer(node.right); - } - res.add(sum / size); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" deleted file mode 100644 index dd133f3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206.java" +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; - -/** - * 二叉树的层次遍历 - * - * @author Zhang Peng - * @since 2020-06-18 - */ -public class 二叉树的层次遍历 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); - List> expectList = new LinkedList<>(); - expectList.add(Arrays.asList(3)); - expectList.add(Arrays.asList(9, 20)); - expectList.add(Arrays.asList(15, 7)); - Assertions.assertArrayEquals(expectList.toArray(), s.levelOrder(root).toArray()); - - Solution s2 = new Solution(); - TreeNode root2 = TreeNode.buildTree(1); - List> expectList2 = new LinkedList<>(); - expectList2.add(Arrays.asList(1)); - Assertions.assertArrayEquals(expectList2.toArray(), s2.levelOrder(root2).toArray()); - - Solution s3 = new Solution(); - TreeNode root3 = TreeNode.buildTree(); - Assertions.assertArrayEquals(new LinkedList<>().toArray(), s3.levelOrder(root3).toArray()); - } - - static class Solution { - - public List> levelOrder(TreeNode root) { - - LinkedList> res = new LinkedList<>(); - if (root == null) { return res; } - - Queue queue = new LinkedList<>(); - queue.offer(root); - // while 循环控制从上向下一层层遍历 - while (!queue.isEmpty()) { - int size = queue.size(); - // 记录这一层的节点值 - List level = new LinkedList<>(); - // for 循环控制每一层从左向右遍历 - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - level.add(node.val); - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - } - res.add(level); - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" deleted file mode 100644 index dae1cfc..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\2062.java" +++ /dev/null @@ -1,73 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * 二叉树的层次遍历 II - * - * @author Zhang Peng - * @since 2020-06-18 - */ -public class 二叉树的层次遍历2 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); - List> expectList = new LinkedList<>(); - expectList.add(Arrays.asList(15, 7)); - expectList.add(Arrays.asList(9, 20)); - expectList.add(Arrays.asList(3)); - Assertions.assertArrayEquals(expectList.toArray(), s.levelOrderBottom(root).toArray()); - - Solution s2 = new Solution(); - TreeNode root2 = TreeNode.buildTree(1); - List> expectList2 = new LinkedList<>(); - expectList2.add(Arrays.asList(1)); - Assertions.assertArrayEquals(expectList2.toArray(), s2.levelOrderBottom(root2).toArray()); - - Solution s3 = new Solution(); - TreeNode root3 = TreeNode.buildTree(); - Assertions.assertArrayEquals(new LinkedList<>().toArray(), s3.levelOrderBottom(root3).toArray()); - } - - static class Solution { - - public List> levelOrderBottom(TreeNode root) { - - if (root == null) { - return new ArrayList(); - } - - LinkedList queue = new LinkedList<>(); - List> result = new LinkedList<>(); - queue.add(root); - - while (!queue.isEmpty()) { - int size = queue.size(); - List currentLevel = new LinkedList<>(); - result.add(currentLevel); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - currentLevel.add(node.val); - if (node.left != null) { - queue.offer(node.left); - } - if (node.right != null) { - queue.offer(node.right); - } - } - } - Collections.reverse(result); - return result; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" deleted file mode 100644 index df94b8e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\345\256\275\345\272\246.java" +++ /dev/null @@ -1,77 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 104. 二叉树的最大深度 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 二叉树的最大宽度 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(4, s.widthOfBinaryTree(TreeNode.buildTree(1, 3, 2, 5, 3, null, 9))); - Assertions.assertEquals(7, s.widthOfBinaryTree(TreeNode.buildTree(1, 3, 2, 5, null, null, 9, 6, null, 7))); - } - - static class Solution { - - public static class NodeInfo { - - public int id; - public TreeNode node; - - public NodeInfo(int id, TreeNode node) { - this.id = id; - this.node = node; - } - - @Override - public String toString() { - return "NodeInfo{" + - "id=" + id + - ", node=" + node.val + - '}'; - } - - } - - public int widthOfBinaryTree(TreeNode root) { - - if (root == null) return 0; - - int level = 0; - int maxWidth = 0; - LinkedList queue = new LinkedList<>(); - queue.offer(new NodeInfo(1, root)); - while (!queue.isEmpty()) { - level++; - int size = queue.size(); - NodeInfo left = null, right = null; - for (int i = 0; i < size; i++) { - NodeInfo info = queue.poll(); - if (info == null) { continue; } - if (left == null) { left = info; } - right = info; - if (info.node.left != null) { - queue.offer(new NodeInfo(2 * info.id, info.node.left)); - } - if (info.node.right != null) { - queue.offer(new NodeInfo(2 * info.id + 1, info.node.right)); - } - } - // System.out.printf("level: %d, left: %s, right: %s\n", level, left.toString(), right.toString()); - int width = right.id - left.id + 1; - maxWidth = Math.max(maxWidth, width); - } - return maxWidth; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index 0d458c6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 103. 二叉树的锯齿形层序遍历 - * - * @author Zhang Peng - * @date 2025-10-21 - */ -public class 二叉树的锯齿形层序遍历 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); - List> expectList = new LinkedList<>(); - expectList.add(Arrays.asList(3)); - expectList.add(Arrays.asList(20, 9)); - expectList.add(Arrays.asList(15, 7)); - Assertions.assertArrayEquals(expectList.toArray(), s.zigzagLevelOrder(root).toArray()); - - TreeNode root2 = TreeNode.buildTree(1, 2, 3, 4, null, null, 5); - List> expectList2 = new LinkedList<>(); - expectList2.add(Arrays.asList(1)); - expectList2.add(Arrays.asList(3, 2)); - expectList2.add(Arrays.asList(4, 5)); - Assertions.assertArrayEquals(expectList2.toArray(), s.zigzagLevelOrder(root2).toArray()); - } - - static class Solution { - - public List> zigzagLevelOrder(TreeNode root) { - List> result = new LinkedList<>(); - if (root == null) return result; - - boolean reverse = false; - LinkedList queue = new LinkedList<>(); - queue.addLast(root); - while (!queue.isEmpty()) { - int size = queue.size(); - LinkedList layer = new LinkedList<>(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.removeFirst(); - if (reverse) { - layer.addFirst(node.val); - } else { - layer.addLast(node.val); - } - if (node.left != null) queue.addLast(node.left); - if (node.right != null) queue.addLast(node.right); - } - reverse = !reverse; - result.add(layer); - } - return result; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" deleted file mode 100644 index c9bdb3c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\234\250\346\257\217\344\270\252\346\240\221\350\241\214\344\270\255\346\211\276\346\234\200\345\244\247\345\200\274.java" +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 515. 在每个树行中找最大值 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 在每个树行中找最大值 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 9 }, - s.largestValues(TreeNode.buildTree(1, 3, 2, 5, 3, null, 9)).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1, 3 }, - s.largestValues(TreeNode.buildTree(1, 2, 3)).toArray()); - } - - static class Solution { - - public List largestValues(TreeNode root) { - - if (root == null) { return new LinkedList<>(); } - - LinkedList res = new LinkedList<>(); - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - int max = Integer.MIN_VALUE; - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - max = Math.max(max, node.val); - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - } - res.add(max); - } - - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" deleted file mode 100644 index 061e188..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\210.java" +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import cn.hutool.json.JSONUtil; -import io.github.dunwu.algorithm.tree.TreeNode; - -import java.util.LinkedList; - -/** - * 116. 填充每个节点的下一个右侧节点指针 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 填充每个节点的下一个右侧节点指针 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode treeNode = TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7); - Node root = JSONUtil.toBean(JSONUtil.toJsonStr(treeNode), Node.class); - s.connect(root); - System.out.println(root); - } - - static class Solution { - - public Node connect(Node root) { - if (root == null) return root; - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - Node prev = queue.poll(); - if (prev.left != null) queue.offer(prev.left); - if (prev.right != null) queue.offer(prev.right); - for (int i = 1; i < size; i++) { - Node next = queue.poll(); - prev.next = next; - prev = next; - if (next.left != null) queue.offer(next.left); - if (next.right != null) queue.offer(next.right); - } - } - return root; - } - - } - - static class Node extends TreeNode { - - public Node next; - public Node left; - public Node right; - - public Node(int val) { - super(val); - } - - public Node(int val, TreeNode left, TreeNode right) { - super(val, left, right); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" deleted file mode 100644 index 187eae0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\241\253\345\205\205\346\257\217\344\270\252\350\212\202\347\202\271\347\232\204\344\270\213\344\270\200\344\270\252\345\217\263\344\276\247\350\212\202\347\202\271\346\214\207\351\222\2102.java" +++ /dev/null @@ -1,68 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import cn.hutool.json.JSONUtil; -import io.github.dunwu.algorithm.tree.TreeNode; - -import java.util.LinkedList; - -/** - * 117. 填充每个节点的下一个右侧节点指针 II - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 填充每个节点的下一个右侧节点指针2 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode treeNode = TreeNode.buildTree(1, 2, 3, 4, 5, null, 7); - Node root = JSONUtil.toBean(JSONUtil.toJsonStr(treeNode), Node.class); - s.connect(root); - System.out.println(root); - } - - static class Solution { - - public Node connect(Node root) { - if (root == null) return null; - traverse(root); - return root; - } - - public void traverse(Node root) { - if (root == null) return; - LinkedList q = new LinkedList<>(); - q.offer(root); - - while (!q.isEmpty()) { - int size = q.size(); - Node prev = null; - for (int i = 0; i < size; i++) { - Node cur = q.poll(); - if (prev != null) { prev.next = cur; } - if (cur.left != null) q.offer(cur.left); - if (cur.right != null) q.offer(cur.right); - prev = cur; - } - } - } - - } - - static class Node extends TreeNode { - - public Node next; - public Node left; - public Node right; - - public Node(int val) { - super(val); - } - - public Node(int val, TreeNode left, TreeNode right) { - super(val, left, right); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\245\207\345\201\266\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\245\207\345\201\266\346\240\221.java" deleted file mode 100644 index 8d58a76..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\245\207\345\201\266\346\240\221.java" +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 1609. 奇偶树 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 奇偶树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isEvenOddTree(TreeNode.buildTree(1, 10, 4, 3, null, 7, 9, 12, 8, 6, null, null, 2))); - Assertions.assertFalse(s.isEvenOddTree(TreeNode.buildTree(5, 4, 2, 3, 3, 7))); - Assertions.assertFalse(s.isEvenOddTree(TreeNode.buildTree(5, 9, 1, 3, 5, 7))); - Assertions.assertTrue(s.isEvenOddTree(TreeNode.buildTree(1))); - Assertions.assertTrue( - s.isEvenOddTree(TreeNode.buildTree(11, 8, 6, 1, 3, 9, 11, 30, 20, 18, 16, 12, 10, 4, 2, 17))); - } - - static class Solution { - - public boolean isEvenOddTree(TreeNode root) { - if (root == null) return false; - int level = 0; - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int size = queue.size(); - boolean odd = level % 2 != 0; - Integer lastVal = null; - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - if (odd) { // 奇数层 - // 奇数下标 层上的所有节点的值都是 偶 整数,从左到右按顺序 严格递减 - if (node.val % 2 != 0) { return false; } - if (lastVal != null && node.val >= lastVal) { return false; } - } else { // 偶数层 - // 偶数下标 层上的所有节点的值都是 奇 整数,从左到右按顺序 严格递增 - if (node.val % 2 == 0) { return false; } - if (lastVal != null && node.val <= lastVal) { return false; } - } - lastVal = node.val; - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - } - level++; - } - return true; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" deleted file mode 100644 index 740f4ea..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\346\217\222\345\205\245\345\231\250.java" +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 919. 完全二叉树插入器 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 完全二叉树插入器 { - - public static void main(String[] args) { - CBTInserter c = new CBTInserter(TreeNode.buildTree(1, 2)); - Assertions.assertEquals(1, c.insert(3)); - Assertions.assertEquals(2, c.insert(4)); - Assertions.assertEquals(TreeNode.buildTree(1, 2, 3, 4), c.get_root()); - } - - static class CBTInserter { - - private TreeNode root; - private final LinkedList unfull; - - public CBTInserter(TreeNode root) { - this.root = root; - this.unfull = new LinkedList<>(); - - LinkedList q = new LinkedList<>(); - q.offer(this.root); - while (!q.isEmpty()) { - for (int i = 0; i < q.size(); i++) { - TreeNode node = q.poll(); - if (node.left != null) { - q.offer(node.left); - } - if (node.right != null) { - q.offer(node.right); - } - if (node.left == null || node.right == null) { - unfull.offer(node); - } - } - } - } - - public int insert(int val) { - if (root == null) { - root = new TreeNode(val); - return 0; - } - - TreeNode parent = unfull.peek(); - TreeNode node = new TreeNode(val); - if (parent.left == null) { - parent.left = node; - } else if (parent.right == null) { - parent.right = node; - unfull.poll(); - } - unfull.offer(node); - return parent.val; - } - - public TreeNode get_root() { - return this.root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" deleted file mode 100644 index 0992a9a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\261\202\346\225\260\346\234\200\346\267\261\345\217\266\345\255\220\350\212\202\347\202\271\347\232\204\345\222\214.java" +++ /dev/null @@ -1,48 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 1302. 层数最深叶子节点的和 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 层数最深叶子节点的和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(15, - s.deepestLeavesSum(TreeNode.buildTree(1, 2, 3, 4, 5, null, 6, 7, null, null, null, null, 8))); - Assertions.assertEquals(19, - s.deepestLeavesSum(TreeNode.buildTree(6, 7, 8, 2, 7, 1, 3, 9, null, 1, 4, null, null, null, 5))); - } - - static class Solution { - - public int deepestLeavesSum(TreeNode root) { - - if (root == null) { return 0; } - - int sum = 0; - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - sum = 0; - int size = queue.size(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - sum += node.val; - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - } - } - return sum; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" deleted file mode 100644 index 37abde6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\225.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.LinkedList; - -/** - * LCR 149. 彩灯装饰记录 I - * - * @author Zhang Peng - * @since 2025-10-28 - */ -public class 彩灯装饰记录 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode root = TreeNode.buildTree(8, 17, 21, 18, null, null, 6); - Assertions.assertArrayEquals(new int[] { 8, 17, 21, 18, 6 }, s.decorateRecord(root)); - } - - static class Solution { - - public int[] decorateRecord(TreeNode root) { - ArrayList list = new ArrayList<>(); - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - TreeNode node = queue.poll(); - if (node == null) { continue; } - list.add(node.val); - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - } - return list.stream().mapToInt(Integer::intValue).toArray(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2252.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2252.java" deleted file mode 100644 index 26ba27f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2252.java" +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * LCR 150. 彩灯装饰记录 II - * - * @author Zhang Peng - * @since 2025-10-28 - */ -public class 彩灯装饰记录2 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode root = TreeNode.buildTree(8, 17, 21, 18, null, null, 6); - List> expectList = new ArrayList<>(); - expectList.add(Arrays.asList(8)); - expectList.add(Arrays.asList(17, 21)); - expectList.add(Arrays.asList(18, 6)); - List> output = s.decorateRecord(root); - for (int i = 0; i < expectList.size(); i++) { - Assertions.assertArrayEquals(expectList.get(i).toArray(), output.get(i).toArray()); - } - } - - static class Solution { - - public List> decorateRecord(TreeNode root) { - List> res = new ArrayList<>(); - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - List list = new ArrayList<>(); - int size = queue.size(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - if (node == null) { continue; } - list.add(node.val); - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - } - if (list.size() != 0) { - res.add(list); - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2253.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2253.java" deleted file mode 100644 index 7985e9f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\345\275\251\347\201\257\350\243\205\351\245\260\350\256\260\345\275\2253.java" +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * LCR 151. 彩灯装饰记录 III - * - * @author Zhang Peng - * @since 2025-10-28 - */ -public class 彩灯装饰记录3 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode root = TreeNode.buildTree(8, 17, 21, 18, null, null, 6); - List> expectList = new ArrayList<>(); - expectList.add(Arrays.asList(8)); - expectList.add(Arrays.asList(21, 17)); - expectList.add(Arrays.asList(18, 6)); - List> output = s.decorateRecord(root); - for (int i = 0; i < expectList.size(); i++) { - Assertions.assertArrayEquals(expectList.get(i).toArray(), output.get(i).toArray()); - } - } - - static class Solution { - - public List> decorateRecord(TreeNode root) { - List> res = new LinkedList<>(); - LinkedList queue = new LinkedList<>(); - queue.offer(root); - boolean reverse = false; - while (!queue.isEmpty()) { - LinkedList list = new LinkedList<>(); - int size = queue.size(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - if (node == null) { continue; } - if (reverse) { - list.addFirst(node.val); - } else { - list.addLast(node.val); - } - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - } - if (list.size() != 0) { - res.add(list); - } - reverse = !reverse; - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" deleted file mode 100644 index d0bd78b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/bfs/\346\234\200\345\244\247\345\261\202\345\206\205\345\205\203\347\264\240\345\222\214.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.bfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 1161. 最大层内元素和 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 最大层内元素和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, - s.maxLevelSum(TreeNode.buildTree(1, 7, 0, 7, -8, null, null))); - Assertions.assertEquals(2, - s.maxLevelSum(TreeNode.buildTree(989, null, 10250, 98693, -89388, null, null, null, -32127))); - Assertions.assertEquals(3, - s.maxLevelSum(TreeNode.buildTree(-100, -200, -300, -20, -5, -10, null))); - } - - static class Solution { - - public int maxLevelSum(TreeNode root) { - if (root == null) { return 0; } - int depth = 1; - int max = Integer.MIN_VALUE; - int maxDepth = 1; - LinkedList queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - int sum = 0; - int size = queue.size(); - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - sum += node.val; - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - } - if (sum > max) { - max = sum; - maxDepth = depth; - } - depth++; - } - return maxDepth; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" deleted file mode 100644 index ca687c2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\345\211\252\346\236\235.java" +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.dfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 814. 二叉树剪枝 - * - * @author Zhang Peng - * @since 2025-10-30 - */ -public class 二叉树剪枝 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(TreeNode.buildTree(1, null, 0, null, 1), - s.pruneTree(TreeNode.buildTree(1, null, 0, 0, 1))); - Assertions.assertEquals(TreeNode.buildTree(1, null, 1, null, 1), - s.pruneTree(TreeNode.buildTree(1, 0, 1, 0, 0, 0, 1))); - Assertions.assertEquals(TreeNode.buildTree(1, 1, 0, 1, 1, null, 1), - s.pruneTree(TreeNode.buildTree(1, 1, 0, 1, 1, 0, 1, 0))); - } - - static class Solution { - - public TreeNode pruneTree(TreeNode root) { - if (root == null) { return null; } - - root.left = pruneTree(root.left); - root.right = pruneTree(root.right); - - if (root.left == null && root.right == null && root.val == 0) { - return null; - } - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index 0572005..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,53 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.dfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 94. 二叉树的中序遍历 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 二叉树的中序遍历 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 2 }, - s.inorderTraversal(TreeNode.buildTree(1, null, 2, 3)).toArray()); - Assertions.assertArrayEquals(new Integer[] {}, - s.inorderTraversal(TreeNode.buildTree()).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1 }, - s.inorderTraversal(TreeNode.buildTree(1)).toArray()); - } - - private static class Solution { - - List values; - - public List inorderTraversal(TreeNode root) { - values = new ArrayList<>(); - traverse(root); - return values; - } - - public void traverse(TreeNode root) { - if (root == null) return; - // 【前序】 - // System.out.printf("[node -> left]从节点 %s 进入节点 %s\n", root, root.left); - traverse(root.left); - // 【中序】 - // System.out.printf("\t[left -> node]从节点 %s 回到节点 %s\n", root.left, root); - // System.out.printf("\t[node -> right]从节点 %s 进入节点 %s\n", root, root.right); - values.add(root.val); - traverse(root.right); - // 【后序】 - // System.out.printf("\t[right -> node]从节点 %s 回到节点 %s\n", root.right, root); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index ba15417..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.dfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 144. 二叉树的前序遍历 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 二叉树的前序遍历 { - - public static void main(String[] args) { - - Solution s1 = new Solution(); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, - s1.preorderTraversal(TreeNode.buildTree(1, null, 2, 3)).toArray()); - Assertions.assertArrayEquals(new Integer[] {}, - s1.preorderTraversal(TreeNode.buildTree()).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1 }, - s1.preorderTraversal(TreeNode.buildTree(1)).toArray(new Integer[0])); - - Solution2 s2 = new Solution2(); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, - s2.preorderTraversal(TreeNode.buildTree(1, null, 2, 3)).toArray()); - Assertions.assertArrayEquals(new Integer[] {}, - s2.preorderTraversal(TreeNode.buildTree()).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1 }, - s2.preorderTraversal(TreeNode.buildTree(1)).toArray(new Integer[0])); - } - - /** - * 【分解】思路解法 - */ - private static class Solution { - - public List preorderTraversal(TreeNode root) { - List res = new ArrayList<>(); - if (root == null) { - return res; - } - // 前序遍历的结果,root.val 在第一个 - res.add(root.val); - // 利用函数定义,后面接着左子树的前序遍历结果 - res.addAll(preorderTraversal(root.left)); - // 利用函数定义,最后接着右子树的前序遍历结果 - res.addAll(preorderTraversal(root.right)); - return res; - } - - } - - /** - * 【遍历】思路解法 - */ - private static class Solution2 { - - List res; - - public List preorderTraversal(TreeNode root) { - res = new ArrayList<>(); - traverse(root); - return res; - } - - public void traverse(TreeNode root) { - if (root == null) { return; } - res.add(root.val); - traverse(root.left); - traverse(root.right); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index cdbcba2..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.dfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 145. 二叉树的后序遍历 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 二叉树的后序遍历 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new Integer[] { 3, 2, 1 }, - s.postorderTraversal(TreeNode.buildTree(1, null, 2, 3)).toArray()); - Assertions.assertArrayEquals(new Integer[] {}, - s.postorderTraversal(TreeNode.buildTree()).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1 }, - s.postorderTraversal(TreeNode.buildTree(1)).toArray()); - Assertions.assertArrayEquals(new Integer[] { 4, 6, 7, 5, 2, 9, 8, 3, 1 }, - s.postorderTraversal(TreeNode.buildTree(1, 2, 3, 4, 5, null, 8, null, null, 6, 7, 9)).toArray()); - } - - private static class Solution { - - List values = null; - - public List postorderTraversal(TreeNode root) { - values = new ArrayList<>(); - traverse(root); - return values; - } - - public void traverse(TreeNode root) { - if (root == null) return; - // 【前序】 - System.out.printf("[node -> left]从节点 %s 进入节点 %s\n", root, root.left); - traverse(root.left); - // 【中序】 - System.out.printf("\t[left -> node]从节点 %s 回到节点 %s\n", root.left, root); - System.out.printf("\t[node -> right]从节点 %s 进入节点 %s\n", root, root.right); - traverse(root.right); - // 【后序】 - System.out.printf("\t[right -> node]从节点 %s 回到节点 %s\n", root.right, root); - values.add(root.val); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\235\241\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\235\241\345\272\246.java" deleted file mode 100644 index 2d5500b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\344\272\214\345\217\211\346\240\221\347\232\204\345\235\241\345\272\246.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.dfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 110. 平衡二叉树 - * - * @author Zhang Peng - * @since 2025-10-30 - */ -public class 二叉树的坡度 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(1, s.findTilt(TreeNode.buildTree(1, 2, 3))); - Assertions.assertEquals(15, s.findTilt(TreeNode.buildTree(4, 2, 9, 3, 5, null, 7))); - Assertions.assertEquals(9, s.findTilt(TreeNode.buildTree(21, 7, 14, 1, 1, 2, 2, 3, 3))); - } - - static class Solution { - - int res = 0; - - public int findTilt(TreeNode root) { - res = 0; - sum(root); - return res; - } - - public int sum(TreeNode root) { - if (root == null) { return 0; } - int left = sum(root.left); - int right = sum(root.right); - res += Math.abs(left - right); - return left + right + root.val; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" deleted file mode 100644 index 550c275..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\207\272\347\216\260\346\254\241\346\225\260\346\234\200\345\244\232\347\232\204\345\255\220\346\240\221\345\205\203\347\264\240\345\222\214.java" +++ /dev/null @@ -1,65 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.dfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 508. 出现次数最多的子树元素和 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 出现次数最多的子树元素和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertArrayEquals(new int[] { 2, -3, 4 }, s.findFrequentTreeSum(TreeNode.buildTree(5, 2, -3))); - Assertions.assertArrayEquals(new int[] { 2 }, s.findFrequentTreeSum(TreeNode.buildTree(5, 2, -5))); - } - - static class Solution { - - private Map map; - - public int[] findFrequentTreeSum(TreeNode root) { - map = new HashMap<>(); - sum(root); - - int max = Integer.MIN_VALUE; - List list = new ArrayList<>(); - for (Map.Entry entry : map.entrySet()) { - Integer k = entry.getKey(); - Integer v = entry.getValue(); - if (v > max) { - max = v; - list.clear(); - list.add(k); - } else if (v == max) { - list.add(k); - } - } - - int[] res = new int[list.size()]; - for (int i = 0; i < list.size(); i++) { - res[i] = list.get(i); - } - return res; - } - - public int sum(TreeNode root) { - if (root == null) { return 0; } - int left = sum(root.left); - int right = sum(root.right); - int sum = left + right + root.val; - map.put(sum, map.getOrDefault(sum, 0) + 1); - return sum; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\210\240\351\231\244\347\273\231\345\256\232\345\200\274\347\232\204\345\217\266\345\255\220\350\212\202\347\202\271.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\210\240\351\231\244\347\273\231\345\256\232\345\200\274\347\232\204\345\217\266\345\255\220\350\212\202\347\202\271.java" deleted file mode 100644 index f273bae..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\210\240\351\231\244\347\273\231\345\256\232\345\200\274\347\232\204\345\217\266\345\255\220\350\212\202\347\202\271.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.dfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 814. 二叉树剪枝 - * - * @author Zhang Peng - * @since 2025-10-30 - */ -public class 删除给定值的叶子节点 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(TreeNode.buildTree(1, null, 3, null, 4), - s.removeLeafNodes(TreeNode.buildTree(1, 2, 3, 2, null, 2, 4), 2)); - Assertions.assertEquals(TreeNode.buildTree(1, 3, null, null, 2), - s.removeLeafNodes(TreeNode.buildTree(1, 3, 3, 3, 2), 3)); - Assertions.assertEquals(TreeNode.buildTree(1), - s.removeLeafNodes(TreeNode.buildTree(1, 2, null, 2, null, 2), 2)); - } - - static class Solution { - - public TreeNode removeLeafNodes(TreeNode root, int target) { - if (root == null) { return null; } - root.left = removeLeafNodes(root.left, target); - root.right = removeLeafNodes(root.right, target); - if (root.left == null && root.right == null && root.val == target) { - return null; - } - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" deleted file mode 100644 index e1463ce..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.dfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * LCR 149. 彩灯装饰记录 I - * - * @author Zhang Peng - * @since 2025-10-28 - */ -public class 叶子相似的树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.leafSimilar(TreeNode.buildTree(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4), - TreeNode.buildTree(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8))); - } - - static class Solution { - - public boolean leafSimilar(TreeNode root1, TreeNode root2) { - List root1Leafs = new ArrayList<>(); - List root2Leafs = new ArrayList<>(); - getLeafs(root1, root1Leafs); - getLeafs(root2, root2Leafs); - if (root1Leafs.size() != root2Leafs.size()) { - return false; - } - for (int i = 0; i < root1Leafs.size(); i++) { - if (!Objects.equals(root1Leafs.get(i), root2Leafs.get(i))) { - return false; - } - } - return true; - } - - public void getLeafs(TreeNode root, List leafs) { - if (root == null) { - return; - } - if (root.left == null && root.right == null) { - leafs.add(root.val); - } - getLeafs(root.left, leafs); - getLeafs(root.right, leafs); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index b67c5f4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/dfs/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.dfs; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 110. 平衡二叉树 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 平衡二叉树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isBalanced(TreeNode.buildTree(3, 9, 20, null, null, 15, 7))); - Assertions.assertFalse(s.isBalanced(TreeNode.buildTree(1, 2, 2, 3, 3, null, null, 4, 4))); - Assertions.assertTrue(s.isBalanced(TreeNode.buildTree())); - } - - static class Solution { - - boolean isOk = true; - - public boolean isBalanced(TreeNode root) { - isOk = true; - maxDepth(root); - return isOk; - } - - public int maxDepth(TreeNode root) { - if (root == null) { return 0; } - if (root.left == null && root.right == null) { return 1; } - int leftDepth = maxDepth(root.left); - int rightDepth = maxDepth(root.right); - if (Math.abs(leftDepth - rightDepth) > 1) { - isOk = false; - } - return Math.max(leftDepth, rightDepth) + 1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" deleted file mode 100644 index 820c810..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\346\234\200\345\244\247\350\267\257\345\276\204\345\222\214.java" +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 124. 二叉树中的最大路径和 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 二叉树中的最大路径和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(6, s.maxPathSum(TreeNode.buildTree(1, 2, 3))); - Assertions.assertEquals(42, s.maxPathSum(TreeNode.buildTree(-10, 9, 20, null, null, 15, 7))); - } - - static class Solution { - - int res = Integer.MIN_VALUE; - - public int maxPathSum(TreeNode root) { - if (root == null) { return 0; } - oneSideMax(root); - return res; - } - - int oneSideMax(TreeNode root) { - if (root == null) { return 0; } - int left = Math.max(oneSideMax(root.left), 0); - int right = Math.max(oneSideMax(root.right), 0); - int pathMaxSum = root.val + left + right; - res = Math.max(res, pathMaxSum); - return Math.max(left, right) + root.val; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index b0b70bf..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\344\270\255\345\272\217\344\270\216\345\220\216\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 106. - * 从中序与后序遍历序列构造二叉树 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 从中序与后序遍历序列构造二叉树 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - TreeNode output1 = s.buildTree(new int[] { 9, 3, 15, 20, 7 }, new int[] { 9, 15, 7, 20, 3 }); - Assertions.assertEquals(TreeNode.buildTree(3, 9, 20, null, null, 15, 7), output1); - - TreeNode output2 = s.buildTree(new int[] { -1 }, new int[] { -1 }); - Assertions.assertEquals(TreeNode.buildTree(-1), output2); - } - - static class Solution { - - Map map = null; - - public TreeNode buildTree(int[] inorder, int[] postorder) { - if (inorder == null || postorder == null) { return null; } - map = new HashMap<>(inorder.length); - for (int i = 0; i < inorder.length; i++) { - map.put(inorder[i], i); - } - return build(inorder, 0, inorder.length - 1, - postorder, 0, postorder.length - 1); - } - - public TreeNode build(int[] inorder, int inLow, int inHigh, - int[] postorder, int postLow, int postHigh) { - if (postLow > postHigh) { return null; } - int inMid = map.get(postorder[postHigh]); - int leftLen = inMid - inLow; - TreeNode root = new TreeNode(postorder[postHigh]); - root.left = build(inorder, inLow, inMid - 1, - postorder, postLow, postLow + leftLen - 1); - root.right = build(inorder, inMid + 1, inHigh, - postorder, postLow + leftLen, postHigh - 1); - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index af00d0e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,58 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 105. - * 从前序与中序遍历序列构造二叉树 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 从前序与中序遍历序列构造二叉树 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - TreeNode output1 = s.buildTree(new int[] { 3, 9, 20, 15, 7 }, new int[] { 9, 3, 15, 20, 7 }); - Assertions.assertEquals(TreeNode.buildTree(3, 9, 20, null, null, 15, 7), output1); - - TreeNode output2 = s.buildTree(new int[] { -1 }, new int[] { -1 }); - Assertions.assertEquals(TreeNode.buildTree(-1), output2); - } - - static class Solution { - - Map map = null; - - public TreeNode buildTree(int[] preorder, int[] inorder) { - if (inorder == null || preorder == null) { return null; } - map = new HashMap<>(inorder.length); - for (int i = 0; i < inorder.length; i++) { - map.put(inorder[i], i); - } - return build(preorder, 0, preorder.length - 1, - inorder, 0, inorder.length - 1); - } - - public TreeNode build(int[] preorder, int preLow, int preHigh, - int[] inorder, int inLow, int inHigh) { - if (preLow > preHigh) { return null; } - int inMid = map.get(preorder[preLow]); - int leftLen = inMid - inLow; - TreeNode root = new TreeNode(preorder[preLow]); - root.left = build(preorder, preLow + 1, preLow + leftLen, - inorder, inLow, inMid - 1); - root.right = build(preorder, preLow + leftLen + 1, preHigh, - inorder, inMid + 1, inHigh); - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" deleted file mode 100644 index c3a3959..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\210\240\347\202\271\346\210\220\346\236\227.java" +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * 1110. 删点成林 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 删点成林 { - - public static void main(String[] args) { - Solution s = new Solution(); - - List output = s.delNodes(TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7), new int[] { 3, 5 }); - List expect = new ArrayList<>(); - expect.add(TreeNode.buildTree(1, 2, null, 4)); - expect.add(TreeNode.buildTree(6)); - expect.add(TreeNode.buildTree(7)); - for (int i = 0; i < output.size(); i++) { - Assertions.assertEquals(expect.get(i), output.get(i)); - } - - List output2 = s.delNodes(TreeNode.buildTree(1, 2, 4, null, 3), new int[] { 3 }); - List expect2 = new ArrayList<>(); - expect2.add(TreeNode.buildTree(1, 2, 4)); - for (int i = 0; i < output2.size(); i++) { - Assertions.assertEquals(expect2.get(i), output2.get(i)); - } - } - - static class Solution { - - private List res; - - public List delNodes(TreeNode root, int[] to_delete) { - res = new ArrayList<>(); - Set set = new HashSet<>(); - for (int val : to_delete) { - set.add(val); - } - delNodes(root, set, false); - return res; - } - - public TreeNode delNodes(TreeNode root, Set set, boolean hasParent) { - if (root == null) { return null; } - boolean deleted = set.contains(root.val); - if (!deleted && !hasParent) { - res.add(root); - } - - root.left = delNodes(root.left, set, !deleted); - root.right = delNodes(root.right, set, !deleted); - return deleted ? null : root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index 0daa7f4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 101. 对称二叉树 - * - * @author Zhang Peng - * @date 2020-01-28 - */ -public class 对称二叉树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isSymmetric(TreeNode.buildTree(1, 2, 2, 3, 4, 4, 3))); - Assertions.assertFalse(s.isSymmetric(TreeNode.buildTree(1, 2, 2, null, 3, null, 3))); - } - - static class Solution { - - public boolean isSymmetric(TreeNode root) { - if (root == null) { return true; } - return isSymmetric(root.left, root.right); - } - - boolean isSymmetric(TreeNode left, TreeNode right) { - if (left == null && right == null) { return true; } - if (left == null || right == null) { return false; } - // 两个根节点需要相同 - if (left.val != right.val) { return false; } - // 左右子树也需要镜像对称 - return isSymmetric(left.left, right.right) && isSymmetric(left.right, right.left); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index e943be3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\211\200\346\234\211\345\217\257\350\203\275\347\232\204\347\234\237\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,77 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; - -import java.util.LinkedList; -import java.util.List; - -/** - * 894. 所有可能的真二叉树 - * - * @author Zhang Peng - * @date 2025-10-21 - */ -public class 所有可能的真二叉树 { - - public static void main(String[] args) { - Solution s = new Solution(); - List trees = s.allPossibleFBT(7); - trees.forEach(tree -> { - System.out.println(TreeNode.serialize(tree)); - }); - } - - static class Solution { - - // 备忘录,记录 n 个节点能够组合成的所有可能二叉树 - List[] memo; - - public List allPossibleFBT(int n) { - if (n % 2 == 0) { - // 题目描述的满二叉树不可能是偶数个节点 - return new LinkedList<>(); - } - memo = new LinkedList[n + 1]; - return build(n); - } - - // 定义:输入一个 n,生成节点树为 n 的所有可能的满二叉树 - public List build(int n) { - List res = new LinkedList<>(); - // base case - if (n == 1) { - res.add(new TreeNode(0)); - return res; - } - if (memo[n] != null) { - // 避免冗余计算 - return memo[n]; - } - - // 递归生成所有符合条件的左右子树 - for (int i = 1; i < n; i += 2) { - int j = n - i - 1; - // 利用函数定义,生成左右子树 - List leftSubTrees = build(i); - List rightSubTrees = build(j); - // 左右子树的不同排列也能构成不同的二叉树 - for (TreeNode left : leftSubTrees) { - for (TreeNode right : rightSubTrees) { - // 生成根节点 - TreeNode root = new TreeNode(0); - // 组装出一种可能的二叉树形状 - root.left = left; - root.right = right; - // 加入结果列表 - res.add(root); - } - } - } - // 存入备忘录 - memo[n] = res; - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" deleted file mode 100644 index 4cac6df..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\2212.java" +++ /dev/null @@ -1,48 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 998. 最大二叉树 II - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 最大二叉树2 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - Assertions.assertEquals(TreeNode.buildTree(5, 4, null, 1, 3, null, null, 2), - s.insertIntoMaxTree(TreeNode.buildTree(4, 1, 3, null, null, 2), 5)); - - Assertions.assertEquals(TreeNode.buildTree(5, 2, 4, null, 1, null, 3), - s.insertIntoMaxTree(TreeNode.buildTree(5, 2, 4, null, 1), 3)); - - Assertions.assertEquals(TreeNode.buildTree(5, 2, 4, null, 1, 3), - s.insertIntoMaxTree(TreeNode.buildTree(5, 2, 3, null, 1), 4)); - } - - static class Solution { - - public TreeNode insertIntoMaxTree(TreeNode root, int val) { - if (root == null) { return new TreeNode(val); } - if (root.val < val) { - // 如果 val 是整棵树最大的,那么原来的这棵树应该是 val 节点的左子树, - // 因为 val 节点是接在原始数组 a 的最后一个元素 - TreeNode node = new TreeNode(val); - node.left = root; - return node; - } else { - // 如果 val 不是最大的,那么就应该在右子树上, - // 因为 val 节点是接在原始数组 a 的最后一个元素 - root.right = insertIntoMaxTree(root.right, val); - return root; - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index 5bb6c8f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\346\240\271\346\215\256\345\211\215\345\272\217\345\222\214\345\220\216\345\272\217\351\201\215\345\216\206\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,59 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.HashMap; -import java.util.Map; - -/** - * 106. - * 从中序与后序遍历序列构造二叉树 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 根据前序和后序遍历构造二叉树 { - - public static void main(String[] args) { - - Solution s = new Solution(); - TreeNode output1 = s.constructFromPrePost(new int[] { 1, 2, 4, 5, 3, 6, 7 }, - new int[] { 4, 5, 2, 6, 7, 3, 1 }); - Assertions.assertEquals(TreeNode.buildTree(1, 2, 3, 4, 5, 6, 7), output1); - - TreeNode output2 = s.constructFromPrePost(new int[] { 1 }, new int[] { 1 }); - Assertions.assertEquals(TreeNode.buildTree(1), output2); - } - - static class Solution { - - Map map = new HashMap<>(); - - public TreeNode constructFromPrePost(int[] preorder, int[] postorder) { - if (preorder.length == 0 || postorder.length == 0) { return null; } - for (int i = 0; i < postorder.length; i++) { - map.put(postorder[i], i); - } - return build(preorder, 0, preorder.length - 1, - postorder, 0, postorder.length - 1); - } - - public TreeNode build(int[] preorder, int preLow, int preHigh, - int[] postorder, int postLow, int postHigh) { - if (preLow > preHigh) { return null; } - if (preLow == preHigh) { return new TreeNode(preorder[preLow]); } - int leftRootVal = preorder[preLow + 1]; - int leftPostHigh = map.get(leftRootVal); - int leftLen = leftPostHigh - postLow + 1; - TreeNode root = new TreeNode(preorder[preLow]); - root.left = build(preorder, preLow + 1, preLow + leftLen, - postorder, postLow, leftPostHigh); - root.right = build(preorder, preLow + leftLen + 1, preHigh, - postorder, leftPostHigh + 1, postHigh - 1); - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\233\270\345\220\214\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\233\270\345\220\214\347\232\204\346\240\221.java" deleted file mode 100644 index 04205a8..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\233\270\345\220\214\347\232\204\346\240\221.java" +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 100. 相同的树 - * - * @author Zhang Peng - * @date 2020-01-28 - */ -public class 相同的树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isSameTree(TreeNode.buildTree(1, 2, 3), TreeNode.buildTree(1, 2, 3))); - Assertions.assertFalse(s.isSameTree(TreeNode.buildTree(1, 2), TreeNode.buildTree(1, 2, 3))); - Assertions.assertFalse(s.isSameTree(TreeNode.buildTree(1, 2, 1), TreeNode.buildTree(1, 1, 2))); - } - - static class Solution { - - public boolean isSameTree(TreeNode p, TreeNode q) { - if (p == null && q == null) { return true; } - if (p == null || q == null) { return false; } - if (p.val != q.val) { return false; } - return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index f3d1c1f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\347\277\273\350\275\254\347\255\211\344\273\267\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 951. 翻转等价二叉树 - * - * @author Zhang Peng - * @date 2025-10-29 - */ -public class 翻转等价二叉树 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode p = TreeNode.buildTree(1, 2, 3, 4, 5, 6, null, null, null, 7, 8); - TreeNode q = TreeNode.buildTree(1, 3, 2, null, 6, 4, 5, null, null, null, null, 8, 7); - Assertions.assertTrue(s.flipEquiv(p, q)); - Assertions.assertTrue(s.flipEquiv(TreeNode.buildTree(), TreeNode.buildTree())); - Assertions.assertFalse(s.flipEquiv(TreeNode.buildTree(), TreeNode.buildTree(1))); - } - - static class Solution { - - // 定义:输入两棵二叉树,判断这两棵二叉树是否是翻转等价的 - public boolean flipEquiv(TreeNode root1, TreeNode root2) { - // 判断 root1 和 root2 两个节点是否能够匹配 - if (root1 == null && root2 == null) { return true; } - if (root1 == null || root2 == null) { return false; } - if (root1.val != root2.val) { return false; } - // 根据函数定义,判断子树是否能够匹配 - // 不翻转、翻转两种情况满足一种即可算是匹配 - return (flipEquiv(root1.left, root2.left) && flipEquiv(root1.right, root2.right)) // 不翻转子树 - || (flipEquiv(root1.left, root2.right) && flipEquiv(root1.right, root2.left)); // 翻转子树 - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" deleted file mode 100644 index 6165bf4..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/divide/\351\252\214\350\257\201\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\345\272\217\345\210\227\345\214\226.java" +++ /dev/null @@ -1,72 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.divide; - -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 331. 验证二叉树的前序序列化 - * - * @author Zhang Peng - * @date 2025-08-15 - */ -public class 验证二叉树的前序序列化 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertTrue(s.isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); - Assertions.assertFalse(s.isValidSerialization("1,#")); - Assertions.assertFalse(s.isValidSerialization("9,#,#,1")); - - Solution2 s2 = new Solution2(); - Assertions.assertTrue(s2.isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); - Assertions.assertFalse(s2.isValidSerialization("1,#")); - Assertions.assertFalse(s2.isValidSerialization("9,#,#,1")); - } - - static class Solution { - - /** - * 参考题解:https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/solutions/651132/pai-an-jiao-jue-de-liang-chong-jie-fa-zh-66nt - */ - public boolean isValidSerialization(String preorder) { - LinkedList stack = new LinkedList<>(); - for (String s : preorder.split(",")) { - stack.push(s); - while (stack.size() >= 3 - && stack.get(0).equals("#") - && stack.get(1).equals("#") - && !stack.get(2).equals("#")) { - stack.pop(); - stack.pop(); - stack.pop(); - stack.push("#"); - } - } - return stack.size() == 1 && stack.pop().equals("#"); - } - - } - - static class Solution2 { - - /** - * 参考题解:https://leetcode.cn/problems/verify-preorder-serialization-of-a-binary-tree/solutions/651132/pai-an-jiao-jue-de-liang-chong-jie-fa-zh-66nt - */ - public boolean isValidSerialization(String preorder) { - int diff = 1; - for (String s : preorder.split(",")) { - diff -= 1; - if (diff < 0) { - return false; - } - if (!s.equals("#")) { - diff += 2; - } - } - return diff == 0; - } - - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/package-info.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/package-info.java deleted file mode 100644 index 8d7a7e9..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 二叉树算法 - * - * @author Zhang Peng - * @since 2020-06-18 - */ -package io.github.dunwu.algorithm.tree.btree; diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" deleted file mode 100644 index 908fd91..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\344\270\255\347\232\204\344\274\252\345\233\236\346\226\207\350\267\257\345\276\204.java" +++ /dev/null @@ -1,68 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.traverse; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 1457. 二叉树中的伪回文路径 - * - * @author Zhang Peng - * @date 2025-08-15 - */ -public class 二叉树中的伪回文路径 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(2, - s.pseudoPalindromicPaths(TreeNode.buildTree(2, 3, 1, 3, 1, null, 1))); - Assertions.assertEquals(1, - s.pseudoPalindromicPaths(TreeNode.buildTree(2, 1, 1, 1, 3, null, null, null, null, null, 1))); - Assertions.assertEquals(1, - s.pseudoPalindromicPaths(TreeNode.buildTree(9))); - } - - static class Solution { - - int res = 0; - // 计数数组,题目说了 1 <= root.val <= 9 - int[] count; - - public int pseudoPalindromicPaths(TreeNode root) { - res = 0; - count = new int[10]; - traverse(root); - return res; - } - - public void traverse(TreeNode root) { - if (root == null) { return; } - - // 选择 - if (root.left == null && root.right == null) { - count[root.val]++; - int odd = 0; - for (int cnt : count) { - if (cnt % 2 != 0) { - odd++; - } - } - if (odd <= 1) { - res++; - } - count[root.val]--; - return; - } - - // 选择 - count[root.val]++; - - traverse(root.left); - traverse(root.right); - - // 取消选择 - count[root.val]--; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" deleted file mode 100644 index 58ab169..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276.java" +++ /dev/null @@ -1,96 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.traverse; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; - -/** - * 求根节点到叶节点数字之和 - * - * @author Zhang Peng - * @date 2025-08-15 - */ -public class 二叉树的右视图 { - - public static void main(String[] args) { - - Solution s = new Solution(); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 4 }, - s.rightSideView(TreeNode.buildTree(1, 2, 3, null, 5, null, 4)).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 4, 5 }, - s.rightSideView(TreeNode.buildTree(1, 2, 3, 4, null, null, null, 5)).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1, 3 }, - s.rightSideView(TreeNode.buildTree(1, null, 3)).toArray()); - Assertions.assertArrayEquals(new Integer[] {}, - s.rightSideView(TreeNode.buildTree()).toArray()); - - Solution2 s2 = new Solution2(); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 4 }, - s2.rightSideView(TreeNode.buildTree(1, 2, 3, null, 5, null, 4)).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 4, 5 }, - s2.rightSideView(TreeNode.buildTree(1, 2, 3, 4, null, null, null, 5)).toArray()); - Assertions.assertArrayEquals(new Integer[] { 1, 3 }, - s2.rightSideView(TreeNode.buildTree(1, null, 3)).toArray()); - Assertions.assertArrayEquals(new Integer[] {}, - s2.rightSideView(TreeNode.buildTree()).toArray()); - - } - - // 【层序遍历】思路 - static class Solution { - - LinkedList res = null; - - public List rightSideView(TreeNode root) { - if (root == null) { return new LinkedList<>(); } - - res = new LinkedList<>(); - LinkedList queue = new LinkedList<>(); - queue.offer(root); - - while (!queue.isEmpty()) { - int size = queue.size(); - // 每层将最后一个元素加入结果集 - for (int i = 0; i < size; i++) { - TreeNode node = queue.poll(); - if (node.left != null) { queue.offer(node.left); } - if (node.right != null) { queue.offer(node.right); } - if (i == size - 1) { - res.add(node.val); - } - } - } - return res; - } - - } - - // 【遍历递归】思路 - static class Solution2 { - - int depth = 0; - LinkedHashMap map = null; - - public List rightSideView(TreeNode root) { - map = new LinkedHashMap<>(); - traverse(root); - return new LinkedList<>(map.values()); - } - - public void traverse(TreeNode root) { - if (root == null) { return; } - depth++; - if (!map.containsKey(depth)) { - map.put(depth, root.val); - } - traverse(root.right); - traverse(root.left); - depth--; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" deleted file mode 100644 index 8da62a1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204.java" +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.traverse; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * 二叉树的所有路径 - * - * @author Zhang Peng - * @since 2025-08-15 - */ -public class 二叉树的所有路径 { - - public static void main(String[] args) { - - Solution s = new Solution(); - Assertions.assertArrayEquals(Arrays.asList("1->2->5", "1->3").toArray(), - s.binaryTreePaths(TreeNode.buildTree(1, 2, 3, 5)).toArray()); - Assertions.assertArrayEquals(Collections.singletonList("1").toArray(), - s.binaryTreePaths(TreeNode.buildTree(1)).toArray()); - } - - static class Solution { - - LinkedList res = null; - LinkedList paths = null; - - public List binaryTreePaths(TreeNode root) { - res = new LinkedList<>(); - paths = new LinkedList<>(); - traverse(root); - return res; - } - - public void traverse(TreeNode root) { - if (root == null) { return; } - - // 选择 - paths.addLast(String.valueOf(root.val)); - if (root.left == null && root.right == null) { - res.addLast(String.join("->", paths)); - // System.out.printf("res: %s\n", JSONUtil.toJsonStr(res)); - } - - // 【前序】 - // System.out.format("root: %s -> root.left: %s\n", root.val, root.left.val); - traverse(root.left); - // 【中序】 - // System.out.format("root.left: %s -> root: %s\n", root.left.val, root.val); - // System.out.format("root: %s -> root.right: %s\n", root.val, root.right.val); - traverse(root.right); - // 【后序】 - // System.out.format("root.right: %s -> root: %s\n", root.right.val, root.val); - - // 取消选择 - paths.removeLast(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" deleted file mode 100644 index cabcee9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\345\217\266\347\273\223\347\202\271\345\274\200\345\247\213\347\232\204\346\234\200\345\260\217\345\255\227\347\254\246\344\270\262.java" +++ /dev/null @@ -1,71 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.traverse; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 988. 从叶结点开始的最小字符串 - * - * @author Zhang Peng - * @date 2025-08-15 - */ -public class 从叶结点开始的最小字符串 { - - public static void main(String[] args) { - - Solution s = new Solution(); - Assertions.assertEquals("dba", - s.smallestFromLeaf(TreeNode.buildTree(0, 1, 2, 3, 4, 3, 4))); - Assertions.assertEquals("adz", - s.smallestFromLeaf(TreeNode.buildTree(25, 1, 3, 1, 3, 0, 2))); - Assertions.assertEquals("abc", - s.smallestFromLeaf(TreeNode.buildTree(2, 2, 1, null, 1, 0, null, 0))); - } - - static class Solution { - - String res = null; - LinkedList nodes = null; - - public String smallestFromLeaf(TreeNode root) { - res = null; - nodes = new LinkedList<>(); - traverse(root); - return res; - } - - public void traverse(TreeNode root) { - // 校验 - if (root == null) { return; } - - // 选择 - nodes.addLast(root.val); - if (root.left == null && root.right == null) { - String str = toString(nodes); - // System.out.printf("\tstr: %s\n", str); - if (res == null || str.compareTo(res) < 0) { - res = str; - } - } - - traverse(root.left); - traverse(root.right); - - // 取消选择 - nodes.removeLast(); - } - - public String toString(LinkedList nodes) { - StringBuilder sb = new StringBuilder(); - for (int node : nodes) { - char c = (char) (node + 'a'); - sb.insert(0, c); - } - return sb.toString(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" deleted file mode 100644 index 6b45eec..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\344\273\216\346\240\271\345\210\260\345\217\266\347\232\204\344\272\214\350\277\233\345\210\266\346\225\260\344\271\213\345\222\214.java" +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.traverse; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 1022. 从根到叶的二进制数之和 - * - * @author Zhang Peng - * @date 2025-08-15 - */ -public class 从根到叶的二进制数之和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(22, s.sumRootToLeaf(TreeNode.buildTree(1, 0, 1, 0, 1, 0, 1))); - Assertions.assertEquals(0, s.sumRootToLeaf(TreeNode.buildTree(0))); - } - - static class Solution { - - int sum = 0; - LinkedList nodes; - - public int sumRootToLeaf(TreeNode root) { - sum = 0; - nodes = new LinkedList<>(); - traverse(root); - return sum; - } - - public void traverse(TreeNode node) { - // 校验 - if (node == null) return; - - // 选择 - nodes.addLast(node.val); - if (node.left == null && node.right == null) { - Integer num = toNum(nodes); - System.out.printf("\tnum: %d\n", num); - sum += num; - } - - traverse(node.left); - traverse(node.right); - - // 取消选择 - nodes.removeLast(); - } - - Integer toNum(LinkedList nodes) { - int num = 0; - for (int node : nodes) { - num = num * 2 + node; - } - return num; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" deleted file mode 100644 index b04a5ff..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\345\242\236\345\212\240\344\270\200\350\241\214.java" +++ /dev/null @@ -1,76 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.traverse; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; -import java.util.List; - -/** - * 623. 在二叉树中增加一行 - * - * @author Zhang Peng - * @date 2025-08-15 - */ -public class 在二叉树中增加一行 { - - public static void main(String[] args) { - TreeNode root = TreeNode.buildTree(4, 2, 6, 3, 1, 5); - TreeNode newRoot = new Solution().addOneRow(root, 1, 2); - List list = TreeNode.toValueList(newRoot); - Assertions.assertArrayEquals(new Integer[] { 4, 1, 1, 2, null, null, 6, 3, 1, 5 }, list.toArray()); - - TreeNode root2 = TreeNode.buildTree(4, 2, 6, 3, 1, 5); - TreeNode newRoot2 = new Solution().addOneRow(root2, 1, 1); - List list2 = TreeNode.toValueList(newRoot2); - Assertions.assertArrayEquals(new Integer[] { 1, 4, null, 2, 6, 3, 1, 5 }, list2.toArray()); - } - - static class Solution { - - public TreeNode addOneRow(TreeNode root, int val, int depth) { - if (root == null) { return root; } - if (depth == 1) { - TreeNode newRoot = new TreeNode(val); - newRoot.left = root; - return newRoot; - } - LinkedList q = new LinkedList<>(); - int level = 1; - q.offer(root); - while (!q.isEmpty()) { - - int size = q.size(); - if (level == depth - 1) { - for (int i = 0; i < size; i++) { - TreeNode node = q.poll(); - TreeNode left = node.left; - node.left = new TreeNode(val); - node.left.left = left; - - TreeNode right = node.right; - node.right = new TreeNode(val); - node.right.right = right; - } - break; - } - - // 层序遍历 - for (int i = 0; i < size; i++) { - TreeNode node = q.poll(); - if (node.left != null) { - q.offer(node.left); - } - if (node.right != null) { - q.offer(node.right); - } - } - - level++; - } - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" deleted file mode 100644 index 7d24178..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.traverse; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 404. 左叶子之和 - * - * @author Zhang Peng - * @date 2025-08-15 - */ -public class 左叶子之和 { - - public static void main(String[] args) { - Assertions.assertEquals(24, - new Solution().sumOfLeftLeaves(TreeNode.buildTree(3, 9, 20, null, null, 15, 7))); - - Assertions.assertEquals(4, - new Solution().sumOfLeftLeaves(TreeNode.buildTree(1, 2, 3, 4, 5))); - - Assertions.assertEquals(0, - new Solution().sumOfLeftLeaves(TreeNode.buildTree(1))); - } - - static class Solution { - - int sum = 0; - - public int sumOfLeftLeaves(TreeNode root) { - traverse(root); - return sum; - } - - public void traverse(TreeNode root) { - if (root == null) { return; } - if (root.left != null && - root.left.left == null && root.left.right == null) { - sum += root.left.val; - } - traverse(root.left); - traverse(root.right); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" deleted file mode 100644 index 737d9b7..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/traverse/\346\261\202\346\240\271\350\212\202\347\202\271\345\210\260\345\217\266\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214.java" +++ /dev/null @@ -1,60 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree.traverse; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 求根节点到叶节点数字之和 - * - * @author Zhang Peng - * @date 2025-08-15 - */ -public class 求根节点到叶节点数字之和 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(25, s.sumNumbers(TreeNode.buildTree(1, 2, 3))); - Assertions.assertEquals(1026, s.sumNumbers(TreeNode.buildTree(4, 9, 0, 5, 1))); - } - - static class Solution { - - int res = 0; - LinkedList paths = null; - - public int sumNumbers(TreeNode root) { - res = 0; - paths = new LinkedList<>(); - traverse(root); - return res; - } - - public void traverse(TreeNode root) { - // 【校验】 - if (root == null) { return; } - - // 选择 - paths.addLast(root.val); - if (root.left == null && root.right == null) { - int num = 0; - for (Integer path : paths) { - num = num * 10 + path; - } - res += num; - } - - // 【前序】 - traverse(root.left); - // 【中序】 - traverse(root.right); - // 【后序】 - - // 取消选择 - paths.removeLast(); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" deleted file mode 100644 index 7eb9b65..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\345\261\225\345\274\200\344\270\272\351\223\276\350\241\250.java" +++ /dev/null @@ -1,61 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 114. 二叉树展开为链表 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 二叉树展开为链表 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - TreeNode root = TreeNode.buildTree(1, 2, 5, 3, 4, null, 6); - s.flatten(root); - Assertions.assertArrayEquals(new Integer[] { 1, null, 2, null, 3, null, 4, null, 5, null, 6 }, - TreeNode.toValueList(root).toArray()); - - TreeNode root2 = TreeNode.buildTree(0); - s.flatten(root2); - Assertions.assertArrayEquals(new Integer[] { 0 }, TreeNode.toValueList(root2).toArray()); - - TreeNode root3 = TreeNode.buildTree(); - s.flatten(root3); - Assertions.assertArrayEquals(new Integer[] {}, TreeNode.toValueList(root3).toArray()); - } - - static class Solution { - - public void flatten(TreeNode root) { - // base case - if (root == null) { return; } - - // 利用定义,把左右子树拉平 - flatten(root.left); - flatten(root.right); - - // *** 后序遍历位置 *** - // 1、左右子树已经被拉平成一条链表 - TreeNode left = root.left; - TreeNode right = root.right; - - // 2、将左子树作为右子树 - root.left = null; - root.right = left; - - // 3、将原先的右子树接到当前右子树的末端 - TreeNode p = root; - while (p.right != null) { - p = p.right; - } - p.right = right; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" deleted file mode 100644 index 4eac5e3..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\344\270\216\345\217\215\345\272\217\345\210\227\345\214\226.java" +++ /dev/null @@ -1,88 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.LinkedList; - -/** - * 297. 二叉树的序列化与反序列化 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 二叉树的序列化与反序列化 { - - public static void main(String[] args) { - - String input1 = "1,2,3,null,null,4,5,null,null,null,null,"; - String input2 = "null,"; - String input3 = "1,null,null,"; - String input4 = "1,2,null,null,null,"; - - Solution s = new Solution(); - Assertions.assertEquals(input1, s.serialize(s.deserialize(input1))); - Assertions.assertEquals(input2, s.serialize(s.deserialize(input2))); - Assertions.assertEquals(input3, s.serialize(s.deserialize(input3))); - Assertions.assertEquals(input4, s.serialize(s.deserialize(input4))); - } - - static class Solution { - - public static final String SEP = ","; - public static final String NULL = "null"; - - // 主函数,将二叉树序列化为字符串 - public String serialize(TreeNode root) { - StringBuilder sb = new StringBuilder(); - serialize(root, sb); - return sb.toString(); - } - - // 辅助函数,将二叉树存入 StringBuilder - void serialize(TreeNode root, StringBuilder sb) { - if (root == null) { - sb.append(NULL).append(SEP); - return; - } - - // ****** 前序位置 ******** - sb.append(root.val).append(SEP); - - // *********************** - - serialize(root.left, sb); - serialize(root.right, sb); - } - - // 主函数,将字符串反序列化为二叉树结构 - public TreeNode deserialize(String data) { - // 将字符串转化成列表 - LinkedList nodes = new LinkedList<>(); - for (String s : data.split(SEP)) { - nodes.addLast(s); - } - return deserialize(nodes); - } - - // 辅助函数,通过 nodes 列表构造二叉树 - TreeNode deserialize(LinkedList nodes) { - if (nodes.isEmpty()) return null; - - // ****** 前序位置 ******** - // 列表最左侧就是根节点 - String first = nodes.removeFirst(); - if (first.equals(NULL)) return null; - TreeNode root = new TreeNode(Integer.parseInt(first)); - - // ********************* - - root.left = deserialize(nodes); - root.right = deserialize(nodes); - - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" deleted file mode 100644 index c01f06a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" +++ /dev/null @@ -1,82 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 104. 二叉树的最大深度 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 二叉树的最大深度 { - - public static void main(String[] args) { - - Solution s = new Solution(); - Assertions.assertEquals(3, s.maxDepth(TreeNode.buildTree(3, 9, 20, null, null, 15, 7))); - Assertions.assertEquals(2, s.maxDepth(TreeNode.buildTree(1, null, 2))); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(3, s2.maxDepth(TreeNode.buildTree(3, 9, 20, null, null, 15, 7))); - Assertions.assertEquals(2, s2.maxDepth(TreeNode.buildTree(1, null, 2))); - } - - /** - * 【分解】思路解法 - */ - static class Solution { - - public int maxDepth(TreeNode root) { - if (root == null) { return 0; } - - // 计算左右子树的最大深度 - int left = maxDepth(root.left); - int right = maxDepth(root.right); - - // 根据左右子树的最大深度推出原二叉树的最大深度 - // 整棵树的最大深度等于左右子树的最大深度取最大值, - // 然后再加上根节点自己 - return Math.max(left, right) + 1; - } - - } - - /** - * 【遍历】思路解法 - */ - static class Solution2 { - - // 记录最大深度 - int res = 0; - // 记录遍历到的节点的深度 - int depth = 0; - - public int maxDepth(TreeNode root) { - // 重置全局变量 - res = 0; - depth = 0; - traverse(root); - return res; - } - - // 遍历二叉树 - void traverse(TreeNode root) { - if (root == null) { return; } - - // 【前序遍历位置】(进入节点)增加深度 - depth++; - // 遍历到叶子节点时记录最大深度 - if (root.left == null && root.right == null) { - res = Math.max(res, depth); - } - traverse(root.left); - // 【中序遍历位置】 - traverse(root.right); - // 【后序遍历位置】(离开节点)减少深度 - depth--; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" deleted file mode 100644 index 38bfbb8..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" +++ /dev/null @@ -1,36 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 二叉树的最小深度 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 二叉树的最小深度 { - - public static void main(String[] args) { - Solution s = new Solution(); - - TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); - Assertions.assertEquals(2, s.minDepth(root)); - - TreeNode root2 = TreeNode.buildTree(2, null, 3, null, 4, null, 5, null, 6); - Assertions.assertEquals(5, s.minDepth(root2)); - } - - static class Solution { - - public int minDepth(TreeNode root) { - if (root == null) { return 0; } - int left = minDepth(root.left); - int right = minDepth(root.right); - if (root.left == null || root.right == null) { return left + right + 1; } - return Math.min(left, right) + 1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" deleted file mode 100644 index 976393b..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" +++ /dev/null @@ -1,82 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 236. 二叉树的最近公共祖先 - * 解题思路 - * - * @author Zhang Peng - * @date 2020-01-28 - */ -public class 二叉树的最近公共祖先 { - - public static void main(String[] args) { - - Solution s = new Solution(); - TreeNode input = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); - TreeNode output1 = s.lowestCommonAncestor(input, TreeNode.find(input, 2), TreeNode.find(input, 8)); - Assertions.assertNotNull(output1); - Assertions.assertEquals(6, output1.val); - TreeNode output2 = s.lowestCommonAncestor(input, TreeNode.find(input, 2), TreeNode.find(input, 4)); - Assertions.assertNotNull(output2); - Assertions.assertEquals(2, output2.val); - - Solution2 s2 = new Solution2(); - TreeNode input2 = TreeNode.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5); - TreeNode output3 = s2.lowestCommonAncestor(input2, TreeNode.find(input2, 2), TreeNode.find(input2, 8)); - Assertions.assertNotNull(output3); - Assertions.assertEquals(6, output3.val); - TreeNode output4 = s2.lowestCommonAncestor(input2, TreeNode.find(input2, 2), TreeNode.find(input2, 4)); - Assertions.assertNotNull(output4); - Assertions.assertEquals(2, output4.val); - } - - static class Solution { - - public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { - - if (root == null) return null; - if (root == p || root == q) return root; - - TreeNode left = lowestCommonAncestor(root.left, p, q); - TreeNode right = lowestCommonAncestor(root.right, p, q); - - if (left != null && right != null) { return root; } - return left != null ? left : right; - } - - } - - static class Solution2 { - - private TreeNode res = null; - - public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { - res = null; - return find(root, p.val, q.val); - } - - TreeNode find(TreeNode root, int p, int q) { - if (root == null) { return null; } - // 如果已经找到 LCA 节点,直接返回 - if (res != null) { return res; } - - if (root.val == p || root.val == q) return root; - - TreeNode left = find(root.left, p, q); - TreeNode right = find(root.right, p, q); - - if (left != null && right != null) { - // 当前节点是 LCA 节点,记录下来 - res = root; - return res; - } - return left != null ? left : right; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" deleted file mode 100644 index c55a9d6..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\347\233\264\345\276\204.java" +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 543. 二叉树的直径 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 二叉树的直径 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(3, s.diameterOfBinaryTree(TreeNode.buildTree(1, 2, 3, 4, 5))); - Assertions.assertEquals(1, s.diameterOfBinaryTree(TreeNode.buildTree(1, 2))); - Assertions.assertEquals(0, s.diameterOfBinaryTree(TreeNode.buildTree(1))); - Assertions.assertEquals(2, s.diameterOfBinaryTree(TreeNode.buildTree(2, 3, null, 1))); - } - - static class Solution { - - private int max = 0; - - public int diameterOfBinaryTree(TreeNode root) { - max = 0; - depth(root); - return max; - } - - public int depth(TreeNode root) { - if (root == null) { return 0; } - int left = depth(root.left); - int right = depth(root.right); - int depth = Math.max(left, right) + 1; - max = Math.max(max, left + right); - return depth; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" deleted file mode 100644 index 1b91f8f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\272\214\345\217\211\346\240\221\347\232\204\351\224\257\351\275\277\345\275\242\345\261\202\346\254\241\351\201\215\345\216\206.java" +++ /dev/null @@ -1,73 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * 103. 二叉树的锯齿形层次遍历 - * - * @author Zhang Peng - * @date 2025-08-18 - */ -public class 二叉树的锯齿形层次遍历 { - - public static void main(String[] args) { - - Solution s = new Solution(); - - TreeNode root = TreeNode.buildTree(3, 9, 20, null, null, 15, 7); - List> expect = new LinkedList<>(); - expect.add(Arrays.asList(3)); - expect.add(Arrays.asList(20, 9)); - expect.add(Arrays.asList(15, 7)); - Assertions.assertArrayEquals(expect.toArray(), s.zigzagLevelOrder(root).toArray()); - - TreeNode root2 = TreeNode.buildTree(1); - List> expect2 = new LinkedList<>(); - expect2.add(Arrays.asList(1)); - Assertions.assertArrayEquals(expect2.toArray(), s.zigzagLevelOrder(root2).toArray()); - - TreeNode root3 = TreeNode.buildTree(); - List> expect3 = new LinkedList<>(); - Assertions.assertArrayEquals(expect3.toArray(), s.zigzagLevelOrder(root3).toArray()); - } - - static class Solution { - - public List> zigzagLevelOrder(TreeNode root) { - - if (root == null) { return new LinkedList<>(); } - - LinkedList q = new LinkedList<>(); - LinkedList> res = new LinkedList<>(); - q.offer(root); - - boolean reverse = false; - while (!q.isEmpty()) { - int size = q.size(); - List cur = new LinkedList<>(); - - for (int i = 0; i < size; i++) { - TreeNode node = q.poll(); - cur.add(node.val); - if (node.left != null) { q.offer(node.left); } - if (node.right != null) { q.offer(node.right); } - } - if (reverse) { - Collections.reverse(cur); - } - res.add(cur); - reverse = !reverse; - } - - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index 729b3c0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\344\273\216\345\205\210\345\272\217\351\201\215\345\216\206\350\277\230\345\216\237\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,76 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; - -import java.util.Stack; - -/** - * @author Zhang Peng - * @since 2020-06-18 - */ -public class 从先序遍历还原二叉树 { - - public static void main(String[] args) { - TreeNode result = recoverFromPreorder("1-2--3--4-5--6--7"); - System.out.println(TreeNode.toList(result)); - } - - public static TreeNode recoverFromPreorder(String S) { - if (S == null || S.length() == 0) return null; - - Stack stack = new Stack<>(); - for (int i = 0; i < S.length(); i++) { - int level = 0; - - // 获取节点深度 - if (S.charAt(i) == '-') { - while (i < S.length() && S.charAt(i) == '-') { - level++; - i++; - } - } - - // 获取节点值 - int data = 0; - if (S.charAt(i) != '-') { - while (i < S.length() && S.charAt(i) != '-') { - data = data * 10 + (S.charAt(i) - '0'); - i++; - } - i--; - } - - // 打印必然成对出现的 节点深度 和 节点值 - System.out.printf("level = %d, num = %d\n", level, data); - - // 构建新节点 - TreeNode node = new TreeNode(data); - - // 栈为空,push 栈顶节点 - if (stack.isEmpty()) { - stack.push(node); - continue; - } - - // 如果栈的 size > 当前节点的 level,即 栈顶节点的 level >= 当前节点的level - // 则说明栈顶不是父亲,栈顶遇到的已经是别人的儿子 - // 说明栈顶的儿子已经找齐了,即自己的子树已经构建完了,该出栈了(子调用有了结果) - while (stack.size() > level) { - stack.pop(); - } - - TreeNode parent = stack.peek(); - if (parent.left == null) { - parent.left = node; - } else { - parent.right = node; - } - stack.push(node); - } - while (stack.size() > 1) { - stack.pop(); - } - return stack.pop(); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" deleted file mode 100644 index 03dc2b9..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\217\266\345\255\220\347\233\270\344\274\274\347\232\204\346\240\221.java" +++ /dev/null @@ -1,54 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * 叶子相似的树 算法实现 - * - *

- * 请考虑一颗二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个 叶值序列 。
- *
- *
- *
- * 举个例子,如上图所示,给定一颗叶值序列为 (6, 7, 4, 9, 8) 的树。
- *
- * 如果有两颗二叉树的叶值序列是相同,那么我们就认为它们是 叶相似 的。
- *
- * 如果给定的两个头结点分别为 root1 和 root2 的树是叶相似的,则返回 true;否则返回 false 。
- *
- * 提示:
- *
- * 给定的两颗树可能会有 1 到 100 个结点。
- * 
- * - * @see 叶子相似的树 - */ -public class 叶子相似的树 { - - public static void main(String[] args) { - TreeNode tree1 = TreeNode.buildTree(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4); - TreeNode tree2 = TreeNode.buildTree(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8); - Assertions.assertTrue(leafSimilar(tree1, tree2)); - } - - public static boolean leafSimilar(TreeNode root1, TreeNode root2) { - List leafs1 = new LinkedList<>(); - List leafs2 = new LinkedList<>(); - leafNodes(root1, leafs1); - leafNodes(root2, leafs2); - return Arrays.equals(leafs1.toArray(), leafs2.toArray()); - } - - public static void leafNodes(TreeNode root, List leafs) { - if (root == null) { return; } - if (root.left == null && root.right == null) { leafs.add(root.val); } - leafNodes(root.left, leafs); - leafNodes(root.right, leafs); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" deleted file mode 100644 index e6aeaec..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221\347\232\204\350\212\202\347\202\271\344\270\252\346\225\260.java" +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 222. 完全二叉树的节点个数 - * - * @author Zhang Peng - * @since 2020-07-06 - */ -public class 完全二叉树的节点个数 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(6, s.countNodes(TreeNode.buildTree(1, 2, 3, 4, 5, 6))); - Assertions.assertEquals(0, s.countNodes(TreeNode.buildTree())); - Assertions.assertEquals(1, s.countNodes(TreeNode.buildTree(1))); - } - - static class Solution { - - public int countNodes(TreeNode root) { - if (root == null) { return 0; } - return countNodes(root.left) + countNodes(root.right) + 1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index 9ac1276..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\346\234\200\345\244\247\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,46 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 654. 最大二叉树 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 最大二叉树 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode output = s.constructMaximumBinaryTree(new int[] { 3, 2, 1, 6, 0, 5 }); - Assertions.assertEquals(TreeNode.buildTree(6, 3, 5, null, 2, 0, null, null, 1), output); - TreeNode output2 = s.constructMaximumBinaryTree(new int[] { 3, 2, 1 }); - Assertions.assertEquals(TreeNode.buildTree(3, null, 2, null, 1), output2); - } - - static class Solution { - - public TreeNode constructMaximumBinaryTree(int[] nums) { - return dfs(nums, 0, nums.length - 1); - } - - public TreeNode dfs(int[] nums, int start, int end) { - if (start > end) { return null; } - int max = -1; - int maxIndex = start; - for (int i = start; i <= end; i++) { - if (nums[i] > max) { - maxIndex = i; - max = nums[i]; - } - } - TreeNode root = new TreeNode(nums[maxIndex]); - root.left = dfs(nums, start, maxIndex - 1); - root.right = dfs(nums, maxIndex + 1, end); - return root; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" deleted file mode 100644 index 30885c1..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\347\277\273\350\275\254\344\272\214\345\217\211\346\240\221.java" +++ /dev/null @@ -1,79 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 226. 翻转二叉树 - * - * @author Zhang Peng - * @date 2025-08-11 - */ -public class 翻转二叉树 { - - public static void main(String[] args) { - Solution s = new Solution(); - Assertions.assertEquals(TreeNode.buildTree(4, 2, 7, 1, 3, 6, 9), - s.invertTree(TreeNode.buildTree(4, 7, 2, 9, 6, 3, 1))); - Assertions.assertEquals(TreeNode.buildTree(2, 3, 1), - s.invertTree(TreeNode.buildTree(2, 1, 3))); - Assertions.assertEquals(TreeNode.buildTree(), - s.invertTree(TreeNode.buildTree())); - - Solution2 s2 = new Solution2(); - Assertions.assertEquals(TreeNode.buildTree(4, 2, 7, 1, 3, 6, 9), - s2.invertTree(TreeNode.buildTree(4, 7, 2, 9, 6, 3, 1))); - Assertions.assertEquals(TreeNode.buildTree(2, 3, 1), - s2.invertTree(TreeNode.buildTree(2, 1, 3))); - Assertions.assertEquals(TreeNode.buildTree(), - s2.invertTree(TreeNode.buildTree())); - } - - /** - * 【分解】思路解法 - */ - static class Solution { - - public TreeNode invertTree(TreeNode root) { - if (root == null) { return root; } - TreeNode left = invertTree(root.left); - TreeNode right = invertTree(root.right); - root.right = left; - root.left = right; - return root; - } - - } - - /** - * 【遍历】思路解法 - */ - static class Solution2 { - - public TreeNode invertTree(TreeNode root) { - traverse(root); - return root; - } - - // 遍历二叉树 - void traverse(TreeNode root) { - if (root == null) { return; } - - // 【前序】 - // System.out.printf("[node -> left]从节点 %s 进入节点 %s\n", root, root.left); - traverse(root.left); - // 【中序】 - // System.out.printf("\t[left -> node]从节点 %s 回到节点 %s\n", root.left, root); - // System.out.printf("\t[node -> right]从节点 %s 进入节点 %s\n", root, root.right); - traverse(root.right); - // 【后序】 - // System.out.printf("\t[right -> node]从节点 %s 回到节点 %s\n", root.right, root); - - TreeNode temp = root.left; - root.left = root.right; - root.right = temp; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" deleted file mode 100644 index 28ae963..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/\350\267\257\345\276\204\346\200\273\345\222\214.java" +++ /dev/null @@ -1,33 +0,0 @@ -package io.github.dunwu.algorithm.tree.btree; - -import io.github.dunwu.algorithm.tree.TreeNode; -import org.junit.jupiter.api.Assertions; - -/** - * 112. 路径总和 - * - * @author Zhang Peng - * @date 2020-01-29 - */ -public class 路径总和 { - - public static void main(String[] args) { - Solution s = new Solution(); - TreeNode tree = TreeNode.buildTree(5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, null, null, 1); - Assertions.assertTrue(s.hasPathSum(tree, 22)); - TreeNode tree2 = TreeNode.buildTree(1, 2); - Assertions.assertFalse(s.hasPathSum(tree2, 1)); - } - - static class Solution { - - public boolean hasPathSum(TreeNode root, int targetSum) { - if (root == null) { return false; } - if (root.left == null && root.right == null && root.val == targetSum) { return true; } - return hasPathSum(root.left, targetSum - root.val) - || hasPathSum(root.right, targetSum - root.val); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index 3f2138f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.dunwu.algorithm.tree.ntree; - -import io.github.dunwu.algorithm.tree.Node; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 589. N 叉树的前序遍历 - * - * @author Zhang Peng - * @date 2025-10-27 - */ -public class N叉树的前序遍历 { - - public static void main(String[] args) { - Solution s = new Solution(); - Node node3 = new Node(3); - node3.children.add(new Node(5)); - node3.children.add(new Node(6)); - Node root = new Node(1); - root.children.add(node3); - root.children.add(new Node(2)); - root.children.add(new Node(4)); - Assertions.assertArrayEquals(new Integer[] { 1, 3, 5, 6, 2, 4 }, s.preorder(root).toArray()); - } - - static class Solution { - - public List preorder(Node root) { - List res = new ArrayList<>(); - dfs(root, res); - return res; - } - - public void dfs(Node root, List res) { - if (root == null) { return; } - res.add(root.val); - for (int i = 0; i < root.children.size(); i++) { - dfs(root.children.get(i), res); - } - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index 17db4ac..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.dunwu.algorithm.tree.ntree; - -import io.github.dunwu.algorithm.tree.Node; -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.List; - -/** - * 589. N 叉树的前序遍历 - * - * @author Zhang Peng - * @date 2025-10-27 - */ -public class N叉树的后序遍历 { - - public static void main(String[] args) { - Solution s = new Solution(); - Node node3 = new Node(3); - node3.children.add(new Node(5)); - node3.children.add(new Node(6)); - Node root = new Node(1); - root.children.add(node3); - root.children.add(new Node(2)); - root.children.add(new Node(4)); - Assertions.assertArrayEquals(new Integer[] { 5, 6, 3, 2, 4, 1 }, s.postorder(root).toArray()); - } - - static class Solution { - - public List postorder(Node root) { - List res = new ArrayList<>(); - dfs(root, res); - return res; - } - - public void dfs(Node root, List res) { - if (root == null) { return; } - for (int i = 0; i < root.children.size(); i++) { - dfs(root.children.get(i), res); - } - res.add(root.val); - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" deleted file mode 100644 index ca4152f..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" +++ /dev/null @@ -1,61 +0,0 @@ -package io.github.dunwu.algorithm.tree.ntree; - -import io.github.dunwu.algorithm.tree.Node; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -/** - * 429. N 叉树的层序遍历 - * - * @author Zhang Peng - * @date 2025-10-27 - */ -public class N叉树的层序遍历 { - - public static void main(String[] args) { - Solution s = new Solution(); - Node node3 = new Node(3); - node3.children.add(new Node(5)); - node3.children.add(new Node(6)); - Node root = new Node(1); - root.children.add(node3); - root.children.add(new Node(2)); - root.children.add(new Node(4)); - List> res = s.levelOrder(root); - System.out.printf("res: %s\n", res); - } - - static class Solution { - - public List> levelOrder(Node root) { - List> res = new ArrayList<>(); - LinkedList queue = new LinkedList<>(); - queue.offer(root); - - while (!queue.isEmpty()) { - int size = queue.size(); - LinkedList list = new LinkedList<>(); - for (int i = 0; i < size; i++) { - Node node = queue.poll(); - if (node == null) { - continue; - } - list.add(node.val); - if (!node.children.isEmpty()) { - for (Node child : node.children) { - queue.offer(child); - } - } - } - if (!list.isEmpty()) { - res.add(list); - } - } - return res; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" deleted file mode 100644 index b4ab98a..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/ntree/N\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.dunwu.algorithm.tree.ntree; - -import io.github.dunwu.algorithm.tree.Node; -import org.junit.jupiter.api.Assertions; - -/** - * 559. N叉树的最大深度 - * - * @author Zhang Peng - * @date 2020-03-23 - */ -public class N叉树的最大深度 { - - public static void main(String[] args) { - Solution s = new Solution(); - io.github.dunwu.algorithm.tree.Node node3 = new io.github.dunwu.algorithm.tree.Node(3); - node3.children.add(new io.github.dunwu.algorithm.tree.Node(5)); - node3.children.add(new io.github.dunwu.algorithm.tree.Node(6)); - io.github.dunwu.algorithm.tree.Node root = new io.github.dunwu.algorithm.tree.Node(1); - root.children.add(node3); - root.children.add(new io.github.dunwu.algorithm.tree.Node(2)); - root.children.add(new io.github.dunwu.algorithm.tree.Node(4)); - Assertions.assertEquals(3, s.maxDepth(root)); - } - - static class Solution { - - private int max = 0; - - public int maxDepth(Node root) { - max = 0; - dfs(root); - return max; - } - - public int dfs(Node root) { - if (root == null) { return 0; } - - int depth = 0; - for (int i = 0; i < root.children.size(); i++) { - depth = Math.max(depth, dfs(root.children.get(i))); - } - max = Math.max(max, depth + 1); - return depth + 1; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" deleted file mode 100644 index 7fbb430..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\344\272\214\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.dunwu.algorithm.tree.template; - -import io.github.dunwu.algorithm.tree.TreeNode; - -/** - * 二叉树递归遍历框架 - * - * @author Zhang Peng - * @date 2025-10-23 - */ -public class 二叉树遍历框架 { - - /** - * 二叉树的遍历框架 - */ - public void traverse(TreeNode root) { - // 【校验】 - if (root == null) { return; } - // 【前序】 - System.out.printf("[node -> left]从节点 %s 进入节点 %s\n", root, root.left); - traverse(root.left); - // 【中序】 - System.out.printf("\t[left -> node]从节点 %s 回到节点 %s\n", root.left, root); - System.out.printf("\t[node -> right]从节点 %s 进入节点 %s\n", root, root.right); - traverse(root.right); - // 【后序】 - System.out.printf("\t[right -> node]从节点 %s 回到节点 %s\n", root.right, root); - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" deleted file mode 100644 index a8154e0..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/template/\345\244\232\345\217\211\346\240\221\351\201\215\345\216\206\346\241\206\346\236\266.java" +++ /dev/null @@ -1,97 +0,0 @@ -package io.github.dunwu.algorithm.tree.template; - -import io.github.dunwu.algorithm.tree.Node; -import io.github.dunwu.algorithm.tree.State; - -import java.util.LinkedList; -import java.util.Queue; - -/** - * 多叉树遍历框架 - * - * @author Zhang Peng - * @date 2025-11-03 - */ -public class 多叉树遍历框架 { - - // 多叉树的遍历框架 - void dfs(Node root) { - // base case - if (root == null) { - return; - } - // 前序位置 - System.out.println("visit " + root.val); - for (Node child : root.children) { - dfs(child); - } - // 后序位置 - } - - void bfs(Node root) { - // base case - if (root == null) { - return; - } - Queue q = new LinkedList<>(); - q.offer(root); - while (!q.isEmpty()) { - Node node = q.poll(); - // 访问 cur 节点 - System.out.println(node.val); - - // 把 cur 的所有子节点加入队列 - for (Node child : node.children) { - q.offer(child); - } - } - } - - // 记录遍历步数的写法 - void bfs2(Node root) { - if (root == null) { - return; - } - Queue q = new LinkedList<>(); - q.offer(root); - // 记录当前遍历到的层数(根节点视为第 1 层) - int depth = 1; - - while (!q.isEmpty()) { - int size = q.size(); - for (int i = 0; i < size; i++) { - Node node = q.poll(); - // 访问 cur 节点,同时知道它所在的层数 - System.out.println("depth = " + depth + ", val = " + node.val); - - for (Node child : node.children) { - q.offer(child); - } - } - depth++; - } - } - - // 每个节点自行维护 State 类,记录深度等信息 - void bfs3(Node root) { - if (root == null) { - return; - } - Queue q = new LinkedList<>(); - // 记录当前遍历到的层数(根节点视为第 1 层) - q.offer(new State(root, 1)); - - while (!q.isEmpty()) { - State state = q.poll(); - Node node = state.node; - int depth = state.depth; - // 访问 cur 节点,同时知道它所在的层数 - System.out.println("depth = " + depth + ", val = " + node.val); - - for (Node child : node.children) { - q.offer(new State(child, depth + 1)); - } - } - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/Trie.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/Trie.java deleted file mode 100644 index 0f616fb..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/Trie.java +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.dunwu.algorithm.trie; - -import java.util.concurrent.atomic.AtomicInteger; - -public class Trie { - - private final AtomicInteger wordCount = new AtomicInteger(0); - private final TrieNode root = new TrieNode('/'); // 存储无意义字符 - - // 往 Trie 树中插入一个字符串 - public void insert(char[] text) { - TrieNode p = root; - for (char c : text) { - int index = c - 'a'; - if (p.children[index] == null) { - p.children[index] = new TrieNode(c); - } else { - p.children[index].count++; - } - p = p.children[index]; - } - wordCount.getAndIncrement(); - p.isEnd = true; - } - - // 在 Trie 树中查找一个字符串 - public boolean find(char[] pattern) { - TrieNode p = root; - for (int i = 0; i < pattern.length; ++i) { - int index = pattern[i] - 'a'; - if (p.children[index] == null) { - return false; // 不存在 pattern - } - p = p.children[index]; - } - return p.isEnd; - } - - public String longest() { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 26; i++) { - method(root.children[i], sb); - } - return sb.toString(); - } - - public void method(TrieNode root, StringBuilder sb) { - if (root != null) { - if (root.count == wordCount.get()) { - sb.append(root.data); - if (root.children != null) { - for (int i = 0; i < 26; i++) { - method(root.children[i], sb); - } - } - } - } - } - - public class TrieNode { - - public int count; - public char data; - public boolean isEnd = false; - public TrieNode[] children = new TrieNode[26]; - - public TrieNode(char data) { - this.count = 1; - this.data = data; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242.java" deleted file mode 100644 index f6d2890..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242.java" +++ /dev/null @@ -1,460 +0,0 @@ -package io.github.dunwu.algorithm.trie; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 79. 单词搜索 - * @since 2020-07-04 - */ -public class 单词搜索 { - - public static void main(String[] args) { - char[][] board = { - { 'A', 'B', 'C', 'E' }, - { 'S', 'F', 'C', 'S' }, - { 'A', 'D', 'E', 'E' } - }; - 单词搜索 demo = new 单词搜索(); - // Assertions.assertFalse(demo.exist(board, "ABCB")); - Assertions.assertTrue(demo.exist(board, "SEE")); - Assertions.assertTrue(demo.exist(board, "ABCCED")); - - char[][] board2 = - { { 'p', 'f', 'h', 'n', 'u', 'v', 'u', 'z', 'z', 'p', 'u', 'j', 's', 't', 'p', 'i', 'v', 'o', 's', 'm', 'q', - 'l', 'c', 't', 'y', 'n', 's', 'p', 'u', 't', 'y', 'l', 'y', 'i', 'a', 'u', 'f', 'u', 't', 'f', 'j', 'n', - 'q', 'd', 'j', 'f', 'n', 'e', 'v', 'f', 't', 'o', 't', 'v', 'h', 't', 'i', 'c', 'j', 'e', 'v', 'j', 'r', - 'v', 'r', 'r', 'p', 'x', 'l' }, - { 'k', 'e', 'w', 'z', 'u', 'b', 'i', 'b', 'p', 'p', 'w', 'w', 'i', 'k', 'p', 'd', 'u', 'l', 'n', 'w', - 'u', 's', 'r', 'd', 'j', 'o', 'x', 'b', 'd', 'w', 'o', 'p', 'a', 'l', 'o', 'w', 'o', 'x', 'x', 'd', - 'o', 't', 'c', 'w', 'g', 'r', 'z', 'a', 'e', 'o', 'w', 'y', 'g', 'p', 'e', 's', 'd', 'd', 'v', 'i', - 'z', 'j', 'z', 'b', 'w', 'n', 'x', 'l', 'm' }, - { 'u', 'q', 'a', 'n', 's', 'w', 't', 'm', 'x', 'v', 'q', 'o', 'r', 'r', 'u', 'i', 'x', 'o', 'n', 'a', - 'j', 'v', 'b', 'v', 'u', 'c', 't', 'k', 'z', 'g', 'w', 't', 'x', 'z', 'i', 'r', 'x', 'e', 'd', 'x', - 'z', 'w', 'l', 't', 'p', 'h', 'b', 'm', 'w', 'p', 'm', 'h', 'm', 'n', 'c', 'j', 'p', 'w', 'v', 'q', - 'c', 't', 'j', 'b', 's', 't', 't', 's', 'x' }, - { 'y', 'p', 'x', 'w', 'c', 'q', 'l', 'j', 't', 'x', 'f', 'k', 'l', 'p', 'x', 'a', 'r', 'i', 'r', 'p', - 'd', 'h', 'u', 'w', 's', 'x', 'p', 'm', 'q', 'j', 'j', 'r', 'y', 'i', 'n', 'a', 'a', 'b', 'l', 'u', - 'y', 't', 'e', 'k', 'i', 'd', 'k', 'b', 'l', 'e', 'r', 'o', 'l', 'n', 'n', 'e', 'k', 'e', 'q', 'd', - 'n', 'b', 'u', 'l', 'k', 'j', 'n', 'k', 'k' }, - { 'y', 'g', 'l', 't', 'l', 'x', 'b', 'q', 'h', 'd', 'c', 'l', 'w', 's', 'z', 'j', 'f', 'f', 't', 'j', - 'v', 'w', 'w', 'y', 's', 'j', 'k', 'e', 'y', 'x', 'q', 'x', 'd', 'b', 'q', 'q', 'y', 'u', 'h', 'i', - 'x', 'l', 'v', 'v', 'd', 'u', 'e', 'l', 'b', 'z', 'w', 'w', 'y', 't', 'x', 'q', 'e', 'h', 'w', 'd', - 'e', 'n', 'c', 'k', 'q', 'u', 'a', 'r', 'q' }, - { 'j', 'z', 'n', 'u', 'w', 'i', 'a', 't', 'o', 'n', 'u', 'o', 'j', 't', 'm', 'e', 'q', 'e', 'j', 'z', - 'b', 'o', 'g', 'q', 's', 'q', 'i', 'm', 's', 'z', 'd', 'c', 'y', 's', 'y', 'v', 'd', 'a', 'q', 'r', - 'n', 'k', 'h', 'x', 'd', 't', 'd', 't', 'y', 'o', 'v', 'b', 'c', 'b', 't', 'w', 'r', 'b', 'j', 'l', - 'b', 'o', 'n', 'b', 'i', 'o', 'y', 'n', 'q' }, - { 'o', 'h', 'e', 'z', 'o', 'd', 'c', 'i', 'i', 'y', 'i', 'x', 'v', 'l', 'b', 'w', 'e', 'y', 'p', 'f', - 'j', 'a', 'g', 'x', 'q', 'i', 'h', 'e', 'g', 'v', 'u', 'v', 'c', 'a', 'w', 's', 'f', 'a', 'c', 'o', - 'y', 'k', 'l', 'v', 'v', 'm', 'r', 'b', 'k', 'g', 'h', 't', 'h', 'n', 's', 'x', 'x', 'c', 'd', 'e', - 'x', 'z', 'b', 'b', 'c', 'x', 't', 'h', 'x' }, - { 'w', 'x', 'y', 'i', 'i', 't', 'g', 'x', 'n', 'h', 'j', 't', 'q', 'f', 'c', 'g', 'x', 'b', 'd', 'b', - 'e', 'j', 'y', 'g', 'm', 'b', 'i', 'l', 'x', 'r', 'j', 'v', 'p', 'j', 'f', 'z', 'e', 'l', 'w', 't', - 'v', 'i', 'n', 'l', 'n', 'r', 't', 'm', 't', 'x', 'o', 'z', 'i', 'o', 'f', 'v', 'q', 'n', 'g', 'n', - 'f', 'r', 'k', 'w', 'c', 'p', 'v', 'h', 'd' }, - { 's', 'c', 'y', 'c', 'p', 'l', 'p', 'j', 'h', 'b', 'c', 'e', 'p', 'b', 'm', 'e', 'h', 'h', 'w', 'w', - 'q', 'l', 'd', 'h', 'v', 'z', 'k', 'k', 'v', 't', 'n', 'p', 'v', 'n', 'r', 'n', 'b', 'g', 'w', 'i', - 'j', 'y', 'o', 'z', 'b', 'c', 'f', 'k', 'm', 'b', 'h', 'c', 'm', 'k', 'j', 'j', 'm', 'v', 't', 'h', - 'o', 'j', 'y', 'k', 'y', 'r', 'z', 'b', 'x' }, - { 'v', 'j', 'i', 'v', 'z', 'j', 'y', 'c', 'o', 'j', 'o', 'r', 'q', 'q', 'f', 'c', 'b', 'o', 'o', 'x', - 'i', 'x', 'l', 't', 'v', 'x', 'r', 'o', 'w', 't', 'n', 't', 'e', 'w', 'q', 'e', 'f', 'p', 'g', 'w', - 'y', 'w', 'n', 'q', 'o', 't', 'u', 'p', 'h', 'j', 'm', 'r', 'i', 'a', 'k', 'g', 'z', 'c', 'u', 'y', - 'x', 'i', 't', 'b', 'e', 'k', 'f', 'l', 'z' }, - { 'n', 'h', 'z', 'j', 'v', 'p', 'z', 'q', 'l', 'p', 'x', 'w', 'd', 'p', 'f', 'f', 'b', 'n', 'f', 'd', - 'h', 'f', 'a', 'r', 'y', 'c', 'x', 'i', 'j', 'j', 'j', 'z', 'q', 'i', 'k', 'n', 'z', 'k', 'd', 'l', - 'z', 'd', 'h', 'e', 's', 'o', 'k', 't', 'b', 'p', 'z', 'l', 'u', 'b', 'c', 'u', 'f', 'a', 'd', 'r', - 'l', 'o', 'q', 'b', 'z', 'a', 'r', 'a', 'k' }, - { 'u', 'n', 'l', 'x', 'x', 'q', 'r', 'l', 'a', 'n', 'p', 'r', 'o', 'a', 'n', 'p', 'e', 'h', 'v', 'e', - 'm', 'm', 'p', 'b', 'e', 't', 'c', 'e', 'k', 'c', 'r', 'g', 'q', 'e', 'g', 'n', 'w', 'x', 'a', 'y', - 'm', 'p', 'p', 'a', 'r', 'c', 'q', 'w', 'm', 'n', 'a', 'y', 'b', 's', 'b', 'f', 'n', 'd', 'l', 'x', - 'g', 'c', 'f', 'w', 'j', 'l', 'l', 'f', 'j' }, - { 'l', 'e', 'v', 'd', 'v', 'w', 'u', 'y', 'o', 'q', 'm', 'b', 't', 'k', 'c', 'l', 'm', 'j', 'a', 'r', - 'u', 'x', 'x', 'x', 'e', 'v', 'i', 'q', 'i', 'n', 'b', 'u', 't', 'w', 'x', 'p', 'u', 'r', 'p', 'k', - 'k', 'd', 'n', 'd', 'n', 'r', 'q', 'b', 'a', 'q', 't', 'v', 'p', 's', 'u', 't', 'q', 'c', 'j', 'y', - 'r', 'k', 's', 'n', 'j', 'r', 'e', 'f', 'l' }, - { 'v', 's', 'v', 'y', 'f', 'a', 'n', 'x', 's', 'p', 'x', 'i', 'k', 'u', 'z', 'e', 'o', 'u', 'u', 's', - 'g', 't', 'm', 'q', 'n', 'z', 'b', 'f', 'f', 'j', 'q', 'a', 'b', 'n', 'y', 'g', 'p', 'n', 'f', 'h', - 'c', 'f', 'r', 'o', 'z', 'q', 't', 'o', 'k', 'n', 'i', 'q', 'i', 'u', 'j', 'w', 'v', 'm', 'b', 'a', - 'v', 't', 'a', 'y', 'i', 'a', 'h', 'x', 'o' }, - { 'm', 'e', 's', 'r', 'v', 'j', 'r', 'n', 'c', 'h', 'x', 'r', 'r', 'q', 'a', 'm', 'b', 'w', 'j', 'n', - 'z', 'k', 'l', 's', 'm', 'j', 'c', 'p', 's', 'z', 'f', 'f', 'f', 'x', 'y', 'c', 'g', 'r', 'r', 'k', - 'a', 'q', 'e', 's', 'g', 'e', 'g', 'h', 'c', 'p', 'v', 'b', 'b', 'i', 'v', 'q', 'r', 'x', 'f', 'm', - 'y', 'k', 'r', 'f', 'j', 'r', 'h', 's', 'j' }, - { 'a', 'e', 'j', 'q', 'i', 'd', 'x', 'm', 'j', 'g', 'q', 'b', 'b', 'r', 'e', 'l', 'o', 'u', 'f', 'n', - 'z', 'r', 'l', 'l', 'i', 's', 'x', 'b', 'b', 'p', 'k', 'b', 't', 'w', 's', 'c', 'b', 'p', 'q', 'n', - 'v', 'h', 'o', 'z', 'a', 's', 'k', 'p', 'n', 'p', 'c', 'o', 'i', 'q', 'c', 'q', 'i', 'z', 's', 'k', - 'o', 'e', 'l', 'j', 'c', 'f', 'l', 'e', 'u' }, - { 'c', 'r', 's', 'l', 'h', 't', 'l', 'b', 'f', 'a', 'q', 'x', 'f', 'f', 'f', 'v', 'h', 'y', 'f', 'g', - 's', 'r', 'w', 'w', 'f', 'f', 'b', 'k', 't', 'f', 'h', 'x', 'y', 'b', 'i', 'f', 'u', 't', 'g', 'b', - 'w', 'x', 'y', 'b', 'e', 'e', 'y', 'l', 'e', 'f', 't', 'w', 'x', 'r', 'u', 'c', 'y', 'v', 'o', 'r', - 'c', 'v', 'o', 'a', 'y', 'y', 'f', 's', 's' }, - { 'o', 'u', 'q', 'l', 'u', 't', 'p', 'a', 'r', 'c', 'e', 'w', 'x', 'c', 'v', 'q', 'x', 'x', 'o', 'u', - 'o', 'g', 'x', 'j', 'w', 'x', 'i', 'v', 'f', 'c', 'p', 't', 'y', 'f', 'g', 'v', 'y', 'x', 'v', 'r', - 'b', 'c', 'p', 'y', 'e', 'l', 'o', 'b', 'k', 'e', 'y', 'y', 'k', 'v', 'k', 'j', 'u', 'u', 'e', 'z', - 'y', 't', 'u', 'x', 'a', 'a', 'u', 'a', 'x' }, - { 'p', 't', 'y', 't', 'i', 'y', 'y', 't', 'o', 'b', 'e', 't', 'z', 'e', 'f', 'u', 'o', 'o', 'p', 'k', - 's', 'q', 'j', 'n', 'l', 'i', 'p', 'n', 'c', 'p', 'n', 't', 'i', 'l', 'n', 't', 'm', 'l', 'o', 'c', - 'm', 'u', 'v', 'o', 'z', 'd', 'i', 'p', 'r', 'z', 'a', 'm', 's', 'j', 'b', 'f', 'r', 'r', 's', 't', - 'i', 'f', 'm', 't', 't', 'b', 'm', 'f', 'm' }, - { 'a', 'h', 'b', 'x', 'f', 'p', 'w', 'i', 'z', 'l', 'b', 'b', 'l', 'p', 't', 'w', 'r', 'y', 'n', 'k', - 'q', 'i', 's', 'y', 'x', 'n', 'r', 'y', 'b', 'y', 'n', 'e', 'h', 'o', 'b', 'o', 'd', 'x', 'y', 'e', - 'k', 'a', 'f', 'y', 'p', 'y', 'u', 'i', 'y', 'k', 's', 'p', 's', 'n', 'p', 'r', 'a', 'g', 'q', 'e', - 'g', 'd', 'i', 'n', 't', 'l', 'e', 'y', 'i' }, - { 'c', 'c', 'u', 'c', 'i', 's', 'u', 'i', 'n', 'c', 'h', 'x', 'v', 'y', 'r', 'i', 'n', 'j', 'k', 't', - 'z', 'o', 'b', 'e', 'y', 'q', 'x', 'j', 'u', 'v', 't', 'x', 'x', 'o', 'b', 'h', 'g', 'v', 'q', 'v', - 'y', 'x', 'u', 'v', 'x', 'm', 'f', 'k', 'v', 'p', 'f', 'w', 'g', 'g', 'a', 'e', 'w', 'z', 'o', 't', - 'u', 'h', 'q', 't', 'x', 'r', 'b', 'e', 'n' }, - { 't', 'b', 'n', 's', 'w', 'k', 'p', 'i', 'p', 'z', 'f', 'g', 'g', 'b', 'm', 'm', 'd', 't', 'k', 'c', - 'h', 'd', 'w', 'q', 't', 'r', 'q', 'n', 'u', 'w', 'c', 'n', 'x', 'p', 'h', 't', 'z', 'w', 'd', 'q', - 'x', 'i', 'w', 'd', 'j', 'j', 'r', 'm', 'c', 'c', 'o', 'l', 'f', 'm', 'd', 'b', 'g', 't', 'q', 'a', - 'p', 's', 'q', 'p', 'j', 'x', 'i', 'k', 'w' }, - { 'm', 'a', 't', 'u', 'w', 'z', 'g', 'h', 'q', 's', 'l', 'u', 'j', 'y', 'c', 'v', 'e', 'f', 'b', 'z', - 'v', 'e', 'r', 'n', 'u', 'g', 'y', 'r', 'q', 'i', 'n', 'e', 'k', 'j', 'z', 'i', 'i', 'h', 's', 'a', - 'z', 'd', 'v', 'i', 'e', 'x', 'g', 'i', 'c', 'j', 'j', 'z', 'n', 'a', 'o', 'h', 'i', 'm', 'z', 'z', - 'w', 'o', 'd', 'g', 'x', 'e', 'q', 'h', 'l' }, - { 'i', 'k', 'n', 'o', 'f', 'v', 's', 'e', 'd', 'c', 'i', 'n', 'n', 'j', 'a', 'o', 'x', 'k', 'y', 'j', - 'l', 'x', 'f', 'b', 'd', 'n', 'b', 'j', 'd', 'i', 'x', 'o', 's', 'k', 'c', 'z', 'h', 'w', 'f', 'l', - 'a', 'p', 'a', 'n', 'y', 'c', 'd', 'v', 'm', 'c', 'g', 'z', 'b', 'l', 'b', 'g', 'a', 'c', 'q', 'g', - 'k', 'n', 'u', 'f', 'x', 'y', 'g', 'g', 'u' }, - { 'o', 'r', 'u', 'd', 'r', 'j', 'c', 'u', 'n', 'z', 'i', 'r', 'g', 'i', 'u', 't', 'j', 'b', 'u', 'l', - 't', 'c', 'x', 'g', 'w', 'e', 'f', 'u', 'l', 'l', 'q', 'z', 'f', 'm', 'e', 'w', 'v', 'g', 's', 'k', - 'g', 'b', 'd', 'o', 'j', 'y', 'h', 'u', 'z', 'd', 'f', 's', 'f', 'e', 'a', 'b', 'j', 'f', 'x', 'u', - 's', 'p', 'v', 'x', 'b', 'z', 'w', 'z', 'i' }, - { 'o', 'l', 'q', 'r', 'p', 'e', 'c', 'n', 'n', 'w', 'o', 'r', 'd', 'g', 'w', 'i', 'i', 'a', 'r', 'p', - 'z', 'n', 'h', 'p', 'k', 'h', 's', 'l', 'd', 't', 'v', 't', 'f', 'n', 'l', 'u', 'r', 'n', 'j', 'h', - 'm', 'x', 'y', 'p', 'f', 'u', 'z', 'n', 'w', 's', 'c', 'w', 'h', 'l', 'n', 'r', 's', 'h', 'f', 'v', - 'b', 'a', 'p', 'i', 'o', 'c', 'c', 'h', 'p' }, - { 'n', 'o', 'd', 'm', 'o', 'v', 'r', 'l', 'u', 'g', 'h', 'n', 'i', 'f', 'u', 't', 's', 'o', 'o', 'a', - 't', 'j', 'd', 'v', 'a', 'l', 'l', 'c', 'p', 't', 'u', 'c', 'j', 'z', 'o', 'y', 'u', 'h', 'j', 'p', - 'n', 's', 'e', 'x', 'y', 'y', 's', 's', 'o', 'g', 'u', 'j', 's', 'x', 'f', 'u', 'i', 'q', 'x', 'x', - 'l', 't', 'b', 'x', 's', 'r', 'x', 'n', 'y' }, - { 'i', 'e', 'n', 'a', 'i', 'm', 'a', 'i', 'h', 't', 'x', 'n', 'n', 'g', 'h', 'l', 'l', 'c', 'v', 'e', - 'b', 'v', 'r', 'w', 'w', 'o', 'o', 'q', 'l', 'd', 'q', 't', 'j', 'e', 'w', 'r', 's', 'w', 'a', 'z', - 'r', 'z', 'p', 'f', 'f', 'w', 's', 't', 'a', 'p', 'x', 'b', 'k', 'q', 'x', 'j', 'f', 'o', 'z', 's', - 't', 'p', 'o', 'd', 'v', 'k', 'w', 'o', 'g' }, - { 'y', 'p', 'a', 'x', 'e', 'f', 'd', 'd', 'z', 'y', 'd', 'o', 'x', 'h', 'b', 'n', 'g', 'k', 'u', 'w', - 'j', 'n', 'q', 'y', 'b', 'v', 'w', 'l', 'r', 'k', 't', 's', 'b', 't', 'p', 'g', 'a', 'u', 'l', 'b', - 's', 'q', 'q', 'p', 'x', 'r', 'd', 'e', 'd', 'x', 'a', 'm', 'm', 's', 'm', 'n', 'n', 'i', 'a', 'h', - 'u', 'w', 'b', 'w', 'p', 'q', 'e', 's', 'l' }, - { 'r', 't', 'd', 'h', 'l', 'v', 'f', 'e', 'a', 'l', 'h', 'z', 'l', 'v', 'm', 'g', 'i', 'b', 'v', 's', - 'c', 'e', 'n', 'y', 'f', 'l', 'p', 'w', 'p', 'h', 'j', 'g', 'd', 'o', 'n', 'o', 'j', 'u', 'v', 'l', - 'f', 'c', 'l', 't', 'y', 'x', 'z', 'i', 'y', 'u', 'a', 'c', 'z', 'p', 'a', 'g', 'a', 'q', 'c', 'r', - 'z', 'l', 'z', 'c', 'c', 'p', 't', 'l', 'j' }, - { 'o', 'x', 'p', 's', 'k', 'k', 's', 'h', 'j', 'a', 'h', 'f', 'b', 'k', 'g', 's', 'm', 'n', 't', 'c', - 'r', 'k', 'c', 'f', 'k', 'g', 'h', 'z', 'z', 'u', 'k', 'n', 't', 'z', 'g', 'd', 'l', 'y', 'm', 'w', - 'z', 'w', 'c', 'c', 'i', 'k', 'w', 'u', 'z', 'p', 'x', 'r', 'a', 'b', 'w', 'm', 'h', 'f', 'l', 'h', - 'z', 'x', 'w', 'v', 'x', 'c', 'y', 'k', 'd' }, - { 'n', 'h', 'e', 'j', 'j', 'i', 'r', 'v', 'e', 'l', 'v', 'u', 'k', 'm', 'w', 'n', 'k', 'i', 'v', 'r', - 'v', 'e', 's', 's', 'a', 'n', 'r', 'f', 'o', 'c', 'i', 'b', 'j', 'm', 'k', 'u', 'u', 'd', 'p', 'y', - 'o', 'm', 's', 'b', 'y', 'o', 'o', 'k', 'y', 'l', 'd', 't', 'r', 'w', 'm', 'u', 'j', 'f', 'z', 'x', - 'h', 'j', 'y', 's', 'v', 'k', 'o', 'p', 'n' }, - { 'e', 'p', 'e', 's', 'k', 'f', 't', 'a', 'v', 'd', 'z', 'j', 'h', 's', 'a', 'f', 'g', 'w', 'o', 'm', - 'v', 'o', 'v', 'e', 'o', 'o', 'b', 'z', 'e', 's', 'm', 'i', 'i', 's', 'd', 's', 'x', 'w', 'u', 'v', - 'z', 't', 'e', 'i', 'o', 'g', 'n', 'u', 'd', 'e', 'i', 'y', 's', 'g', 'f', 'g', 'w', 'g', 'h', 'a', - 'b', 'w', 'l', 'j', 'o', 'o', 'd', 'm', 'k' }, - { 'z', 'h', 'j', 't', 'n', 'u', 'h', 't', 'j', 'd', 'w', 'n', 'o', 'x', 'h', 'u', 'c', 'q', 'q', 'k', - 'x', 'q', 'n', 't', 'b', 'w', 'k', 'p', 'b', 'w', 'z', 'b', 'f', 'l', 'w', 'u', 'h', 'f', 'n', 'q', - 'i', 'k', 'g', 'w', 'j', 'p', 'q', 'n', 'f', 'g', 'x', 'f', 'z', 'l', 'a', 'a', 'j', 'k', 's', 'n', - 'i', 't', 'q', 'p', 'e', 'o', 'j', 'n', 't' }, - { 'x', 'g', 'b', 'j', 'm', 'a', 'u', 'b', 'q', 'h', 'j', 'z', 'e', 'q', 'y', 'r', 'q', 'a', 'd', 'b', - 'u', 's', 'l', 'o', 'i', 'b', 'u', 'w', 'k', 'i', 'r', 'j', 'o', 's', 'u', 'c', 's', 'o', 'f', 'l', - 'v', 'o', 'k', 'c', 'e', 'k', 't', 'x', 'm', 'y', 'a', 'h', 'q', 'l', 'v', 'a', 'm', 'r', 'y', 'z', - 'b', 'p', 'k', 'p', 'i', 'f', 't', 'c', 'v' }, - { 'z', 'n', 'r', 'p', 'z', 'v', 'w', 'j', 'q', 't', 'y', 'p', 'v', 'f', 'h', 'g', 'c', 'i', 'v', 't', - 'g', 'w', 'x', 'w', 'g', 'o', 'g', 'n', 'i', 'i', 'j', 'j', 'w', 'c', 'y', 'x', 'x', 'w', 'h', 'p', - 'r', 'h', 'e', 'm', 'm', 'm', 't', 'q', 'u', 'q', 'l', 'c', 'm', 'i', 'y', 's', 'x', 'e', 'i', 'f', - 'p', 'r', 'q', 'n', 'v', 'o', 'k', 'u', 'n' }, - { 'r', 'j', 'e', 'y', 'o', 'r', 'm', 'c', 'm', 'e', 'y', 'e', 'q', 'a', 'q', 'a', 'b', 'k', 'x', 'h', - 's', 'e', 'w', 'l', 'u', 'j', 'g', 'l', 'u', 'a', 'y', 'n', 'k', 'e', 'o', 'a', 'v', 'c', 'e', 'j', - 'h', 'c', 'n', 'z', 'e', 'd', 'z', 'h', 'q', 'x', 'p', 'i', 'd', 'n', 'w', 'a', 'z', 'c', 'l', 't', - 'f', 'l', 'i', 'r', 'p', 'y', 'r', 'n', 'b' }, - { 'x', 'w', 'k', 'z', 'm', 'j', 'f', 'r', 'k', 'n', 'h', 'j', 'e', 's', 'n', 'r', 'o', 'p', 'q', 'q', - 'a', 'l', 'v', 'n', 'u', 'o', 'e', 'u', 'f', 'r', 'x', 'c', 'q', 'h', 'd', 'c', 's', 'l', 't', 'd', - 'y', 'b', 'm', 'c', 't', 'b', 'v', 'j', 'q', 'm', 'z', 's', 'x', 'x', 'h', 't', 'l', 'm', 'q', 't', - 'd', 'n', 'x', 'v', 'x', 'd', 'x', 'r', 'o' }, - { 't', 'u', 'o', 'w', 'j', 's', 'r', 'm', 'n', 'a', 'f', 'z', 'z', 'x', 'z', 'y', 'h', 'u', 'm', 't', - 'm', 'h', 'y', 'a', 'g', 'u', 'z', 'l', 't', 'q', 'z', 'm', 'n', 'p', 'i', 'w', 'h', 'z', 'k', 'v', - 'z', 'p', 'w', 'b', 'p', 'x', 'b', 'w', 'u', 'n', 'r', 'g', 'w', 'p', 'i', 'd', 'j', 'h', 'o', 'd', - 'y', 'q', 'r', 'l', 'f', 'a', 'j', 'p', 'z' }, - { 'v', 'k', 'b', 'l', 'i', 'e', 'c', 'g', 'f', 'a', 'a', 'v', 'r', 'i', 'r', 'i', 'r', 'w', 'u', 'y', - 'n', 'z', 'y', 'f', 'q', 'j', 'm', 'q', 'u', 'b', 's', 'q', 'l', 'v', 'd', 'w', 'z', 'h', 'c', 'g', - 'j', 'e', 'b', 'c', 'm', 'v', 'k', 'd', 't', 'g', 'e', 'g', 'f', 'c', 'l', 'y', 'o', 'a', 'q', 'i', - 'b', 'k', 'a', 'p', 'f', 'f', 'l', 'g', 'o' }, - { 'n', 'n', 'x', 't', 'o', 'b', 'f', 'l', 'm', 'j', 'f', 'u', 'n', 'l', 'a', 'r', 'z', 'y', 'f', 'z', - 'q', 'q', 'c', 'b', 's', 'r', 'g', 'a', 'c', 'n', 'o', 'r', 'a', 'o', 'k', 'q', 'p', 'q', 'c', 'd', - 'b', 'h', 'y', 'q', 'u', 'a', 'h', 'v', 'a', 'n', 'w', 'q', 'f', 'z', 'r', 'x', 's', 'a', 'x', 'v', - 'n', 'o', 'o', 'p', 'c', 'z', 'h', 'r', 'r' }, - { 'l', 'x', 's', 'u', 'v', 'k', 'p', 'x', 'r', 'm', 'x', 'g', 'l', 'p', 'n', 'k', 'h', 'l', 'c', 'h', - 'k', 'z', 'w', 'y', 'o', 'n', 'a', 'n', 'u', 'u', 'g', 'g', 'r', 'a', 'a', 'o', 'k', 'r', 'n', 'd', - 'g', 'k', 'k', 'r', 'z', 'x', 'b', 'i', 'k', 'f', 'r', 'v', 'f', 'n', 'v', 'v', 'a', 'y', 'k', 'x', - 'u', 'q', 'd', 'n', 'q', 'f', 'b', 'a', 'z' }, - { 'o', 'd', 'f', 'a', 'p', 'y', 'b', 'p', 'b', 'm', 'b', 'g', 'd', 'y', 'n', 'r', 'u', 'k', 't', 's', - 'u', 'q', 'm', 'k', 'v', 'z', 'c', 'd', 'c', 'e', 'c', 's', 'k', 'j', 'u', 'b', 'h', 'x', 'q', 'k', - 'j', 'u', 's', 'n', 's', 'i', 'g', 'm', 's', 'z', 'g', 'n', 'q', 's', 'z', 'n', 't', 'e', 'q', 'x', - 'i', 's', 'p', 's', 'd', 'l', 'u', 'm', 'j' }, - { 'm', 'w', 's', 'g', 'p', 'h', 'z', 'x', 'n', 'n', 'r', 'p', 'u', 'g', 'f', 'o', 'g', 's', 'i', 'k', - 'j', 'h', 'u', 'd', 'z', 'n', 'h', 'k', 'j', 'v', 't', 'v', 's', 'o', 'c', 'j', 'v', 'd', 'g', 'l', - 'q', 'z', 'a', 'k', 'g', 'h', 'z', 'm', 'z', 'j', 'y', 'k', 'q', 's', 'q', 'r', 'h', 'z', 'c', 'q', - 'u', 'x', 'm', 'm', 'l', 'q', 'v', 'j', 't' }, - { 'd', 'u', 'j', 'd', 'u', 'w', 'j', 'b', 'v', 'x', 'c', 'g', 'x', 'p', 'y', 'r', 'f', 'q', 'z', 'g', - 's', 'p', 'a', 'r', 'd', 'p', 'd', 't', 'k', 'o', 'o', 'q', 'i', 'y', 't', 'e', 'u', 'e', 'h', 'r', - 'd', 'l', 'z', 'a', 'a', 'x', 'r', 'h', 'n', 'q', 'n', 'h', 'i', 'q', 'b', 'n', 'f', 'g', 'j', 'r', - 'u', 'x', 'h', 'e', 'x', 'c', 'i', 't', 'i' }, - { 'r', 'm', 'l', 'c', 'l', 'l', 'f', 'j', 'f', 'm', 'y', 'x', 'c', 'i', 'h', 'u', 'j', 'v', 'z', 'p', - 'e', 'q', 'j', 'b', 'a', 'n', 'b', 'c', 'x', 'u', 'l', 'o', 'j', 'y', 's', 'u', 'm', 'x', 'f', 'r', - 'm', 'e', 'o', 'q', 'm', 'w', 'k', 'v', 't', 'j', 'm', 'x', 'b', 'v', 'a', 'b', 'k', 'd', 'g', 'j', - 'a', 't', 'z', 'j', 'r', 'r', 'd', 'd', 'p' }, - { 'j', 'w', 'b', 'n', 'n', 'r', 'b', 'l', 'b', 'y', 'e', 'm', 'k', 'b', 'p', 'h', 'd', 't', 't', 'h', - 'z', 'c', 'h', 'u', 'b', 'q', 'n', 's', 'v', 'r', 'j', 'e', 'p', 'k', 't', 'c', 'd', 'w', 'n', 'g', - 'w', 'r', 'u', 'i', 'u', 'k', 'p', 'a', 'd', 'k', 'h', 'e', 'o', 'q', 'y', 'p', 'i', 'l', 'k', 'd', - 'e', 't', 'k', 'u', 'g', 'd', 'y', 'l', 'c' }, - { 'm', 'u', 'y', 'f', 'o', 'h', 'c', 'y', 'y', 'c', 'b', 'j', 'l', 'h', 'x', 'b', 'f', 'p', 'j', 't', - 'b', 'm', 'x', 'u', 'y', 't', 'c', 'c', 's', 'q', 'g', 'g', 'k', 'e', 'n', 'y', 'n', 'p', 'z', 'm', - 't', 'a', 'x', 'e', 'i', 'u', 'f', 'p', 'l', 'q', 'i', 'm', 'f', 'g', 'j', 'd', 'b', 'n', 'h', 't', - 'd', 'n', 'b', 'p', 'u', 'p', 'o', 'h', 'g' }, - { 'n', 'v', 'a', 'p', 's', 'e', 'z', 'p', 'm', 'r', 'a', 'e', 'z', 'n', 'j', 'h', 'y', 'p', 'j', 'l', - 'w', 'e', 'r', 'm', 'i', 'g', 'g', 'z', 'w', 'p', 'f', 'l', 'l', 'h', 'b', 'd', 'm', 'c', 's', 'a', - 't', 'v', 'e', 'v', 'k', 'q', 'c', 'i', 'f', 'n', 'v', 'd', 'u', 'm', 'p', 'c', 'v', 'x', 'b', 'r', - 'n', 'i', 'f', 'y', 'q', 'g', 'd', 'e', 'k' }, - { 'y', 'g', 'e', 't', 'm', 'z', 'f', 'c', 'd', 'n', 'j', 'r', 'k', 'n', 'n', 'z', 'c', 'p', 'w', 'c', - 's', 'n', 'p', 'a', 'u', 'p', 's', 'c', 's', 'w', 'n', 's', 'e', 't', 'l', 'r', 'u', 'q', 't', 'x', - 'f', 'd', 'q', 's', 's', 'd', 'r', 'w', 'u', 'n', 'y', 'm', 'c', 'p', 'p', 'x', 'e', 'h', 'z', 'z', - 'g', 'o', 'r', 'k', 'h', 'f', 'b', 'b', 'v' }, - { 'x', 'b', 'd', 'a', 'r', 'x', 'u', 'v', 'o', 'q', 'p', 'd', 'r', 'e', 'h', 'g', 't', 'g', 'l', 'a', - 'i', 'm', 'i', 'w', 'd', 't', 'e', 'i', 'u', 'h', 'g', 'r', 'i', 'l', 't', 'a', 'i', 'p', 'x', 'y', - 'g', 'o', 'd', 'z', 'u', 'k', 'f', 'n', 't', 's', 'q', 'b', 'e', 'y', 'x', 'k', 't', 'd', 's', 'q', - 'n', 'a', 'h', 'v', 'l', 'd', 'x', 't', 's' }, - { 'w', 't', 'a', 'l', 'w', 'z', 'h', 'j', 'h', 'v', 'c', 'z', 'n', 'd', 'g', 'n', 'c', 'q', 'j', 'g', - 'i', 'z', 'v', 'j', 'i', 'q', 'w', 'l', 'o', 's', 'g', 'm', 'l', 'i', 'x', 'k', 'k', 'h', 't', 'r', - 'e', 'v', 's', 'r', 'a', 'y', 'g', 'c', 'o', 'p', 'k', 'z', 'q', 'f', 'k', 'z', 'y', 'i', 'm', 'm', - 'a', 's', 'y', 'm', 'd', 'y', 'w', 'n', 'h' }, - { 'r', 'e', 'l', 'm', 'w', 'e', 'o', 'x', 'k', 'q', 'n', 'c', 'd', 'm', 's', 'k', 'y', 't', 'i', 'h', - 'g', 'w', 'h', 'a', 'x', 'v', 'd', 'x', 't', 'q', 'e', 'k', 'w', 'p', 'y', 'v', 'v', 'o', 's', 'f', - 'h', 'f', 'j', 'k', 'u', 'e', 'u', 'u', 'x', 'f', 'b', 'd', 'b', 'l', 'e', 'a', 'i', 'j', 'x', 'e', - 'a', 'd', 'q', 'y', 'u', 'p', 't', 'p', 'd' }, - { 'n', 'v', 'm', 'v', 'g', 'w', 'p', 'k', 't', 'l', 'k', 'a', 'p', 'n', 'b', 'c', 't', 'e', 'k', 'd', - 'b', 'o', 'f', 'h', 'f', 'd', 'b', 'w', 'z', 'r', 'b', 'm', 'o', 'o', 'h', 'u', 'm', 'y', 'h', 'h', - 'k', 'r', 'h', 'z', 'g', 'l', 'd', 'a', 'p', 'n', 'f', 's', 'e', 'k', 'z', 'l', 'p', 'b', 'j', 'o', - 'u', 'm', 'd', 'i', 'c', 'k', 'e', 'p', 'l' }, - { 'l', 'w', 'x', 'e', 'e', 'y', 'l', 'r', 'b', 'n', 'g', 'q', 's', 'a', 'u', 'c', 'a', 'h', 't', 'd', - 'q', 'i', 'x', 'd', 'l', 'h', 'f', 'x', 'l', 'w', 'k', 'x', 'v', 'h', 'b', 'b', 'f', 'o', 's', 'i', - 'b', 'a', 'z', 't', 'a', 'v', 'x', 'a', 'd', 'r', 'f', 'v', 'b', 'e', 'y', 'm', 'l', 'g', 'l', 'x', - 'e', 'w', 'u', 'z', 'f', 'x', 'c', 'n', 'm' }, - { 'u', 'v', 'p', 'u', 'w', 'j', 'x', 's', 'i', 'x', 'v', 'z', 'f', 'q', 'a', 'j', 'r', 'o', 'v', 'z', - 'c', 's', 'f', 'y', 'o', 'h', 'f', 'n', 'j', 's', 'b', 'g', 'q', 'r', 'c', 'm', 'a', 'z', 'e', 'i', - 'x', 'b', 'k', 'e', 's', 'm', 'n', 'l', 'd', 'i', 'm', 'f', 'c', 'r', 'f', 's', 'y', 'k', 'g', 'i', - 'f', 'h', 'o', 'v', 'y', 's', 'h', 'a', 's' }, - { 'm', 'l', 'r', 'p', 'v', 'v', 'j', 'j', 'i', 'u', 'm', 't', 'i', 'r', 'x', 'a', 'y', 'q', 'a', 'j', - 'w', 'i', 'o', 'f', 'y', 'l', 'e', 'r', 's', 'g', 'j', 'g', 'r', 'a', 'w', 'o', 'x', 'f', 'y', 'f', - 'c', 'k', 'a', 'k', 'e', 'y', 'm', 'c', 'q', 'n', 'n', 'o', 'x', 'd', 't', 'w', 'o', 'z', 'p', 'j', - 'g', 'a', 'p', 'x', 'c', 'n', 'm', 'z', 't' }, - { 'm', 'g', 'x', 'w', 'j', 'h', 'c', 'j', 'u', 'f', 'z', 'j', 's', 'n', 'g', 'y', 'i', 'c', 'm', 'i', - 't', 'v', 'q', 'v', 'n', 'n', 'z', 'a', 'b', 'a', 'v', 'n', 'j', 's', 'm', 's', 'c', 'o', 'b', 'y', - 't', 'c', 'h', 'o', 'p', 'n', 'o', 'x', 's', 'c', 'h', 'n', 'y', 'x', 'j', 'n', 'n', 'k', 'n', 'q', - 'l', 'l', 'e', 'u', 'd', 's', 'm', 'h', 'g' }, - { 'p', 'f', 'c', 'r', 'o', 's', 'i', 'c', 'g', 'h', 'w', 'i', 'p', 'j', 'i', 'o', 'u', 'v', 'b', 'f', - 'l', 'u', 'q', 'w', 'y', 'k', 'b', 's', 'y', 'l', 'y', 'n', 's', 'a', 'g', 'h', 'u', 'o', 'l', 'a', - 'v', 'h', 'l', 'm', 'q', 't', 'b', 'n', 'r', 'e', 's', 'e', 'y', 'i', 'c', 'y', 'u', 'f', 'q', 'u', - 'q', 'r', 'j', 'j', 't', 'p', 's', 'o', 'f' }, - { 'd', 'o', 'a', 'k', 'b', 'p', 'c', 'v', 'q', 'p', 'o', 'w', 'j', 'u', 'x', 't', 'w', 'v', 'p', 'b', - 'o', 'j', 'u', 'f', 'u', 'd', 'y', 'j', 'v', 'm', 'q', 'a', 'd', 't', 'k', 'e', 'i', 'o', 'b', 'a', - 'g', 'r', 'w', 'p', 'l', 't', 'l', 'h', 'r', 'a', 'l', 'h', 'k', 'f', 'm', 'g', 'k', 'm', 'q', 'h', - 'z', 'i', 'h', 'e', 'b', 't', 'k', 'j', 'j' }, - { 'o', 'j', 'r', 'f', 'i', 'h', 't', 'd', 'u', 'a', 'w', 'u', 'n', 'd', 'g', 'u', 'p', 'n', 'e', 'e', - 'f', 'n', 'd', 'n', 'w', 'j', 'p', 'p', 't', 'a', 'b', 'h', 'm', 's', 'p', 'u', 'b', 'i', 'z', 'v', - 'k', 'w', 's', 'y', 'b', 'y', 's', 't', 'n', 'z', 'x', 's', 'o', 'c', 'i', 'l', 'l', 'z', 'c', 'e', - 'z', 'd', 'o', 'n', 'w', 'd', 'j', 'z', 'l' }, - { 'j', 'v', 'v', 'h', 'n', 'v', 'k', 'n', 'q', 'd', 'b', 'p', 'a', 'v', 'd', 'e', 'f', 'o', 'p', 'g', - 'r', 'w', 'i', 'w', 'm', 'v', 's', 'p', 'f', 's', 'c', 'q', 'p', 'z', 'z', 'e', 'v', 'j', 'r', 'l', - 'n', 'u', 'c', 'p', 's', 'f', 'u', 'x', 'w', 'j', 'e', 'p', 'h', 'm', 'l', 't', 'j', 'g', 'k', 'o', - 'a', 'm', 'g', 'p', 'm', 'f', 't', 'j', 'p' }, - { 'm', 'u', 'c', 'h', 'w', 't', 'z', 'd', 'n', 'y', 'b', 'z', 'e', 'q', 'g', 's', 'e', 'c', 'c', 'k', - 'm', 's', 'k', 'z', 'z', 'b', 'n', 'e', 'u', 'w', 'v', 'g', 's', 'z', 'p', 'o', 't', 'o', 't', 'i', - 'p', 'v', 'h', 't', 'n', 'q', 'o', 'r', 's', 'q', 'd', 'e', 'k', 'p', 'd', 'l', 'q', 's', 'q', 'k', - 'o', 'n', 't', 'g', 'n', 'i', 'w', 'g', 'z' }, - { 's', 'q', 'o', 'n', 'y', 'j', 'c', 'o', 'z', 'w', 'i', 'p', 'z', 'm', 'c', 'p', 's', 'n', 'h', 'k', - 'f', 's', 'z', 't', 'n', 'h', 'i', 'v', 'e', 'q', 'w', 'w', 'g', 'm', 'l', 'e', 'y', 'p', 'u', 'x', - 'l', 'e', 'p', 'n', 'r', 'r', 'e', 'l', 'e', 'n', 'v', 'm', 'f', 'w', 'f', 'u', 'g', 'n', 's', 'k', - 'd', 'o', 'i', 'j', 'b', 'v', 'q', 'b', 'm' }, - { 'm', 'y', 'a', 'r', 'n', 'p', 'k', 'g', 't', 'v', 'n', 'g', 's', 'z', 'o', 'p', 'g', 'k', 'v', 't', - 'c', 'h', 'y', 'r', 'r', 'j', 'u', 'o', 'b', 'x', 'a', 'o', 'v', 'a', 'h', 'l', 'p', 'r', 'r', 'k', - 'o', 'e', 't', 'g', 'f', 'j', 'x', 'l', 't', 'u', 'g', 'w', 'd', 'g', 'p', 'w', 'q', 'l', 'k', 't', - 'i', 'l', 'h', 'f', 'l', 'q', 'q', 'd', 'j' }, - { 'k', 'n', 'x', 'o', 'g', 'g', 'w', 'p', 'f', 'h', 'l', 'c', 'o', 'j', 'f', 'u', 'y', 'c', 'm', 'l', - 'o', 'g', 'v', 'z', 'p', 'a', 'n', 'g', 't', 'q', 'r', 'd', 'f', 'r', 't', 'o', 'x', 'p', 'f', 'e', - 'x', 'q', 'g', 'n', 'z', 'm', 'j', 'z', 'q', 'w', 'k', 'e', 'e', 'h', 'g', 't', 'i', 'v', 'b', 'b', - 'n', 'v', 'g', 's', 'm', 'z', 'g', 'l', 'p' }, - { 'o', 'p', 'o', 'e', 'w', 'b', 'g', 'k', 'k', 'f', 'a', 'i', 's', 'g', 'o', 'b', 'o', 'k', 'j', 'j', - 'n', 'm', 'w', 'i', 's', 'r', 'u', 'u', 'x', 'f', 'j', 'n', 'v', 'x', 'u', 't', 'a', 'a', 'd', 'm', - 'h', 'f', 'x', 'b', 'n', 'l', 'd', 'c', 'v', 'o', 'n', 'j', 'd', 'k', 'r', 'x', 'b', 'o', 'r', 'a', - 'v', 'c', 'o', 's', 'b', 'i', 'l', 'b', 'k' }, - { 'q', 'q', 'r', 'v', 'n', 'v', 'j', 'y', 'y', 'n', 'u', 'o', 'a', 'f', 'r', 'm', 'w', 'p', 'p', 'm', - 'g', 'q', 'i', 'j', 'g', 'a', 'k', 'q', 'o', 'o', 'c', 'e', 'e', 'v', 'c', 'r', 'q', 'n', 'r', 'q', - 'a', 'l', 'f', 'c', 's', 'w', 'p', 'p', 'n', 'e', 'd', 'w', 'w', 'l', 'f', 'e', 'o', 'r', 'w', 'e', - 'f', 'y', 'i', 'l', 'u', 'k', 'c', 'k', 'x' }, - { 'u', 'd', 'z', 'h', 'i', 'c', 'a', 'g', 't', 'r', 'w', 'z', 'u', 's', 'y', 'i', 'x', 'e', 'y', 'q', - 'b', 'c', 'y', 'b', 'm', 'j', 'v', 'z', 'o', 'i', 'y', 'i', 'l', 'a', 'r', 'v', 'e', 't', 'd', 'x', - 'k', 'z', 'y', 'h', 'r', 'y', 'r', 'q', 'd', 'r', 'j', 'g', 'v', 'h', 'h', 'h', 'q', 'd', 'i', 'e', - 'n', 'j', 'o', 'a', 'j', 'i', 'x', 'n', 'b' }, - { 'a', 'm', 'm', 'c', 'k', 'v', 'v', 'j', 'm', 'm', 'o', 'd', 'x', 'u', 'y', 'e', 'b', 'h', 'w', 'g', - 's', 'b', 't', 'b', 'r', 'v', 'k', 'z', 's', 'z', 'd', 't', 'l', 'p', 'x', 'x', 'm', 's', 'i', 'a', - 'g', 'w', 'f', 'd', 's', 'd', 'j', 'u', 'm', 'g', 'c', 'e', 'j', 'y', 'h', 'a', 't', 't', 'c', 'o', - 's', 'f', 'j', 'f', 'w', 'g', 'd', 'i', 'y' }, - { 'n', 'k', 'h', 'm', 'p', 'k', 'e', 'u', 'u', 'a', 'g', 'a', 'f', 'n', 'j', 'd', 'w', 'l', 'y', 'q', - 'n', 'm', 'i', 'u', 'v', 'q', 'q', 'd', 't', 'a', 'c', 'i', 'k', 'j', 'u', 'b', 'v', 'b', 'v', 'r', - 'b', 'e', 'r', 'i', 'r', 'c', 'l', 'n', 'q', 'm', 'f', 'f', 'y', 'o', 'a', 'w', 'e', 's', 'z', 'z', - 'v', 'd', 'j', 'h', 'o', 'e', 'j', 'm', 'h' }, - { 'e', 'd', 'i', 'k', 'x', 't', 'b', 'z', 'e', 'r', 'r', 's', 'w', 'x', 't', 'm', 'z', 'p', 's', 'r', - 'q', 't', 'o', 'w', 'd', 'w', 'm', 'j', 'h', 'y', 'q', 'n', 'c', 'a', 'y', 'b', 't', 'b', 'c', 'a', - 'u', 'u', 's', 't', 'r', 'n', 'h', 's', 'e', 'a', 'l', 'x', 'v', 'a', 't', 'a', 'y', 'h', 'l', 'h', - 'g', 'd', 'u', 'k', 'e', 's', 'l', 'z', 'w' }, - { 'n', 'b', 'q', 'j', 'w', 'j', 'c', 'j', 'r', 'u', 'o', 't', 'g', 'l', 'q', 'i', 'g', 'r', 'i', 'n', - 'e', 'p', 'v', 'i', 'j', 'h', 'o', 'e', 'u', 'n', 'a', 'i', 'r', 's', 't', 'n', 'c', 'w', 'y', 'v', - 's', 'o', 'q', 'a', 'b', 'g', 'i', 'h', 'z', 's', 'x', 'e', 'h', 'u', 'o', 't', 'c', 'c', 'x', 'w', - 'r', 'z', 'g', 'i', 'r', 'a', 'x', 'v', 'y' }, - { 'y', 'q', 'q', 'm', 'g', 'r', 'o', 'p', 'b', 'x', 'o', 'u', 'u', 'u', 'b', 'p', 'i', 'w', 'r', 'k', - 't', 'p', 'c', 'u', 'w', 'm', 'm', 'y', 'k', 'j', 'w', 'i', 'a', 'o', 'w', 'i', 'f', 'k', 'x', 'j', - 'i', 'o', 'd', 'e', 'i', 'g', 't', 'r', 'd', 'm', 'b', 'y', 'c', 'f', 't', 'a', 's', 'h', 'y', 'e', - 'q', 'w', 'o', 's', 'k', 'k', 'd', 's', 'v' }, - { 'a', 'b', 'f', 'o', 'g', 'j', 'z', 'm', 'f', 'q', 'p', 'r', 'r', 'o', 'v', 'z', 'j', 'x', 'r', 'q', - 'v', 'v', 'i', 't', 'j', 'b', 'g', 'v', 'e', 'y', 's', 'g', 'b', 'x', 'x', 'h', 'j', 'w', 't', 'o', - 'm', 'l', 'h', 'f', 'b', 'd', 'e', 'k', 'a', 'x', 'c', 'y', 's', 'k', 't', 'd', 'n', 'z', 'b', 'r', - 'z', 't', 'a', 'a', 'r', 'x', 'h', 'c', 'v' }, - { 'd', 'q', 'j', 'q', 'x', 'o', 'r', 'c', 'v', 'd', 'd', 's', 'h', 'd', 'n', 'r', 'w', 's', 'f', 'w', - 't', 'y', 'x', 'n', 'a', 'y', 'g', 'x', 'h', 'i', 'u', 'm', 'y', 'd', 'c', 'x', 's', 't', 'a', 'p', - 'y', 'f', 'h', 'f', 'i', 'w', 'z', 'g', 'p', 'g', 'c', 'i', 'g', 'a', 'x', 'h', 'a', 'd', 'g', 'h', - 'n', 'b', 'w', 'n', 'e', 'y', 'l', 'y', 'u' }, - { 'n', 'n', 's', 's', 'x', 'a', 'c', 't', 'z', 'i', 'k', 'f', 'n', 't', 'n', 'p', 's', 'u', 'p', 'w', - 'b', 'y', 'l', 'c', 'u', 'z', 'i', 'v', 'm', 'h', 'p', 'z', 'w', 'j', 't', 't', 'j', 'v', 'p', 'k', - 'f', 'z', 'r', 's', 'u', 'f', 'h', 'n', 'z', 'y', 'l', 'c', 'z', 'w', 'e', 't', 'x', 'p', 'o', 'j', - 'w', 'f', 'k', 'u', 'p', 'f', 'o', 'a', 'a' }, - { 'f', 'l', 'i', 'e', 'c', 'a', 'z', 'h', 'k', 'o', 'j', 'i', 'z', 'l', 'h', 'v', 's', 'd', 'v', 'j', - 't', 'e', 'f', 'z', 'r', 'b', 'q', 'w', 'r', 'q', 'z', 'w', 'b', 'h', 'b', 'g', 'h', 'c', 'p', 't', - 'q', 'a', 'c', 'r', 'm', 'j', 'o', 'g', 'o', 'j', 'p', 'i', 'q', 'w', 'j', 'h', 'x', 'z', 'd', 'p', - 'p', 'e', 'n', 't', 'l', 'o', 'z', 'v', 's' }, - { 'q', 'o', 'k', 'r', 's', 'b', 'f', 'c', 'q', 'l', 's', 'b', 'c', 'a', 'r', 'a', 'j', 'y', 'z', 'i', - 'e', 'o', 'a', 'i', 'e', 't', 'w', 's', 'u', 'r', 'n', 'k', 'h', 'x', 'd', 'a', 'b', 'i', 'e', 't', - 'v', 'w', 'u', 'z', 'z', 'm', 'z', 'i', 'm', 'z', 't', 'q', 'p', 't', 'b', 't', 'o', 'x', 'o', 'i', - 'q', 'd', 'u', 'x', 'c', 'a', 'z', 'd', 'i' }, - { 'd', 'y', 'g', 'c', 't', 'f', 'b', 'h', 'h', 'j', 't', 'g', 'e', 'm', 'x', 'x', 'n', 't', 'n', 'k', - 'j', 'x', 'c', 'm', 's', 'b', 'q', 's', 'b', 'u', 'c', 'g', 'u', 'i', 'i', 'n', 'q', 'j', 'u', 'x', - 'v', 'q', 'f', 'z', 'c', 'c', 'z', 'r', 'x', 'm', 'd', 'i', 'k', 'f', 'u', 'e', 'g', 'n', 'y', 'h', - 'h', 'c', 'q', 'b', 'l', 'y', 'r', 'd', 'k' } }; - - Assertions.assertFalse(demo.exist(board2, "afdfghjhy")); - - char[][] board3 = - { { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }, - { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', - 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'b' } }; - String longWord = - "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - - Assertions.assertTrue(demo.exist(board3, longWord)); - } - - public boolean exist(char[][] board, String word) { - if (board == null || board.length == 0 - || word == null || word.length() == 0) { return false; } - - int row = board.length; - int col = board[0].length; - boolean[][] visited = new boolean[row][col]; - for (int i = 0; i < row; i++) { - for (int j = 0; j < col; j++) { - if (dfs(board, visited, "", word, i, j)) { - return true; - } - } - } - - return false; - } - - // DFS + 回溯 + 剪枝 - public boolean dfs(char[][] board, boolean[][] visited, String str, String word, int x, int y) { - // 数组越界,扫描退出 - if (x < 0 || x >= board.length || y < 0 || y >= board[0].length) { return false; } - if (str.length() > word.length()) return false; - if (!word.startsWith(str)) return false; - // 已扫描过,则退出 - if (visited[x][y]) return false; - - // 拼接字符串,然后在字典树中查找,如果找到 word,添加到目标 list - // visited[x][y] 已被扫描过,置为 true - str += board[x][y]; - // if (!trie.startsWith(str)) return false; - if (word.equals(str)) return true; - visited[x][y] = true; - - // 基于当前位置,向四个方向展开 DFS 搜索 - boolean flag = dfs(board, visited, str, word, x + 1, y) - || dfs(board, visited, str, word, x - 1, y) - || dfs(board, visited, str, word, x, y + 1) - || dfs(board, visited, str, word, x, y - 1); - if (flag) return true; - - // // 重置 visited[x][y] 为 false - visited[x][y] = false; - return false; - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242II.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242II.java" deleted file mode 100644 index 3ad1f6e..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\215\225\350\257\215\346\220\234\347\264\242II.java" +++ /dev/null @@ -1,161 +0,0 @@ -package io.github.dunwu.algorithm.trie; - -import org.junit.jupiter.api.Assertions; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * @author Zhang Peng - * @see 212. 单词搜索 II - * @since 2020-07-04 - */ -public class 单词搜索II { - - Set set = new HashSet<>(); - - public static void main(String[] args) { - String[] words = { "oath", "pea", "eat", "rain" }; - char[][] board = { - { 'o', 'a', 'a', 'n' }, - { 'e', 't', 'a', 'e' }, - { 'i', 'h', 'k', 'r' }, - { 'i', 'f', 'l', 'v' } - }; - - 单词搜索II demo = new 单词搜索II(); - List result = demo.findWords(board, words); - Assertions.assertArrayEquals(Arrays.asList("oath", "eat").toArray(), result.toArray()); - } - - // 利用字典树来进行单词搜索 - public List findWords(char[][] board, String[] words) { - - if (board == null || board.length == 0 - || words == null || words.length == 0) { return new ArrayList<>(set); } - - // 初始化字典树 - Trie trie = new Trie(); - for (String w : words) { - trie.insert(w); - } - - int row = board.length; - int col = board[0].length; - boolean[][] visited = new boolean[row][col]; - for (int i = 0; i < row; i++) { - for (int j = 0; j < col; j++) { - dfs(board, visited, trie, "", i, j); - } - } - - return new ArrayList<>(set); - } - - public void dfs(char[][] board, boolean[][] visited, Trie trie, String str, int x, int y) { - // 数组越界,扫描退出 - if (x < 0 || x >= board.length || y < 0 || y >= board[0].length) { return;} - // 已扫描过,则退出 - if (visited[x][y]) return; - - // 拼接字符串,然后在字典树中查找,如果找到 word,添加到目标 list - // visited[x][y] 已被扫描过,置为 true - str += board[x][y]; - if (!trie.startsWith(str)) return; - if (trie.search(str)) set.add(str); - visited[x][y] = true; - - // 基于当前位置,向四个方向展开 DFS 搜索 - dfs(board, visited, trie, str, x + 1, y); - dfs(board, visited, trie, str, x - 1, y); - dfs(board, visited, trie, str, x, y + 1); - dfs(board, visited, trie, str, x, y - 1); - - // 重置 visited[x][y] 为 false - visited[x][y] = false; - } - - public static class Trie { - - private TrieNode root; - public static final int MAX_WORD_COUNT = 26; - - public Trie() { - root = new TrieNode('/'); - } - - public void insert(String word) { - if (word == null || word.length() == 0) { - return; - } - - TrieNode node = root; - for (int i = 0; i < word.length(); i++) { - char c = word.charAt(i); - int index = c - 'a'; - if (node.children[index] == null) { - node.children[index] = new TrieNode(c); - } - node = node.children[index]; - } - node.isEnd = true; - } - - public boolean search(String word) { - if (word == null || word.length() == 0) { - return false; - } - - TrieNode node = root; - for (int i = 0; i < word.length(); i++) { - char c = word.charAt(i); - int index = c - 'a'; - if (node.children[index] == null) { - return false; - } - node = node.children[index]; - } - return node.isEnd; - } - - public boolean startsWith(String prefix) { - if (prefix == null || prefix.length() == 0) { - return false; - } - - TrieNode node = root; - for (int i = 0; i < prefix.length(); i++) { - char c = prefix.charAt(i); - int index = c - 'a'; - if (node.children[index] == null) { - return false; - } - node = node.children[index]; - } - return true; - } - - static class TrieNode { - - boolean isEnd; - char data; - TrieNode[] children; - - public TrieNode(char data) { - this(data, false); - } - - public TrieNode(char data, boolean isEnd) { - this.data = data; - this.isEnd = isEnd; - children = new TrieNode[MAX_WORD_COUNT]; - } - - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\256\236\347\216\260Trie_\345\211\215\347\274\200\346\240\221.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\256\236\347\216\260Trie_\345\211\215\347\274\200\346\240\221.java" deleted file mode 100644 index 4b1b84c..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\345\256\236\347\216\260Trie_\345\211\215\347\274\200\346\240\221.java" +++ /dev/null @@ -1,99 +0,0 @@ -package io.github.dunwu.algorithm.trie; - -import org.junit.jupiter.api.Assertions; - -/** - * @author Zhang Peng - * @see 208. 实现 Trie (前缀树) - * @since 2020-06-15 - */ -public class 实现Trie_前缀树 { - - public static void main(String[] args) { - 实现Trie_前缀树 trie = new 实现Trie_前缀树(); - trie.insert("apple"); - Assertions.assertTrue(trie.search("apple")); - Assertions.assertFalse(trie.search("app")); - Assertions.assertTrue(trie.startsWith("app")); - - trie.insert("app"); - Assertions.assertTrue(trie.search("app")); - } - - private TrieNode root; - public static final int MAX_WORD_COUNT = 26; - - public 实现Trie_前缀树() { - root = new TrieNode('/'); - } - - public void insert(String word) { - if (word == null || word.length() == 0) { - return; - } - - TrieNode node = root; - for (int i = 0; i < word.length(); i++) { - char c = word.charAt(i); - int index = c - 'a'; - if (node.children[index] == null) { - node.children[index] = new TrieNode(c); - } - node = node.children[index]; - } - node.isEnd = true; - } - - public boolean search(String word) { - if (word == null || word.length() == 0) { - return false; - } - - TrieNode node = root; - for (int i = 0; i < word.length(); i++) { - char c = word.charAt(i); - int index = c - 'a'; - if (node.children[index] == null) { - return false; - } - node = node.children[index]; - } - return node.isEnd; - } - - public boolean startsWith(String prefix) { - if (prefix == null || prefix.length() == 0) { - return false; - } - - TrieNode node = root; - for (int i = 0; i < prefix.length(); i++) { - char c = prefix.charAt(i); - int index = c - 'a'; - if (node.children[index] == null) { - return false; - } - node = node.children[index]; - } - return true; - } - - public static class TrieNode { - - boolean isEnd; - char data; - TrieNode[] children; - - public TrieNode(char data) { - this(data, false); - } - - public TrieNode(char data, boolean isEnd) { - this.data = data; - this.isEnd = isEnd; - children = new TrieNode[MAX_WORD_COUNT]; - } - - } - -} diff --git "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" "b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" deleted file mode 100644 index 8cd0187..0000000 --- "a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/trie/\346\234\200\351\225\277\345\205\254\345\205\261\345\211\215\347\274\200.java" +++ /dev/null @@ -1,21 +0,0 @@ -package io.github.dunwu.algorithm.trie; - -/** - * @author Zhang Peng - * @since 2020-06-15 - */ -public class 最长公共前缀 { - - public static void main(String[] args) { - longestCommonPrefix("flower", "flow", "flight"); - } - - public static String longestCommonPrefix(String... strs) { - Trie trie = new Trie(); - for (String s : strs) { - trie.insert(s.toCharArray()); - } - return trie.longest(); - } - -} diff --git a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java b/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java deleted file mode 100644 index 117d1b1..0000000 --- a/codes/algorithm/src/main/java/io/github/dunwu/algorithm/util/ArrayUtil.java +++ /dev/null @@ -1,232 +0,0 @@ -package io.github.dunwu.algorithm.util; - -import lombok.extern.slf4j.Slf4j; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; - -/** - * 数组工具类 - * - * @author Zhang Peng - */ -@Slf4j -public class ArrayUtil { - - public static int[] toIntArray(List list) { - if (list == null || list.isEmpty()) { return new int[0]; } - int[] res = new int[list.size()]; - for (int i = 0; i < list.size(); i++) { - res[i] = list.get(i); - } - return res; - } - - public static List> toIntMatrixList(int[][] arr) { - if (arr == null || arr.length == 0) { return new ArrayList<>(); } - List> listlist = new ArrayList<>(); - for (int i = 0; i < arr.length; i++) { - List list = new ArrayList<>(); - listlist.add(list); - for (int j = 0; j < arr[i].length; j++) { - list.add(arr[i][j]); - } - } - return listlist; - } - - public static int[][] toIntMatrixArray(List> listlist) { - if (listlist == null || listlist.size() == 0) { return new int[0][0]; } - List arrList = new ArrayList<>(); - for (List list : listlist) { - arrList.add(toIntArray(list)); - } - return arrList.toArray(new int[listlist.size()][]); - } - - public static String[] toStringArray(List list) { - if (list == null || list.isEmpty()) { return new String[0]; } - String[] res = new String[list.size()]; - for (int i = 0; i < list.size(); i++) { - res[i] = list.get(i); - } - return res; - } - - public static List> toStringMatrixList(String[][] arr) { - if (arr == null || arr.length == 0) { return new ArrayList<>(); } - List> listlist = new ArrayList<>(); - for (String[] strings : arr) { - List list = new ArrayList<>(); - listlist.add(list); - Collections.addAll(list, strings); - } - return listlist; - } - - public static String[][] toStringMatrixArray(List> listlist) { - if (listlist == null || listlist.size() == 0) { return new String[0][0]; } - List arrList = new ArrayList<>(); - for (List list : listlist) { - arrList.add(toStringArray(list)); - } - return arrList.toArray(new String[listlist.size()][]); - } - - public static void printArray(T[] arr, int begin, int end, String tip) { - System.out.printf("%s -> %s\n", tip, getArrayString(arr, begin, end)); - } - - public static String getArrayString(T[] arr) { - return getArrayString(arr, 0, arr.length); - } - - public static String getArrayString(T[] arr, int begin, int end) { - StringBuilder sb = new StringBuilder(); - int count = 0; - for (int i = begin; i <= end; i++) { - if (count != 0 && count % 10 == 0) { - sb.append("\n"); - } - sb.append("\t" + arr[i]); - count++; - } - - return sb.toString(); - } - - /** - * 随机指定范围内N个不重复的Int数组。 - *

- * 在初始化的无重复待选数组中随机产生一个数放入结果中, - *

- *

- * 将待选数组被随机到的数,用待选数组(len-1)下标对应的数替换, - *

- *

- * 然后从len-2里随机产生下一个随机数,如此类推 - *

- * - * @param min 指定范围最小值 - * @param max 指定范围最大值 - * @param length 随机数个数 - * @return int[] 随机数结果集 - */ - public static int[] randomNoRepeatIntArray(int min, int max, int length) { - int len = max - min + 1; - - if (max < min || length > len) { - return null; - } - - // 初始化给定范围的待选数组 - int[] source = new int[len]; - for (int i = min; i < min + len; i++) { - source[i - min] = i; - } - - int[] result = new int[length]; - Random rd = new Random(); - int index = 0; - for (int i = 0; i < result.length; i++) { - // 待选数组0到(len-2)随机一个下标 - index = Math.abs(rd.nextInt() % len--); - // 将随机到的数放入结果集 - result[i] = source[index]; - // 将待选数组中被随机到的数,用待选数组(len-1)下标对应的数替换 - source[index] = source[len]; - } - return result; - } - - /** - * 随机指定范围内N个重复的Int数组。 - * - * @param min 指定范围最小值 - * @param max 指定范围最大值 - * @param length 随机数个数 - * @return 随机数结果集 - */ - public static int[] randomRepeatIntArray(int min, int max, int length) { - int len = max - min + 1; - - if (max < min || length > len) { - return null; - } - - int[] result = new int[length]; - for (int i = 0; i < result.length; i++) { - result[i] = (int) (Math.random() * max); - } - return result; - } - - /** - * 随机指定范围内N个不重复的Integer数组。 - *

- * 在初始化的无重复待选数组中随机产生一个数放入结果中, - *

- *

- * 将待选数组被随机到的数,用待选数组(len-1)下标对应的数替换, - *

- *

- * 然后从len-2里随机产生下一个随机数,如此类推 - *

- * - * @param min 指定范围最小值 - * @param max 指定范围最大值 - * @param length 随机数个数 - * @return int[] 随机数结果集 - */ - public static Integer[] randomNoRepeatIntegerArray(int min, int max, int length) { - int len = max - min + 1; - - if (max < min || length > len) { - return null; - } - - // 初始化给定范围的待选数组 - Integer[] source = new Integer[len]; - for (int i = min; i < min + len; i++) { - source[i - min] = i; - } - - Integer[] result = new Integer[length]; - Random rd = new Random(); - int index = 0; - for (int i = 0; i < result.length; i++) { - // 待选数组0到(len-2)随机一个下标 - index = Math.abs(rd.nextInt() % len--); - // 将随机到的数放入结果集 - result[i] = source[index]; - // 将待选数组中被随机到的数,用待选数组(len-1)下标对应的数替换 - source[index] = source[len]; - } - return result; - } - - /** - * 随机指定范围内N个重复的Integer数组。 - * - * @param min 指定范围最小值 - * @param max 指定范围最大值 - * @param length 随机数个数 - * @return 随机数结果集 - */ - public static Integer[] randomRepeatIntegerArray(int min, int max, int length) { - int len = max - min + 1; - - if (max < min || length > len) { - return null; - } - - Integer[] result = new Integer[length]; - for (int i = 0; i < result.length; i++) { - result[i] = (int) (Math.random() * max); - } - return result; - } - -} diff --git a/codes/algorithm/src/main/resources/logback.xml b/codes/algorithm/src/main/resources/logback.xml deleted file mode 100644 index 3a5812a..0000000 --- a/codes/algorithm/src/main/resources/logback.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - %d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n - - - - - - ${user.dir}/logs/${DIR_NAME}/all.%d{yyyy-MM-dd}.log - 30 - - - - - 30MB - - - - %d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n - - - - - - - - - - - - - - - - - diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/IteratorTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/IteratorTest.java deleted file mode 100644 index 6aa8bcb..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/IteratorTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.dunwu.algorithm.common; - -import java.util.Iterator; - -public class IteratorTest { - - public static > boolean testIterator(Iterator iter) { - while (iter.hasNext()) { - T item = iter.next(); - if (item == null) { - System.err.println("Iterator failure."); - return false; - } - } - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/JavaCollectionTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/JavaCollectionTest.java deleted file mode 100644 index ccf9bb6..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/JavaCollectionTest.java +++ /dev/null @@ -1,255 +0,0 @@ -package io.github.dunwu.algorithm.common; - -import java.util.Collection; - -public class JavaCollectionTest { - - public static > boolean testCollection(Collection collection, Class type, String name, - Integer[] unsorted, Integer[] sorted, Integer _invalid) { - // Make sure the collection is empty - if (!collection.isEmpty()) { - System.err.println(name + " initial isEmpty() failed."); - Utils.handleError(collection); - return false; - } - - if (collection.size() != 0) { - System.err.println(name + " initial size() failed."); - Utils.handleError(collection); - return false; - } - - addAndRemoveInOrder(collection, type, name, unsorted, _invalid); - addInOrderRemoveInReverseOrder(collection, type, name, unsorted, _invalid); - addInReverseOrderAndRemoveInOrder(collection, type, name, unsorted, _invalid); - - addAndRemoveInOrder(collection, type, name, sorted, _invalid); - addInOrderRemoveInReverseOrder(collection, type, name, sorted, _invalid); - addInReverseOrderAndRemoveInOrder(collection, type, name, sorted, _invalid); - - // Make sure the collection is empty - if (!collection.isEmpty()) { - System.err.println(name + " initial isEmpty() failed."); - Utils.handleError(collection); - return false; - } - - if (collection.size() != 0) { - System.err.println(name + " initial size() failed."); - Utils.handleError(collection); - return false; - } - - return true; - } - - private static > boolean addAndRemoveInOrder(Collection collection, Class type, - String name, Integer[] data, Integer _invalid) { - T invalid = Utils.parseT(_invalid, type); - - // Add and remove in order (from index zero to length) - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - boolean added = collection.add(item); - if (!added) { - System.err.println(name + " addAndRemoveInOrder add failed."); - Utils.handleError(data, collection); - return false; - } - } - - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - boolean contains = collection.contains(item); - if (!contains) { - System.err.println(name + " addAndRemoveInOrder contains failed."); - Utils.handleError(data, collection); - return false; - } - } - - boolean contains = collection.contains(invalid); - boolean removed = collection.remove(invalid); - if (contains || removed) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, collection); - return false; - } - - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - removed = collection.remove(item); - if (!removed) { - System.err.println(name + " addAndRemoveInOrder remove failed."); - Utils.handleError(data, collection); - return false; - } - } - - if (!collection.isEmpty()) { - System.err.println(name + " addAndRemoveInOrder isEmpty() failed."); - Utils.handleError(data, collection); - return false; - } - if (collection.size() != 0) { - System.err.println(name + " addAndRemoveInOrder size() failed."); - Utils.handleError(data, collection); - return false; - } - - if (collection instanceof java.util.List && (!ListIteratorTest - .testListIterator(((java.util.List) collection).listIterator(), type, data, data.length))) { - System.err.println(name + " addAndRemoveInOrder list iterator failed."); - Utils.handleError(data, collection); - return false; - } - - return true; - } - - public static > boolean addInOrderRemoveInReverseOrder(Collection collection, - Class type, String name, Integer[] data, Integer _invalid) { - T invalid = Utils.parseT(_invalid, type); - - // Add in order (from index zero to length) and then remove in reverse (from index - // length-1 to zero) order - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - boolean added = collection.add(item); - if (!added) { - System.err.println(name + " addInOrderRemoveInReverseOrder add failed."); - Utils.handleError(data, collection); - return false; - } - } - - boolean contains = collection.contains(invalid); - boolean removed = collection.remove(invalid); - if (contains || removed) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, collection); - return false; - } - - if (!IteratorTest.testIterator(collection.iterator())) { - System.err.println(name + " addInOrderRemoveInReverseOrder iterator failed."); - Utils.handleError(data, collection); - return false; - } - - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - contains = collection.contains(item); - if (!contains) { - System.err.println(name + " addInOrderRemoveInReverseOrder contains failed."); - Utils.handleError(data, collection); - return false; - } - } - - for (int i = data.length - 1; i >= 0; i--) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - removed = collection.remove(item); - if (!removed) { - System.err.println(name + " addInOrderRemoveInReverseOrder remove failed."); - Utils.handleError(data, collection); - return false; - } - } - - if (!collection.isEmpty()) { - System.err.println(name + " addInOrderRemoveInReverseOrder isEmpty() failed."); - Utils.handleError(data, collection); - return false; - } - if (collection.size() != 0) { - System.err.println(name + " addInOrderRemoveInReverseOrder size() failed."); - Utils.handleError(data, collection); - return false; - } - - if (collection instanceof java.util.List && (!ListIteratorTest - .testListIterator(((java.util.List) collection).listIterator(), type, data, data.length))) { - System.err.println(name + " addInOrderRemoveInReverseOrder list iterator failed."); - Utils.handleError(data, collection); - return false; - } - - return true; - } - - private static > boolean addInReverseOrderAndRemoveInOrder(Collection collection, - Class type, String name, Integer[] data, Integer _invalid) { - T invalid = Utils.parseT(_invalid, type); - - // Add in reverse (from index length-1 to zero) order and then remove in order - // (from index zero to length) - for (int i = data.length - 1; i >= 0; i--) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - boolean added = collection.add(item); - if (!added) { - System.err.println(name + " addInReverseOrderAndRemoveInOrder add failed."); - Utils.handleError(data, collection); - return false; - } - } - - boolean contains = collection.contains(invalid); - boolean removed = collection.remove(invalid); - if (contains || removed) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, collection); - return false; - } - - if (!IteratorTest.testIterator(collection.iterator())) { - System.err.println(name + " addInReverseOrderAndRemoveInOrder iterator failed."); - Utils.handleError(data, collection); - return false; - } - - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - contains = collection.contains(item); - if (!contains) { - System.err.println(name + " addInReverseOrderAndRemoveInOrder contains failed."); - Utils.handleError(data, collection); - return false; - } - } - - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - removed = collection.remove(item); - if (!removed) { - System.err.println(name + " addInReverseOrderAndRemoveInOrder remove failed."); - Utils.handleError(data, collection); - return false; - } - } - - if (!collection.isEmpty()) { - System.err.println(name + " addInReverseOrderAndRemoveInOrder isEmpty() failed."); - Utils.handleError(data, collection); - return false; - } - - if (collection.size() != 0) { - System.err.println(name + " addInReverseOrderAndRemoveInOrder size() failed."); - Utils.handleError(data, collection); - return false; - } - - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/JavaMapTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/JavaMapTest.java deleted file mode 100644 index db018a3..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/JavaMapTest.java +++ /dev/null @@ -1,307 +0,0 @@ -package io.github.dunwu.algorithm.common; - -@SuppressWarnings("unchecked") -public class JavaMapTest { - - public static > boolean testJavaMap(java.util.Map map, Class type, - String name, Integer[] unsorted, Integer[] sorted, Integer _invalid) { - // Make sure the map is empty - if (!map.isEmpty()) { - System.err.println(name + " initial isEmpty() failed."); - Utils.handleError(map); - return false; - } - if (map.size() != 0) { - System.err.println(name + " initial size() failed."); - Utils.handleError(map); - return false; - } - - addInOrderAndRemoveInOrder(map, type, name, unsorted, _invalid); - addInReverseOrderAndRemoveInReverseOrder(map, type, name, unsorted, _invalid); - addInOrderAndRemoveInReverseOrder(map, type, name, unsorted, _invalid); - - addInOrderAndRemoveInOrder(map, type, name, sorted, _invalid); - addInReverseOrderAndRemoveInReverseOrder(map, type, name, sorted, _invalid); - addInOrderAndRemoveInReverseOrder(map, type, name, sorted, _invalid); - - // Make sure the map is empty - if (!map.isEmpty()) { - System.err.println(name + " initial isEmpty() failed."); - Utils.handleError(map); - return false; - } - if (map.size() != 0) { - System.err.println(name + " initial size() failed."); - Utils.handleError(map); - return false; - } - - return true; - } - - private static > boolean addInOrderAndRemoveInOrder(java.util.Map map, - Class keyType, String name, Integer[] data, Integer _invalid) { - for (int i = 0; i < data.length; i++) { - Integer item = data[i]; - K k = null; - V v = null; - if (keyType.isAssignableFrom(Integer.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, String.class); - } else if (keyType.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, Integer.class); - } - map.put(k, v); - } - - K invalidKey = (K) Utils.parseT(_invalid, keyType); - boolean contains = map.containsKey(invalidKey); - V removed = map.remove(invalidKey); - if (contains || (removed != null)) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, map); - return false; - } - - for (Integer item : data) { - K k = (K) Utils.parseT(item, keyType); - map.containsKey(k); - } - - for (int i = 0; i < data.length; i++) { - Integer item = data[i]; - K k = (K) Utils.parseT(item, keyType); - removed = map.remove(k); - if (removed == null) { - System.err.println(name + " invalidity check. removed=" + removed); - Utils.handleError(data, map); - return false; - } - } - - if (!testMapEntrySet(map, keyType, data)) { return false; } - - if (!map.isEmpty()) { - System.err.println(name + " isEmpty() failed."); - Utils.handleError(data, map); - return false; - } - if (map.size() != 0) { - System.err.println(name + " size() failed."); - Utils.handleError(data, map); - return false; - } - return true; - } - - private static > boolean addInReverseOrderAndRemoveInReverseOrder( - java.util.Map map, Class keyType, String name, Integer[] data, Integer _invalid) { - for (int i = data.length - 1; i >= 0; i--) { - Integer item = data[i]; - K k = null; - V v = null; - if (keyType.isAssignableFrom(Integer.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, String.class); - } else if (keyType.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, String.class); - } - map.put(k, v); - } - - K invalidKey = (K) Utils.parseT(_invalid, keyType); - boolean contains = map.containsKey(invalidKey); - V removed = map.remove(invalidKey); - if (contains || (removed != null)) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, map); - return false; - } - - for (Integer item : data) { - K k = (K) Utils.parseT(item, keyType); - map.containsKey(k); - } - - for (int i = data.length - 1; i >= 0; i--) { - Integer item = data[i]; - K k = (K) Utils.parseT(item, keyType); - removed = map.remove(k); - if (removed == null) { - System.err.println(name + " invalidity check. removed=" + removed); - Utils.handleError(data, map); - return false; - } - } - - if (!map.isEmpty()) { - System.err.println(name + " isEmpty() failed."); - Utils.handleError(data, map); - return false; - } - if (map.size() != 0) { - System.err.println(name + " size() failed."); - Utils.handleError(data, map); - return false; - } - return true; - } - - private static > boolean addInOrderAndRemoveInReverseOrder(java.util.Map map, - Class keyType, String name, Integer[] data, Integer _invalid) { - for (int i = 0; i < data.length; i++) { - Integer item = data[i]; - K k = null; - V v = null; - if (keyType.isAssignableFrom(Integer.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, String.class); - } else if (keyType.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, Integer.class); - } - map.put(k, v); - } - - K invalidKey = (K) Utils.parseT(_invalid, keyType); - boolean contains = map.containsKey(invalidKey); - V removed = map.remove(invalidKey); - if (contains || (removed != null)) { - System.err.println(name + " sorted invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, map); - return false; - } - - for (Integer item : data) { - K k = (K) Utils.parseT(item, keyType); - map.containsKey(k); - } - - for (int i = data.length - 1; i >= 0; i--) { - Integer item = data[i]; - K k = (K) Utils.parseT(item, keyType); - removed = map.remove(k); - if (removed == null) { - System.err.println(name + " invalidity check. removed=" + removed); - Utils.handleError(data, map); - return false; - } - } - - if (!testMapEntrySet(map, keyType, data)) { return false; } - - if (!map.isEmpty()) { - System.err.println(name + " sorted isEmpty() failed."); - Utils.handleError(data, map); - return false; - } - if (map.size() != 0) { - System.err.println(name + " sorted size() failed."); - Utils.handleError(data, map); - return false; - } - return true; - } - - private static > boolean testMapEntrySet(java.util.Map map, Class keyType, - Integer[] data) { - { // Test keys - for (int i = 0; i < data.length; i++) { - Integer item = data[i]; - K k = null; - V v = null; - if (keyType.isAssignableFrom(Integer.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, String.class); - } else if (keyType.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, Integer.class); - } - map.put(k, v); - } - - java.util.Set set = map.keySet(); - for (int i = 0; i < data.length; i++) { - Integer item = data[i]; - K k = (K) Utils.parseT(item, keyType); - if (!set.contains(k)) { - System.err.println("MayEntry contains() failure."); - Utils.handleError(data, map); - return false; - } - } - - java.util.Iterator keyIter = set.iterator(); - while (keyIter.hasNext()) { - keyIter.next(); - keyIter.remove(); - } - - if (!map.isEmpty()) { - System.err.println("MayEntry isEmpty() failure."); - Utils.handleError(data, map); - return false; - } - if (map.size() != 0) { - System.err.println("MayEntry size()!=0 failure."); - Utils.handleError(data, map); - return false; - } - } - - { // Test values - for (int i = 0; i < data.length; i++) { - Integer item = data[i]; - K k = null; - V v = null; - if (keyType.isAssignableFrom(Integer.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, String.class); - } else if (keyType.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, keyType); - v = (V) Utils.parseT(item, Integer.class); - } - map.put(k, v); - } - - java.util.Collection collection = map.values(); - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - V v = null; - // These are reversed on purpose - if (keyType.isAssignableFrom(Integer.class)) { - v = (V) Utils.parseT(value, String.class); - } else if (keyType.isAssignableFrom(String.class)) { - v = (V) Utils.parseT(value, Integer.class); - } - if (!collection.contains(v)) { - System.err.println("MayEntry contains() failure."); - Utils.handleError(data, map); - return false; - } - } - - java.util.Iterator valueIter = collection.iterator(); - while (valueIter.hasNext()) { - valueIter.next(); - valueIter.remove(); - } - - if (!map.isEmpty()) { - System.err.println("MayEntry isEmpty() failure."); - Utils.handleError(data, map); - return false; - } - if (map.size() != 0) { - System.err.println("MayEntry size()!=0 failure."); - Utils.handleError(data, map); - return false; - } - } - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/ListIteratorTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/ListIteratorTest.java deleted file mode 100644 index 4da00d1..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/ListIteratorTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package io.github.dunwu.algorithm.common; - -import java.util.ListIterator; -import java.util.NoSuchElementException; - -public class ListIteratorTest { - - public static > boolean testListIterator(ListIterator iter, Class type, - Integer[] data, int size) { - // Make sure you catch going prev at the start - boolean exceptionThrown = false; - try { - iter.previous(); - } catch (NoSuchElementException e) { - exceptionThrown = true; - } - if (!exceptionThrown) { - System.err.println("ListIterator exception failure."); - return false; - } - - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - iter.add(item); - } - while (iter.hasPrevious()) { iter.previous(); } - - int i = 0; - while (iter.hasNext()) { - T item = iter.next(); - int idx = iter.nextIndex(); - if (idx != ++i) { - System.err.println("ListIterator index failure."); - return false; - } - if (item == null) { - System.err.println("ListIterator item is null."); - return false; - } - } - - // We should be at the end of the collection, this should fail - exceptionThrown = false; - try { - iter.next(); - } catch (NoSuchElementException e) { - exceptionThrown = true; - } - if (!exceptionThrown) { - System.err.println("ListIterator exception failure."); - return false; - } - - // This should be list.size - iter.nextIndex(); - int listSize = iter.nextIndex(); - if (listSize != size) { - System.err.println("ListIterator ARRAY_SIZE failure."); - return false; - } - - i--; - while (iter.hasPrevious()) { - T item = iter.previous(); - int idx = iter.previousIndex(); - if (idx != --i) { - System.err.println("ListIterator index failure."); - return false; - } - if (item == null) { - System.err.println("ListIterator item is null."); - return false; - } - } - - // We should be at the beginning of the collection, this should fail - exceptionThrown = false; - try { - iter.previous(); - } catch (NoSuchElementException e) { - exceptionThrown = true; - } - if (!exceptionThrown) { - System.err.println("ListIterator exception failure."); - return false; - } - - // This should be negative one - iter.previousIndex(); - int negOne = iter.previousIndex(); - if (negOne != -1) { - System.err.println("ListIterator negative_one failure."); - return false; - } - - // Remove all using iterator - while (iter.hasNext()) { - iter.next(); - iter.remove(); - } - - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/ListTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/ListTest.java deleted file mode 100644 index 93930fc..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/ListTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.github.dunwu.algorithm.common; - -public class ListTest { - - public static > boolean testList(IList list, String name, T[] data, T _invalid) { - for (int i = 0; i < data.length; i++) { - T item = data[i]; - boolean added = list.add(item); - if ((!list.validate() || (list.size() != i + 1))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, list); - return false; - } - if ((!added || !list.contains(item))) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, list); - return false; - } - } - - boolean contains = list.contains(_invalid); - boolean removed = list.remove(_invalid); - if (contains || removed) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, list); - return false; - } - - int size = list.size(); - for (int i = 0; i < size; i++) { - T item = data[i]; - removed = list.remove(item); - if ((!list.validate() || (list.size() != data.length - (i + 1)))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, list); - return false; - } - if ((!removed || list.contains(item))) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, list); - return false; - } - } - - // Add half, remove a quarter, add three-quarters, remove all - int quarter = data.length / 4; - int half = data.length / 2; - for (int i = 0; i < half; i++) { - T item = data[i]; - boolean added = list.add(item); - if ((!list.validate() || (list.size() != i + 1))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, list); - return false; - } - if ((!added || !list.contains(item))) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, list); - return false; - } - } - for (int i = (half - 1); i >= quarter; i--) { - T item = data[i]; - removed = list.remove(item); - if ((!list.validate() || (list.size() != i))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, list); - return false; - } - if ((!removed || list.contains(item))) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, list); - return false; - } - } - for (int i = quarter; i < data.length; i++) { - T item = data[i]; - boolean added = list.add(item); - if ((!list.validate() || (list.size() != i + 1))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, list); - return false; - } - if ((!added || !list.contains(item))) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, list); - return false; - } - } - for (int i = data.length - 1; i >= 0; i--) { - T item = data[i]; - removed = list.remove(item); - if ((!list.validate() || (list.size() != i))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, list); - return false; - } - if ((!removed || list.contains(item))) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, list); - return false; - } - } - - if ((list.size() != 0)) { - System.err.println(name + " YIKES!! a size mismatch."); - Utils.handleError(data, list); - return false; - } - - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/MapTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/MapTest.java deleted file mode 100644 index 10b3e59..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/MapTest.java +++ /dev/null @@ -1,166 +0,0 @@ -package io.github.dunwu.algorithm.common; - -public class MapTest { - - @SuppressWarnings("unchecked") - public static > boolean testMap(IMap map, Class type, String name, - Integer[] data, Integer _invalid) { - for (int i = 0; i < data.length; i++) { - Integer item = data[i]; - K k = null; - V v = null; - if (type.isAssignableFrom(Integer.class)) { - k = (K) item; - v = (V) Utils.parseT(item, type); - } else if (type.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, type); - v = (V) item; - } - V added = map.put(k, v); - if ((!map.validate() || (map.size() != (i + 1)))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, map); - return false; - } - if ((added != null || !map.contains(k))) { - System.err.println(name + " YIKES!! " + item + " doesn't exists."); - Utils.handleError(data, map); - return false; - } - } - - K invalidKey = null; - if (type.isAssignableFrom(Integer.class)) { - invalidKey = (K) Utils.parseT(_invalid, type); - } else if (type.isAssignableFrom(String.class)) { - invalidKey = (K) Utils.parseT(_invalid, type); - } - boolean contains = map.contains(invalidKey); - V removed = map.remove(invalidKey); - if (contains || (removed != null)) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, map); - return false; - } - - for (int i = 0; i < data.length; i++) { - Integer item = data[i]; - K k = null; - if (type.isAssignableFrom(Integer.class)) { - k = (K) item; - } else if (type.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, type); - } - removed = map.remove(k); - if ((!map.validate() || (map.size() != (data.length - (i + 1))))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, map); - return false; - } - if (map.contains(k)) { - System.err.println(name + " YIKES!! " + item + " still exists."); - Utils.handleError(data, map); - return false; - } - } - - // Add half, remove a quarter, add three-quarters, remove all - int quarter = data.length / 4; - int half = data.length / 2; - for (int i = 0; i < half; i++) { - Integer item = data[i]; - K k = null; - V v = null; - if (type.isAssignableFrom(Integer.class)) { - k = (K) item; - v = (V) Utils.parseT(item, type); - } else if (type.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, type); - v = (V) item; - } - V added = map.put(k, v); - if ((!map.validate() || (map.size() != (i + 1)))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, map); - return false; - } - if ((added != null || !map.contains(k))) { - System.err.println(name + " YIKES!! " + item + " doesn't exists."); - Utils.handleError(data, map); - return false; - } - } - for (int i = (half - 1); i >= quarter; i--) { - Integer item = data[i]; - K k = null; - if (type.isAssignableFrom(Integer.class)) { - k = (K) item; - } else if (type.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, type); - } - removed = map.remove(k); - if ((!map.validate() || (map.size() != i))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, map); - return false; - } - if ((removed == null || map.contains(k))) { - System.err.println(name + " YIKES!! " + item + " still exists."); - Utils.handleError(data, map); - return false; - } - } - for (int i = quarter; i < data.length; i++) { - Integer item = data[i]; - K k = null; - V v = null; - if (type.isAssignableFrom(Integer.class)) { - k = (K) item; - v = (V) Utils.parseT(item, type); - } else if (type.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, type); - v = (V) item; - } - V added = map.put(k, v); - if ((!map.validate() || (map.size() != (i + 1)))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, map); - return false; - } - if ((added != null || !map.contains(k))) { - System.err.println(name + " YIKES!! " + item + " doesn't exists."); - Utils.handleError(data, map); - return false; - } - } - for (int i = data.length - 1; i >= 0; i--) { - Integer item = data[i]; - K k = null; - if (type.isAssignableFrom(Integer.class)) { - k = (K) item; - } else if (type.isAssignableFrom(String.class)) { - k = (K) Utils.parseT(item, type); - } - removed = map.remove(k); - if ((!map.validate() || (map.size() != i))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, map); - return false; - } - if ((removed == null || map.contains(k))) { - System.err.println(name + " YIKES!! " + item + " still exists."); - Utils.handleError(data, map); - return false; - } - } - - if ((map.size() != 0)) { - System.err.println(name + " YIKES!! a size mismatch."); - Utils.handleError(data, map); - return false; - } - - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/QueueTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/QueueTest.java deleted file mode 100644 index 17301db..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/QueueTest.java +++ /dev/null @@ -1,150 +0,0 @@ -package io.github.dunwu.algorithm.common; - -public class QueueTest { - - public static > boolean testQueue(IQueue queue, String name, T[] data, T _invalid) { - for (int i = 0; i < data.length; i++) { - T item = data[i]; - boolean added = queue.offer(item); - if (!queue.validate() || (queue.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, queue); - return false; - } - if (!added || !queue.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, queue); - return false; - } - } - - boolean contains = queue.contains(_invalid); - boolean removed = queue.remove(_invalid); - if (contains || removed) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, queue); - return false; - } - - int size = queue.size(); - for (int i = 0; i < size; i++) { - T item = queue.poll(); - T correct = data[i]; - if (item.compareTo(correct) != 0) { - System.err.println(name + " YIKES!! " + item + " does not match FIFO item."); - Utils.handleError(data, queue); - return false; - } - if (!queue.validate() || (queue.size() != data.length - (i + 1))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, queue); - return false; - } - if (queue.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, queue); - return false; - } - } - - // Add half, remove a quarter, add three-quarters - int quarter = data.length / 4; - int half = data.length / 2; - int changeOver = half - quarter; - for (int i = 0; i < half; i++) { - T item = data[i]; - boolean added = queue.offer(item); - if (!queue.validate() || (queue.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, queue); - return false; - } - if (!added || !queue.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, queue); - return false; - } - } - for (int i = 0; i < quarter; i++) { - T item = queue.poll(); - T correct = data[i]; - if (item.compareTo(correct) != 0) { - System.err.println(name + " YIKES!! " + item + " does not match FIFO item."); - Utils.handleError(data, queue); - return false; - } - if (!queue.validate() || (queue.size() != (half - (i + 1)))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, queue); - return false; - } - if (queue.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, queue); - return false; - } - } - for (int i = 0; i < quarter; i++) { - T item = data[i]; - boolean added = queue.offer(item); - if (!queue.validate() || (queue.size() != ((half - quarter) + (i + 1)))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, queue); - return false; - } - if (!added || !queue.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, queue); - return false; - } - } - for (int i = half; i < data.length; i++) { - T item = data[i]; - boolean added = queue.offer(item); - if (!queue.validate() || (queue.size() != (i + 1))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, queue); - return false; - } - if (!added || !queue.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, queue); - return false; - } - } - for (int i = 0; i < data.length; i++) { - T item = queue.poll(); - int idx = i; - if (idx < changeOver) { - idx = quarter + i; - } else if (idx >= changeOver && idx < half) { - idx = i - changeOver; - } - T correct = data[idx]; - if ((item.compareTo(correct) != 0)) { - System.err.println(name + " YIKES!! " + item + " does not match FIFO item."); - Utils.handleError(data, queue); - return false; - } - if (!queue.validate() || (queue.size() != (data.length - (i + 1)))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, queue); - return false; - } - if (queue.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, queue); - return false; - } - } - - if ((queue.size() != 0)) { - System.err.println(name + " YIKES!! a size mismatch."); - Utils.handleError(data, queue); - return false; - } - - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/SetTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/SetTest.java deleted file mode 100644 index f989017..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/SetTest.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.github.dunwu.algorithm.common; - -public class SetTest { - - public static > boolean testSet(ISet set, String name, T[] data, T _invalid) { - for (int i = 0; i < data.length; i++) { - T item = data[i]; - boolean added = set.add(item); - if (!set.validate() || (set.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, set); - return false; - } - if (!added || !set.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, set); - return false; - } - } - - boolean contains = set.contains(_invalid); - boolean removed = set.remove(_invalid); - if (contains || removed) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, set); - return false; - } - - int size = set.size(); - for (int i = 0; i < size; i++) { - T item = data[i]; - removed = set.remove(item); - if (!set.validate() || (set.size() != data.length - (i + 1))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, set); - return false; - } - if (!removed || set.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, set); - return false; - } - } - - // Add half, remove a quarter, add three-quarters, remove all - int quarter = data.length / 4; - int half = data.length / 2; - for (int i = 0; i < half; i++) { - T item = data[i]; - boolean added = set.add(item); - if (!set.validate() || (set.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, set); - return false; - } - if (!added || !set.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, set); - return false; - } - } - for (int i = (half - 1); i >= quarter; i--) { - T item = data[i]; - removed = set.remove(item); - if (!set.validate() || (set.size() != i)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, set); - return false; - } - if (!removed || set.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, set); - return false; - } - } - for (int i = quarter; i < data.length; i++) { - T item = data[i]; - boolean added = set.add(item); - if (!set.validate() || (set.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, set); - return false; - } - if (!added || !set.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, set); - return false; - } - } - for (int i = data.length - 1; i >= 0; i--) { - T item = data[i]; - removed = set.remove(item); - if (!set.validate() || (set.size() != i)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, set); - return false; - } - if ((!removed || set.contains(item))) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, set); - return false; - } - } - - if (set.size() != 0) { - System.err.println(name + " YIKES!! a size mismatch."); - Utils.handleError(data, set); - return false; - } - - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/StackTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/StackTest.java deleted file mode 100644 index 3601c5d..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/StackTest.java +++ /dev/null @@ -1,129 +0,0 @@ -package io.github.dunwu.algorithm.common; - -public class StackTest { - - public static > boolean testStack(IStack stack, String name, T[] data, T _invalid) { - for (int i = 0; i < data.length; i++) { - T item = data[i]; - boolean added = stack.push(item); - if (!stack.validate() || (stack.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, stack); - return false; - } - if (!added || item == null || !stack.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, stack); - return false; - } - } - - boolean contains = stack.contains(_invalid); - boolean removed = stack.remove(_invalid); - if (contains || removed) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, stack); - return false; - } - - int size = stack.size(); - for (int i = 0; i < size; i++) { - T item = stack.pop(); - T correct = data[data.length - (i + 1)]; - if ((item.compareTo(correct) != 0)) { - System.err.println(name + " YIKES!! " + item + " does not match LIFO item."); - Utils.handleError(data, stack); - return false; - } - if (!stack.validate() || (stack.size() != data.length - (i + 1))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, stack); - return false; - } - if (stack.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, stack); - return false; - } - } - - // Add half, remove a quarter, add three-quarters, remove all - int quarter = data.length / 4; - int half = data.length / 2; - for (int i = 0; i < half; i++) { - T item = data[i]; - boolean added = stack.push(item); - if (!stack.validate() || (stack.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, stack); - return false; - } - if (!added || item == null || !stack.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, stack); - return false; - } - } - for (int i = (half - 1); i >= quarter; i--) { - T item = stack.pop(); - T correct = data[i]; - if (item.compareTo(correct) != 0) { - System.err.println(name + " YIKES!! " + item + " does not match LIFO item."); - Utils.handleError(data, stack); - return false; - } - if (!stack.validate() || (stack.size() != i)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, stack); - return false; - } - if (stack.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, stack); - return false; - } - } - for (int i = quarter; i < data.length; i++) { - T item = data[i]; - boolean added = stack.push(item); - if (!stack.validate() || (stack.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, stack); - return false; - } - if (!added || item == null || !stack.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, stack); - return false; - } - } - for (int i = data.length - 1; i >= 0; i--) { - T item = stack.pop(); - T correct = data[i]; - if (item.compareTo(correct) != 0) { - System.err.println(name + " YIKES!! " + item + " does not match LIFO item."); - Utils.handleError(data, stack); - return false; - } - if (!stack.validate() || (stack.size() != i)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, stack); - return false; - } - if (stack.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, stack); - return false; - } - } - - if (stack.size() != 0) { - System.err.println(name + " YIKES!! a size mismatch."); - Utils.handleError(data, stack); - return false; - } - - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/SuffixTreeTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/SuffixTreeTest.java deleted file mode 100644 index 0eb4ebb..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/SuffixTreeTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.dunwu.algorithm.common; - -public class SuffixTreeTest { - - /** - * In computer science, a suffix tree (also called PAT tree or, in an earlier form, position tree) is a compressed - * trie containing all the suffixes of the given text as their keys and positions in the text as their values. - * Suffix trees allow particularly fast implementations of many important string operations. - * - * @param tree Suffix tree to test. - * @param test String to use in testing the suffix tree. - * @return True if the suffix tree passes it's invariants tests. - */ - public static boolean suffixTreeTest(ISuffixTree tree, String test) { - boolean exists = tree.doesSubStringExist(test); - if (!exists) { - System.err.println("YIKES!! " + test + " doesn't exists."); - Utils.handleError(test, tree); - return false; - } - - String failed = test + "Z"; - exists = tree.doesSubStringExist(failed); - if (exists) { - System.err.println("YIKES!! " + failed + " exists."); - Utils.handleError(failed, tree); - return false; - } - - String pass = test.substring(0, 6); - exists = tree.doesSubStringExist(pass); - if (!exists) { - System.err.println("YIKES!! " + pass + " doesn't exists."); - Utils.handleError(pass, tree); - return false; - } - - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/TreeTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/TreeTest.java deleted file mode 100644 index 4c6de6e..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/TreeTest.java +++ /dev/null @@ -1,122 +0,0 @@ -package io.github.dunwu.algorithm.common; - -public class TreeTest { - - public static > boolean testTree(ITree tree, Class type, String name, Integer[] data, - Integer _invalid) { - for (int i = 0; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - boolean added = tree.add(item); - if (!tree.validate() || (tree.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, tree); - return false; - } - if (!added || !tree.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, tree); - return false; - } - } - - T invalidItem = Utils.parseT(_invalid, type); - boolean contains = tree.contains(invalidItem); - T removed = tree.remove(invalidItem); - if (contains || removed != null) { - System.err.println(name + " invalidity check. contains=" + contains + " removed=" + removed); - Utils.handleError(_invalid, tree); - return false; - } - - int size = tree.size(); - for (int i = 0; i < size; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - removed = tree.remove(item); - if (!tree.validate() || (tree.size() != data.length - (i + 1))) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, tree); - return false; - } - if (removed == null || tree.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been removed."); - Utils.handleError(data, tree); - return false; - } - } - - // Add half, remove a quarter, add three-quarters - int quarter = data.length / 4; - int half = data.length / 2; - for (int i = 0; i < half; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - boolean added = tree.add(item); - if (!tree.validate() || (tree.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, tree); - return false; - } - if (!added || !tree.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, tree); - return false; - } - } - for (int i = (half - 1); i >= quarter; i--) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - removed = tree.remove(item); - if (!tree.validate() || (tree.size() != i)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, tree); - return false; - } - if (removed == null || tree.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, tree); - return false; - } - } - for (int i = quarter; i < data.length; i++) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - boolean added = tree.add(item); - if (!tree.validate() || (tree.size() != i + 1)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, tree); - return false; - } - if (!added || !tree.contains(item)) { - System.err.println(name + " YIKES!! " + item + " doesn't exists but has been added."); - Utils.handleError(data, tree); - return false; - } - } - for (int i = data.length - 1; i >= 0; i--) { - Integer value = data[i]; - T item = Utils.parseT(value, type); - removed = tree.remove(item); - if (!tree.validate() || (tree.size() != i)) { - System.err.println(name + " YIKES!! " + item + " caused a size mismatch."); - Utils.handleError(data, tree); - return false; - } - if (removed == null || tree.contains(item)) { - System.err.println(name + " YIKES!! " + item + " still exists but it has been remove."); - Utils.handleError(data, tree); - return false; - } - } - - if (tree.size() != 0) { - System.err.println(name + " YIKES!! a size mismatch."); - Utils.handleError(data, tree); - return false; - } - - return true; - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/Utils.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/Utils.java deleted file mode 100644 index 67b6d28..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/common/Utils.java +++ /dev/null @@ -1,140 +0,0 @@ -package io.github.dunwu.algorithm.common; - -import java.util.Arrays; -import java.util.Random; - -public class Utils { - - private static final Random RANDOM = new Random(); - - public static final T parseT(final Integer value, final Class type) { - T returnValue = null; - - if (type == null) { - throw new NullPointerException("Type can not be null"); - } else if (Integer.class.equals(type)) { - returnValue = type.cast(value); - } else if (String.class.equals(type)) { - returnValue = type.cast(String.valueOf(value)); - } else { - throw new IllegalArgumentException("Unsupported type " + type.getName()); - } - return returnValue; - } - - public static void handleError(Object obj) { - System.err.println("Object={\n" + obj.toString() + "\n}"); - throw new RuntimeException("Error in test."); - } - - public static void handleError(Object data, Object obj) { - System.err.println("Data={" + data + "}"); - System.err.println("Object={\n" + obj.toString() + "\n}"); - throw new RuntimeException("Error in test."); - } - - public static void handleError(Object[] data, Object obj) { - System.err.println("Data={"); - for (Object o : data) - System.err.print(o.toString() + ", "); - System.err.println("\n}"); - System.err.println("Object={\n" + obj.toString() + "\n}"); - throw new RuntimeException("Error in test."); - } - - public static TestData testData(int... integers) { - TestData data = new TestData(integers.length); - - StringBuilder builder = new StringBuilder(); - data.unsorted = new Integer[integers.length]; - java.util.Set set = new java.util.HashSet(); - builder.append("Array="); - for (int i = 0; i < integers.length; i++) { - Integer j = integers[i]; - data.unsorted[i] = j; - if (i != integers.length - 1) { builder.append(j).append(','); } - } - set.clear(); - set = null; - builder.append('\n'); - data.string = builder.toString(); - - data.sorted = Arrays.copyOf(data.unsorted, data.unsorted.length); - Arrays.sort(data.sorted); - - return data; - } - - public static TestData generateTestData(int data_size) { - TestData data = new TestData(data_size); - - StringBuilder builder = new StringBuilder(); - data.unsorted = new Integer[data_size]; - java.util.Set set = new java.util.HashSet(); - builder.append("Array="); - for (int i = 0; i < data_size; i++) { - Integer j = RANDOM.nextInt(data.random_size); - // Make sure there are no duplicates - boolean found = true; - while (found) { - if (set.contains(j)) { - j = RANDOM.nextInt(data.random_size); - } else { - data.unsorted[i] = j; - set.add(j); - found = false; - } - } - data.unsorted[i] = j; - if (i != data_size - 1) { builder.append(j).append(','); } - } - set.clear(); - set = null; - builder.append('\n'); - data.string = builder.toString(); - - data.sorted = Arrays.copyOf(data.unsorted, data.unsorted.length); - Arrays.sort(data.sorted); - - return data; - } - - public static class TestData { - - public int random_size = 0; - - public Integer invalid = 0; - - public Integer[] unsorted = null; - - public Integer[] sorted = null; - - public String string = null; - - public TestData(Integer[] _unsorted) { - this(_unsorted.length); - unsorted = _unsorted; - sorted = unsorted.clone(); - Arrays.sort(sorted); - setString(unsorted); - } - - public TestData(int size) { - this.random_size = 1000 * size; - this.invalid = random_size + 10; - } - - private static final String setString(Integer[] _unsorted) { - StringBuilder builder = new StringBuilder(); - builder.append("Array="); - for (int i = 0; i < _unsorted.length; i++) { - Integer d = _unsorted[i]; - if (i != _unsorted.length - 1) { builder.append(d).append(','); } - } - builder.append('\n'); - return builder.toString(); - } - - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java deleted file mode 100644 index 89c3766..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/DoubleLinkListTests.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import io.github.dunwu.algorithm.linkedlist.demo.DoublyLinkedList; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-01-26 - */ -public class DoubleLinkListTests { - - @Test - public void addTest() { - DoublyLinkedList list = new DoublyLinkedList<>(); - list.addLast(2); - list.addLast(3); - list.addFirst(1); - List result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); - } - - @Test - public void removeFirstTest() { - DoublyLinkedList list = new DoublyLinkedList<>(); - list.addLast(1); - list.addLast(1); - list.remove(new Integer(1)); - List result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1 }, result.toArray()); - - list.clear(); - list.addLast(1); - list.addLast(2); - list.addLast(3); - list.remove(new Integer(1)); - result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 2, 3 }, result.toArray()); - - list.clear(); - list.addLast(1); - list.addLast(2); - list.addLast(3); - list.remove(new Integer(3)); - result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2 }, result.toArray()); - - list.clear(); - list.addLast(1); - list.addLast(2); - list.remove(new Integer(4)); - result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2 }, result.toArray()); - } - - @Test - public void removeAllTest() { - DoublyLinkedList list = new DoublyLinkedList<>(); - list.addLast(1); - list.addLast(1); - list.addLast(1); - list.removeAll(1); - List result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] {}, result.toArray()); - - list.clear(); - list.addLast(1); - list.addLast(2); - list.addLast(3); - list.removeAll(4); - result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java deleted file mode 100644 index 15020fd..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/list/SingleLinkListTests.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.github.dunwu.algorithm.list; - -import io.github.dunwu.algorithm.linkedlist.demo.SinglyLinkedList; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-01-26 - */ -public class SingleLinkListTests { - - @Test - public void addTest() { - SinglyLinkedList list = new SinglyLinkedList<>(); - list.addLast(2); - list.addLast(3); - list.addFirst(1); - List result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); - } - - @Test - public void removeFirstTest() { - SinglyLinkedList list = new SinglyLinkedList<>(); - list.addLast(1); - list.addLast(1); - list.remove(new Integer(1)); - List result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1 }, result.toArray()); - - list.clear(); - list.addLast(1); - list.addLast(2); - list.addLast(3); - list.remove(new Integer(1)); - result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 2, 3 }, result.toArray()); - - list.clear(); - list.addLast(1); - list.addLast(2); - list.addLast(3); - list.remove(new Integer(3)); - result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2 }, result.toArray()); - - list.clear(); - list.addLast(1); - list.addLast(2); - list.remove(new Integer(4)); - result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2 }, result.toArray()); - } - - @Test - public void removeAllTest() { - SinglyLinkedList list = new SinglyLinkedList<>(); - list.addLast(1); - list.addLast(1); - list.addLast(1); - list.removeAll(1); - List result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] {}, result.toArray()); - - list.clear(); - list.addLast(1); - list.addLast(2); - list.addLast(3); - list.removeAll(4); - result = list.toList(); - System.out.println(result); - Assertions.assertArrayEquals(new Integer[] { 1, 2, 3 }, result.toArray()); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/search/SearchStrategyTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/search/SearchStrategyTest.java deleted file mode 100644 index 7aa8ca4..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/search/SearchStrategyTest.java +++ /dev/null @@ -1,98 +0,0 @@ -package io.github.dunwu.algorithm.search; - -import io.github.dunwu.algorithm.search.strategy.BinarySearch; -import io.github.dunwu.algorithm.search.strategy.OrderSearch; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.Random; - -// import io.github.dunwu.algorithm.util.ArrayUtil; - -/** - * 排序算法单元测试 如果需要打印每趟排序的结果,可以修改 logback.xml 中 - * 的 level 级别,改为 DEBUG, - * 日志就会打印 debug 信息。 - * - * @author Zhang Peng - */ -public class SearchStrategyTest { - - /** - * 随机样本一 - */ - private static Integer[] origin01; - - private static int expected01; - - /** - * 随机样本二 - */ - private static Integer[] origin02; - - private static int expected02; - - /** - * 随机样本三 - */ - private static Integer[] origin03; - - private static int expected03; - - /** - * 生成随机数组样本,并调用 JDK api 生成期望的有序数组 - */ - @BeforeAll - public static void beforeClass() { - Random random = new Random(); - - // 在 [0, 100] 间生成长度为 10 的不重复的随机数组 - origin01 = ArrayUtil.randomNoRepeatIntegerArray(0, 10, 10); - expected01 = random.nextInt(origin01.length); - - // 在 [0, 100] 间生成长度为 17 的不重复的随机数组 - origin02 = ArrayUtil.randomNoRepeatIntegerArray(0, 100, 20); - expected02 = random.nextInt(origin02.length); - - // 在 [0, 100] 间生成长度为 100 的不重复的随机数组 - origin03 = ArrayUtil.randomNoRepeatIntegerArray(0, 100, 100); - expected03 = random.nextInt(origin03.length); - } - - /** - * 每次执行 @Test 前都使用生成的随机样本初始化实际用于排序的数组 - */ - @BeforeEach - public void before() { - } - - @Test - public void testOrderSearch() { - SearchStrategy strategy = new SearchStrategy(new OrderSearch()); - executeSearch(strategy); - } - - /** - * 注入 BinarySearch,执行对三个样本的排序测试 - */ - private void executeSearch(SearchStrategy strategy) { - int target01 = strategy.find(origin01, origin01[expected01]); - Assertions.assertEquals(expected01, target01); - - int target02 = strategy.find(origin02, origin02[expected02]); - Assertions.assertEquals(expected02, target02); - - int target03 = strategy.find(origin03, origin03[expected03]); - Assertions.assertEquals(expected03, target03); - } - - @Test - public void testBinarySearch() { - SearchStrategy strategy = new SearchStrategy(new BinarySearch()); - executeSearch(strategy); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java deleted file mode 100644 index 2783f81..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java +++ /dev/null @@ -1,140 +0,0 @@ -package io.github.dunwu.algorithm.sort; - -import io.github.dunwu.algorithm.sort.strategy.BubbleSort; -import io.github.dunwu.algorithm.sort.strategy.BubbleSort2; -import io.github.dunwu.algorithm.sort.strategy.HeapSort; -import io.github.dunwu.algorithm.sort.strategy.InsertSort; -import io.github.dunwu.algorithm.sort.strategy.MergeSort; -import io.github.dunwu.algorithm.sort.strategy.QuickSort; -import io.github.dunwu.algorithm.sort.strategy.SelectionSort; -import io.github.dunwu.algorithm.sort.strategy.ShellSort; -import io.github.dunwu.algorithm.util.ArrayUtil; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; - -/** - * 排序算法单元测试 如果需要打印每趟排序的结果,可以修改 logback.xml 中 - * 的 level 级别,改为 DEBUG, - * 日志就会打印 debug 信息。 - * - * @author Zhang Peng - */ -public class SortStrategyTest { - - /** - * 随机样本一 - */ - private static Integer[] s1; - private static Integer[] t1; - private static Integer[] e1; - - /** - * 随机样本二 - */ - private static Integer[] s2; - private static Integer[] t2; - private static Integer[] e2; - - /** - * 随机样本三 - */ - private static Integer[] s3; - private static Integer[] t3; - private static Integer[] e3; - - /** - * 生成随机数组样本,并调用 JDK api 生成期望的有序数组 - */ - @BeforeAll - public static void beforeClass() { - // 在 [0, 100] 间生成长度为 10 的存在重复的随机数组 - s1 = ArrayUtil.randomRepeatIntegerArray(0, 10, 5); - e1 = Arrays.copyOf(s1, s1.length); - Arrays.sort(e1); - - // 在 [0, 100] 间生成长度为 17 的不重复的随机数组 - s2 = ArrayUtil.randomNoRepeatIntegerArray(0, 100, 10); - e2 = Arrays.copyOf(s2, s2.length); - Arrays.sort(e2); - - // 在 [0, 100] 间生成长度为 100 的不重复的随机数组 - s3 = ArrayUtil.randomNoRepeatIntegerArray(0, 100, 30); - e3 = Arrays.copyOf(s3, s3.length); - Arrays.sort(e3); - } - - /** - * 注入 SortStrategy,执行对三个样本的排序测试 - */ - private void executeSort(SortStrategy strategy) { - strategy.sort(t1); - Assertions.assertArrayEquals(e1, t1); - strategy.sort(t2); - Assertions.assertArrayEquals(e2, t2); - strategy.sort(t3); - Assertions.assertArrayEquals(e3, t3); - } - - /** - * 每次执行 @Test 前都使用生成的随机样本初始化实际用于排序的数组 - */ - @BeforeEach - public void before() { - t1 = Arrays.copyOf(s1, s1.length); - t2 = Arrays.copyOf(s2, s2.length); - t3 = Arrays.copyOf(s3, s3.length); - } - - @Test - public void testBubbleSort() { - SortStrategy strategy = new SortStrategy(new BubbleSort()); - executeSort(strategy); - } - - @Test - public void testBubbleSort2() { - SortStrategy strategy = new SortStrategy(new BubbleSort2()); - executeSort(strategy); - } - - @Test - public void testQuickSort() { - SortStrategy strategy = new SortStrategy(new QuickSort()); - executeSort(strategy); - } - - @Test - public void testInsertSort() { - SortStrategy strategy = new SortStrategy(new InsertSort()); - executeSort(strategy); - } - - @Test - public void testShellSort() { - SortStrategy strategy = new SortStrategy(new ShellSort()); - executeSort(strategy); - } - - @Test - public void testSelectionSort() { - SortStrategy strategy = new SortStrategy(new SelectionSort()); - executeSort(strategy); - } - - @Test - public void testHeapSort() { - SortStrategy strategy = new SortStrategy(new HeapSort()); - executeSort(strategy); - } - - @Test - public void testMergeSort() { - SortStrategy strategy = new SortStrategy(new MergeSort()); - executeSort(strategy); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/AddBinaryTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/AddBinaryTest.java deleted file mode 100644 index 993ada9..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/AddBinaryTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.dunwu.algorithm.str; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class AddBinaryTest { - - @Test - public void test() { - Assertions.assertEquals("100", AddBinary.addBinary("11", "1")); - Assertions.assertEquals("10101", AddBinary.addBinary("1010", "1011")); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ImplementStrstrTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ImplementStrstrTest.java deleted file mode 100644 index ff65cdf..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ImplementStrstrTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.github.dunwu.algorithm.str; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class ImplementStrstrTest { - - @Test - public void test() { - Assertions.assertEquals(0, ImplementStrstr.strStr("", "")); - Assertions.assertEquals(-1, ImplementStrstr.strStr("aaa", "aaaa")); - Assertions.assertEquals(0, ImplementStrstr.strStr("aaa", "")); - Assertions.assertEquals(2, ImplementStrstr.strStr("hello", "ll")); - Assertions.assertEquals(-1, ImplementStrstr.strStr("aaaaa", "bba")); - Assertions.assertEquals(1, ImplementStrstr.strStr("mississippi", "issi")); - Assertions.assertEquals(9, ImplementStrstr.strStr("mississippi", "pi")); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/LongestCommonPrefixTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/LongestCommonPrefixTest.java deleted file mode 100644 index 08d8729..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/LongestCommonPrefixTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.github.dunwu.algorithm.str; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class LongestCommonPrefixTest { - - @Test - public void test() { - String[] strs1 = { "flower", "flow", "flight" }; - String[] strs2 = { "dog", "racecar", "car" }; - - Assertions.assertEquals("fl", LongestCommonPrefix.longestCommonPrefix(strs1)); - Assertions.assertEquals("", LongestCommonPrefix.longestCommonPrefix(strs2)); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseStringTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseStringTest.java deleted file mode 100644 index 70da08d..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseStringTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.dunwu.algorithm.str; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class ReverseStringTest { - - @Test - public void test() { - Assertions.assertEquals("olleh", ReverseString.reverseString("hello")); - Assertions.assertEquals("amanaP :lanac a ,nalp a ,nam A", - ReverseString.reverseString("A man, a plan, a canal: Panama")); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseWordsInAString3Test.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseWordsInAString3Test.java deleted file mode 100644 index 492b368..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseWordsInAString3Test.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.dunwu.algorithm.str; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class ReverseWordsInAString3Test { - - @Test - public void test() { - Assertions.assertEquals("s'teL ekat edoCteeL tsetnoc", - ReverseWordsInAString3.reverseWords("Let's take LeetCode contest")); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseWordsInAStringTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseWordsInAStringTest.java deleted file mode 100644 index 212d0dd..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/str/ReverseWordsInAStringTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.dunwu.algorithm.str; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2018-11-05 - */ -public class ReverseWordsInAStringTest { - - @Test - public void test() { - Assertions.assertEquals("blue is sky the", ReverseWordsInAString.reverseWords("the sky is blue")); - Assertions.assertEquals(" ", ReverseWordsInAString.reverseWords(" ")); - Assertions.assertEquals("1", ReverseWordsInAString.reverseWords("1 ")); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/string/StringAlgorithmTest.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/string/StringAlgorithmTest.java deleted file mode 100644 index 7aa1f30..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/string/StringAlgorithmTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.github.dunwu.algorithm.string; - -import io.github.dunwu.algorithm.str.StringAlgorithm; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author Zhang Peng - * @since 2020-01-18 - */ -public class StringAlgorithmTest { - - @Test - public void lengthOfLongestSubstring() { - int len = StringAlgorithm.lengthOfLongestSubstring("abcabcbb"); - Assertions.assertEquals(3, len); - - len = StringAlgorithm.lengthOfLongestSubstring("bbbbb"); - Assertions.assertEquals(1, len); - - len = StringAlgorithm.lengthOfLongestSubstring("pwwkew"); - Assertions.assertEquals(3, len); - } - - @Test - public void longestCommonPrefix() { - String str = StringAlgorithm.longestCommonPrefix(new String[] { "flower", "flow", "flight" }); - Assertions.assertEquals("fl", str); - - str = StringAlgorithm.longestCommonPrefix(new String[] { "dog", "racecar", "car" }); - Assertions.assertEquals("", str); - } - - @Test - public void checkInclusion() { - boolean result = StringAlgorithm.checkInclusion("ab", "eidbaooo"); - Assertions.assertEquals(true, result); - - result = StringAlgorithm.checkInclusion("ab", "eidboaoo"); - Assertions.assertEquals(false, result); - } - - @Test - public void multiply() { - String result = StringAlgorithm.multiply("2", "3"); - Assertions.assertEquals("6", result); - - result = StringAlgorithm.multiply("333", "2"); - Assertions.assertEquals("666", result); - - result = StringAlgorithm.multiply("123", "456"); - Assertions.assertEquals("56088", result); - - result = StringAlgorithm.multiply("123456789", "987654321"); - Assertions.assertEquals("121932631112635269", result); - - result = StringAlgorithm.multiply("498828660196", "840477629533"); - Assertions.assertEquals("419254329864656431168468", result); - } - - @Test - public void add() { - String result = StringAlgorithm.add("100000000000000000000", "8888"); - Assertions.assertEquals("100000000000000008888", result); - - result = StringAlgorithm.add("1368", "9120"); - Assertions.assertEquals("10488", result); - } - - @Test - public void reverseWords() { - String result = StringAlgorithm.reverseWords("the sky is blue"); - Assertions.assertEquals("blue is sky the", result); - - result = StringAlgorithm.reverseWords(" hello world! "); - Assertions.assertEquals("world! hello", result); - - result = StringAlgorithm.reverseWords("a good example"); - Assertions.assertEquals("example good a", result); - } - - @Test - public void simplifyPath() { - String result = StringAlgorithm.simplifyPath("/home/"); - Assertions.assertEquals("/home", result); - - result = StringAlgorithm.simplifyPath("/../"); - Assertions.assertEquals("/", result); - - result = StringAlgorithm.simplifyPath("/home//foo/"); - Assertions.assertEquals("/home/foo", result); - - result = StringAlgorithm.simplifyPath("/a/./b/../../c/"); - Assertions.assertEquals("/c", result); - } - -} diff --git a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeTests.java b/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeTests.java deleted file mode 100644 index f53c916..0000000 --- a/codes/algorithm/src/test/java/io/github/dunwu/algorithm/tree/BTreeTests.java +++ /dev/null @@ -1,66 +0,0 @@ -package io.github.dunwu.algorithm.tree; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * @author Zhang Peng - * @since 2020-01-28 - */ -public class BTreeTests { - - @Test - @DisplayName("二叉树的最大深度") - public void maxDepthTest() { - BTree tree = BTree.build(1, 2, 3, 4, 5); - Assertions.assertEquals(3, tree.maxDepth()); - } - - @Test - @DisplayName("二叉树的最小深度") - public void minDepthTest() { - BTree tree = BTree.build(3, 9, 20, null, null, 15, 7); - Assertions.assertEquals(2, tree.minDepth()); - - tree = BTree.build(1, 2); - Assertions.assertEquals(2, tree.minDepth()); - } - - @Test - @DisplayName("判断两颗二叉树是否完全一致") - public void isEqualsTest() { - BTree tree1 = BTree.build(1, 2, 3); - BTree tree2 = BTree.build(1, 2, 3); - Assertions.assertTrue(BTree.isEquals(tree1, tree2)); - - tree1 = BTree.build(1, 2, 1); - tree2 = BTree.build(1, 1, 2); - Assertions.assertFalse(BTree.isEquals(tree1, tree2)); - } - - @Test - @DisplayName("广度优先搜索(BFS)") - public void levelOrderBottomTest() { - BTree tree = BTree.build(3, 9, 20, null, null, 15, 7); - List> lists = new ArrayList<>(); - lists.add(Collections.singletonList(3)); - lists.add(Arrays.asList(9, 20)); - lists.add(Arrays.asList(15, 7)); - Assertions.assertIterableEquals(lists, tree.levelOrderLists()); - } - - @Test - @DisplayName("判断两颗二叉树的叶子节点是否相似") - public void isLeafSimilarTest() { - BTree tree1 = BTree.build(3, 5, 1, 6, 2, 9, 8, null, null, 7, 4); - BTree tree2 = BTree.build(3, 5, 1, 6, 7, 4, 2, null, null, null, null, null, null, 9, 8); - Assertions.assertTrue(BTree.isLeafSimilar(tree1, tree2)); - } - -} diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js deleted file mode 100644 index f18b41b..0000000 --- a/docs/.vuepress/config.js +++ /dev/null @@ -1,172 +0,0 @@ -const htmlModules = require('./config/htmlModules.js') - -module.exports = { - port: '4000', - dest: 'docs/.temp', - base: '/algorithm-tutorial/', // 默认'/'。如果你想将你的网站部署到如 https://foo.github.io/bar/,那么 base 应该被设置成 "/bar/",(否则页面将失去样式等文件) - title: 'ALGORITHM-TUTORIAL', - description: '☕ algorithm-tutorial 是一个数据结构与算法教程。', - theme: 'vdoing', // 使用依赖包主题 - // theme: require.resolve('../../vdoing'), // 使用本地主题 - head: [ - // 注入到页面 中的标签,格式[tagName, { attrName: attrValue }, innerHTML?] - ['link', { rel: 'icon', href: '/img/favicon.ico' }], //favicons,资源放在public文件夹 - ['meta', { name: 'keywords', content: 'vuepress,theme,blog,vdoing' }], - ['meta', { name: 'theme-color', content: '#11a8cd' }], // 移动浏览器主题颜色 - ], - markdown: { - // lineNumbers: true, - extractHeaders: ['h2', 'h3', 'h4', 'h5', 'h6'], // 提取标题到侧边栏的级别,默认['h2', 'h3'] - externalLinks: { - target: '_blank', - rel: 'noopener noreferrer', - }, - }, - // 主题配置 - themeConfig: { - nav: [], - sidebarDepth: 2, // 侧边栏显示深度,默认1,最大2(显示到h3标题) - logo: 'https://raw.githubusercontent.com/dunwu/images/master/common/dunwu-logo.png', // 导航栏logo - repo: 'dunwu/algorithm-tutorial', // 导航栏右侧生成Github链接 - searchMaxSuggestions: 10, // 搜索结果显示最大数 - lastUpdated: '上次更新', // 更新的时间,及前缀文字 string | boolean (取值为git提交时间) - - docsDir: 'docs', // 编辑的文件夹 - editLinks: true, // 编辑链接 - editLinkText: '📝 帮助改善此页面!', - - // 以下配置是Vdoing主题改动的和新增的配置 - sidebar: { mode: 'structuring', collapsable: false }, // 侧边栏 'structuring' | { mode: 'structuring', collapsable: Boolean} | 'auto' | 自定义 温馨提示:目录页数据依赖于结构化的侧边栏数据,如果你不设置为'structuring',将无法使用目录页 - - // sidebarOpen: false, // 初始状态是否打开侧边栏,默认true - updateBar: { - // 最近更新栏 - showToArticle: true, // 显示到文章页底部,默认true - // moreArticle: '/archives' // “更多文章”跳转的页面,默认'/archives' - }, - // titleBadge: false, // 文章标题前的图标是否显示,默认true - // titleBadgeIcons: [ // 文章标题前图标的地址,默认主题内置图标 - // '图标地址1', - // '图标地址2' - // ], - // bodyBgImg: [ - // 'https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175828.jpeg', - // 'https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175845.jpeg', - // 'https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200507175846.jpeg' - // ], // body背景大图,默认无。 单张图片 String || 多张图片 Array, 多张图片时每隔15秒换一张。 - - // categoryText: '随笔', // 碎片化文章(_posts文件夹的文章)预设生成的分类值,默认'随笔' - - // contentBgStyle: 1, - - category: true, // 是否打开分类功能,默认true。 如打开,会做的事情有:1. 自动生成的frontmatter包含分类字段 2.页面中显示与分类相关的信息和模块 3.自动生成分类页面(在@pages文件夹)。如关闭,则反之。 - tag: true, // 是否打开标签功能,默认true。 如打开,会做的事情有:1. 自动生成的frontmatter包含标签字段 2.页面中显示与标签相关的信息和模块 3.自动生成标签页面(在@pages文件夹)。如关闭,则反之。 - archive: true, // 是否打开归档功能,默认true。 如打开,会做的事情有:1.自动生成归档页面(在@pages文件夹)。如关闭,则反之。 - - author: { - // 文章默认的作者信息,可在md文件中单独配置此信息 String | {name: String, href: String} - name: 'dunwu', // 必需 - href: 'https://github.com/dunwu', // 可选的 - }, - social: { - // 社交图标,显示于博主信息栏和页脚栏 - // iconfontCssFile: '//at.alicdn.com/t/font_1678482_u4nrnp8xp6g.css', // 可选,阿里图标库在线css文件地址,对于主题没有的图标可自由添加 - icons: [ - { - iconClass: 'icon-youjian', - title: '发邮件', - link: 'mailto:forbreak@163.com', - }, - { - iconClass: 'icon-github', - title: 'GitHub', - link: 'https://github.com/dunwu', - }, - ], - }, - footer: { - // 页脚信息 - createYear: 2019, // 博客创建年份 - copyrightInfo: '钝悟(dunwu) | CC-BY-SA-4.0', // 博客版权信息,支持a标签 - }, - htmlModules, - }, - - // 插件 - plugins: [ - [ - require('./plugins/love-me'), - { - // 鼠标点击爱心特效 - color: '#11a8cd', // 爱心颜色,默认随机色 - excludeClassName: 'theme-vdoing-content', // 要排除元素的class, 默认空'' - }, - ], - - ['fulltext-search'], // 全文搜索 - - // ['thirdparty-search', { // 可以添加第三方搜索链接的搜索框(原官方搜索框的参数仍可用) - // thirdparty: [ // 可选,默认 [] - // { - // title: '在GitHub中搜索', - // frontUrl: 'https://github.com/search?q=', // 搜索链接的前面部分 - // behindUrl: '' // 搜索链接的后面部分,可选,默认 '' - // }, - // { - // title: '在npm中搜索', - // frontUrl: 'https://www.npmjs.com/search?q=', - // }, - // { - // title: '在Bing中搜索', - // frontUrl: 'https://cn.bing.com/search?q=' - // } - // ] - // }], - - [ - 'one-click-copy', - { - // 代码块复制按钮 - copySelector: ['div[class*="language-"] pre', 'div[class*="aside-code"] aside'], // String or Array - copyMessage: '复制成功', // default is 'Copy successfully and then paste it for use.' - duration: 1000, // prompt message display time. - showInMobile: false, // whether to display on the mobile side, default: false. - }, - ], - [ - 'demo-block', - { - // demo演示模块 https://github.com/xiguaxigua/vuepress-plugin-demo-block - settings: { - // jsLib: ['http://xxx'], // 在线示例(jsfiddle, codepen)中的js依赖 - // cssLib: ['http://xxx'], // 在线示例中的css依赖 - // vue: 'https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js', // 在线示例中的vue依赖 - jsfiddle: false, // 是否显示 jsfiddle 链接 - codepen: true, // 是否显示 codepen 链接 - horizontal: false, // 是否展示为横向样式 - }, - }, - ], - [ - 'vuepress-plugin-zooming', // 放大图片 - { - selector: '.theme-vdoing-content img:not(.no-zoom)', - options: { - bgColor: 'rgba(0,0,0,0.6)', - }, - }, - ], - [ - '@vuepress/last-updated', // "上次更新"时间格式 - { - transformer: (timestamp, lang) => { - const dayjs = require('dayjs') // https://day.js.org/ - return dayjs(timestamp).format('YYYY/MM/DD, HH:mm:ss') - }, - }, - ], - ], - - // 监听文件变化并重新构建 - extraWatchFiles: ['.vuepress/config.js', '.vuepress/config/htmlModules.js'], -} diff --git a/docs/.vuepress/config/baiduCode.js b/docs/.vuepress/config/baiduCode.js deleted file mode 100644 index 9dc5fc1..0000000 --- a/docs/.vuepress/config/baiduCode.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = ''; diff --git a/docs/.vuepress/config/htmlModules.js b/docs/.vuepress/config/htmlModules.js deleted file mode 100644 index 6ba3782..0000000 --- a/docs/.vuepress/config/htmlModules.js +++ /dev/null @@ -1,52 +0,0 @@ -/** 插入自定义html模块 (可用于插入广告模块等) - * { - * homeSidebarB: htmlString, 首页侧边栏底部 - * - * sidebarT: htmlString, 全局左侧边栏顶部 - * sidebarB: htmlString, 全局左侧边栏底部 - * - * pageT: htmlString, 全局页面顶部 - * pageB: htmlString, 全局页面底部 - * pageTshowMode: string, 页面顶部-显示方式:未配置默认全局;'article' => 仅文章页①; 'custom' => 仅自定义页① - * pageBshowMode: string, 页面底部-显示方式:未配置默认全局;'article' => 仅文章页①; 'custom' => 仅自定义页① - * - * windowLB: htmlString, 全局左下角② - * windowRB: htmlString, 全局右下角② - * } - * - * ①注:在.md文件front matter配置`article: false`的页面是自定义页,未配置的默认是文章页(首页除外)。 - * ②注:windowLB 和 windowRB:1.展示区块最大宽高200px*400px。2.请给自定义元素定一个不超过200px*400px的宽高。3.在屏幕宽度小于960px时无论如何都不会显示。 - */ - -module.exports = { - // 万维广告 - pageB: ` -
- - `, - windowRB: ` -
- - `, -} - -// module.exports = { -// homeSidebarB: `
自定义模块测试
`, -// sidebarT: `
自定义模块测试
`, -// sidebarB: `
自定义模块测试
`, -// pageT: `
自定义模块测试
`, -// pageB: `
自定义模块测试
`, -// windowLB: `
自定义模块测试
`, -// windowRB: `
自定义模块测试
`, -// } diff --git a/docs/.vuepress/config/sidebar.js b/docs/.vuepress/config/sidebar.js deleted file mode 100644 index 9c97278..0000000 --- a/docs/.vuepress/config/sidebar.js +++ /dev/null @@ -1,105 +0,0 @@ -// !!!注:此文件没有使用到,仅用于测试和侧边栏数据格式的参考。 - -// 侧边栏 -module.exports = { - '/01.前端/': [ - { - title: 'JavaScript', - collapsable: false, //是否可折叠,可选的,默认true - children: [ - ['01.JavaScript/01.JavaScript中的名词概念','JavaScript中的名词概念'], - ['01.JavaScript/02.数据类型转换','数据类型转换'], - ['01.JavaScript/03.ES5面向对象','ES5面向对象'], - ['01.JavaScript/04.ES6面向对象','ES6面向对象'], - ['01.JavaScript/05.new命令原理','new命令原理'], - ['01.JavaScript/06.多种数组去重性能对比','多种数组去重性能对比'], - ] - }, - ], - '/02.页面/': [ - { - title: 'html-css', - collapsable: false, - children: [ - ['01.html-css/00.flex布局语法','flex布局语法'], - ['01.html-css/01.flex布局案例-基础','flex布局案例-基础'], - ['01.html-css/02.flex布局案例-骰子','flex布局案例-骰子'], - ['01.html-css/03.flex布局案例-网格布局','flex布局案例-网格布局'], - ['01.html-css/04.flex布局案例-圣杯布局','flex布局案例-圣杯布局'], - ['01.html-css/05.flex布局案例-输入框布局','flex布局案例-输入框布局'], - ['01.html-css/06.CSS3之transform过渡','CSS3之transform过渡'], - ['01.html-css/07.CSS3之animation动画','CSS3之animation动画'], - ] - }, - ], - '/03.技术杂谈/': [ - { - title: '技术杂谈', - collapsable: false, //是否可折叠,可选的,默认true - sidebarDepth: 2, // 深度,可选的, 默认值是 1 - children: [ - ['01.Git使用手册','Git使用手册'], // 同 {path: '01.Git使用手册', title: 'Git使用文档'} - ['02.GitHub高级搜索技巧','GitHub高级搜索技巧'], - ['03.Markdown使用教程','Markdown使用教程'], - ['04.npm常用命令','npm常用命令'], - ['05.yaml语言教程','yaml语言教程'], - ['06.解决百度无法收录搭建在GitHub上的个人博客的问题','解决百度无法收录搭建在GitHub上的个人博客的问题'], - ['07.使用Gitalk实现静态博客无后台评论系统','使用Gitalk实现静态博客无后台评论系统'], - ] - } - ], - '/04.其他/': [ - { - title: '学习', - collapsable: false, - children: [ - ['01.学习/01.学习网站','学习网站'], - ['01.学习/02.学习效率低,忘性很大怎么办?','学习效率低,忘性很大怎么办?'], - ] - }, - { - title: '学习笔记', - collapsable: false, - children: [ - ['02.学习笔记/01.小程序笔记','小程序笔记'], - ] - }, - { - title: '面试', - collapsable: false, //是否可折叠,可选的,默认true - children: [ - ['03.面试/01.面试问题集锦','面试问题集锦'], - ] - }, - ['01.在线工具','在线工具'], - ['02.友情链接','友情链接'], - ], - // '/': [ // 在最后定义,在没有单独设置侧边栏时统一使用这个侧边栏 - // '', - // 'git', - // 'github', - // 'markdown', - // 'study', - // 'interview' - // // '/', - // // { - // // title: 'foo', // 标题,必要的 - // // path: '/foo/', // 标题的路径,可选的, 应该是一个绝对路径 - // // collapsable: false, // 是否可折叠,可选的,默认true - // // sidebarDepth: 1, // 深度,可选的, 默认值是 1 - // // children: [ - // // ['foo/', '子页1'], - // // 'foo/1', - // // 'foo/2', - // // ] - // // }, - // // { - // // title: 'bar', - // // children: [ - // // ['bar/', '子页2'], - // // 'bar/3', - // // 'bar/4', - // // ] - // // } - // ], -} diff --git a/docs/.vuepress/enhanceApp.js b/docs/.vuepress/enhanceApp.js deleted file mode 100644 index 6dd9f98..0000000 --- a/docs/.vuepress/enhanceApp.js +++ /dev/null @@ -1,64 +0,0 @@ -// import vue from 'vue/dist/vue.esm.browser' -export default ({ - Vue, // VuePress 正在使用的 Vue 构造函数 - options, // 附加到根实例的一些选项 - router, // 当前应用的路由实例 - siteData // 站点元数据 -}) => { - try { - document && integrateGitalk(router) - } catch (e) { - console.error(e.message) - } -} - -// 集成 Gitalk 评论插件 -function integrateGitalk(router) { - const linkGitalk = document.createElement('link') - linkGitalk.href = 'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css' - linkGitalk.rel = 'stylesheet' - document.body.appendChild(linkGitalk) - const scriptGitalk = document.createElement('script') - scriptGitalk.src = 'https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js' - document.body.appendChild(scriptGitalk) - - router.afterEach((to) => { - if (scriptGitalk.onload) { - loadGitalk(to) - } else { - scriptGitalk.onload = () => { - loadGitalk(to) - } - } - }) - - function loadGitalk(to) { - let commentsContainer = document.getElementById('gitalk-container') - if (!commentsContainer) { - commentsContainer = document.createElement('div') - commentsContainer.id = 'gitalk-container' - commentsContainer.classList.add('content') - } - const $page = document.querySelector('.page') - if ($page) { - $page.appendChild(commentsContainer) - if (typeof Gitalk !== 'undefined' && Gitalk instanceof Function) { - renderGitalk(to.fullPath) - } - } - } - function renderGitalk(fullPath) { - console.info(fullPath) - const gitalk = new Gitalk({ - clientID: '8772d9c11ed3dc0b8922', - clientSecret: '7c6d2d583ff9437f5405bf9479e08db63d3a75fb', // come from github development - repo: 'blog', - owner: 'dunwu', - admin: ['dunwu'], - id: 'comment', - distractionFreeMode: false, - language: 'zh-CN', - }) - gitalk.render('gitalk-container') - } -} diff --git a/docs/.vuepress/plugins/love-me/index.js b/docs/.vuepress/plugins/love-me/index.js deleted file mode 100644 index 67f5ea9..0000000 --- a/docs/.vuepress/plugins/love-me/index.js +++ /dev/null @@ -1,12 +0,0 @@ -const path = require('path') -const LoveMyPlugin = (options = {}) => ({ - define() { - const COLOR = - options.color || - 'rgb(' + ~~(255 * Math.random()) + ',' + ~~(255 * Math.random()) + ',' + ~~(255 * Math.random()) + ')' - const EXCLUDECLASS = options.excludeClassName || '' - return { COLOR, EXCLUDECLASS } - }, - enhanceAppFiles: [path.resolve(__dirname, 'love-me.js')], -}) -module.exports = LoveMyPlugin diff --git a/docs/.vuepress/plugins/love-me/love-me.js b/docs/.vuepress/plugins/love-me/love-me.js deleted file mode 100644 index f93855e..0000000 --- a/docs/.vuepress/plugins/love-me/love-me.js +++ /dev/null @@ -1,62 +0,0 @@ -export default () => { - if (typeof window !== "undefined") { - (function(e, t, a) { - function r() { - for (var e = 0; e < s.length; e++) s[e].alpha <= 0 ? (t.body.removeChild(s[e].el), s.splice(e, 1)) : (s[e].y--, s[e].scale += .004, s[e].alpha -= .013, s[e].el.style.cssText = "left:" + s[e].x + "px;top:" + s[e].y + "px;opacity:" + s[e].alpha + ";transform:scale(" + s[e].scale + "," + s[e].scale + ") rotate(45deg);background:" + s[e].color + ";z-index:99999"); - requestAnimationFrame(r) - } - function n() { - var t = "function" == typeof e.onclick && e.onclick; - - e.onclick = function(e) { - // 过滤指定元素 - let mark = true; - EXCLUDECLASS && e.path && e.path.forEach((item) =>{ - if(item.nodeType === 1) { - typeof item.className === 'string' && item.className.indexOf(EXCLUDECLASS) > -1 ? mark = false : '' - } - }) - - if(mark) { - t && t(), - o(e) - } - } - } - function o(e) { - var a = t.createElement("div"); - a.className = "heart", - s.push({ - el: a, - x: e.clientX - 5, - y: e.clientY - 5, - scale: 1, - alpha: 1, - color: COLOR - }), - t.body.appendChild(a) - } - function i(e) { - var a = t.createElement("style"); - a.type = "text/css"; - try { - a.appendChild(t.createTextNode(e)) - } catch(t) { - a.styleSheet.cssText = e - } - t.getElementsByTagName("head")[0].appendChild(a) - } - // function c() { - // return "rgb(" + ~~ (255 * Math.random()) + "," + ~~ (255 * Math.random()) + "," + ~~ (255 * Math.random()) + ")" - // } - var s = []; - e.requestAnimationFrame = e.requestAnimationFrame || e.webkitRequestAnimationFrame || e.mozRequestAnimationFrame || e.oRequestAnimationFrame || e.msRequestAnimationFrame || - function(e) { - setTimeout(e, 1e3 / 60) - }, - i(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"), - n(), - r() - })(window, document) - } -} \ No newline at end of file diff --git a/docs/.vuepress/styles/index.styl b/docs/.vuepress/styles/index.styl deleted file mode 100644 index 3113dd6..0000000 --- a/docs/.vuepress/styles/index.styl +++ /dev/null @@ -1,93 +0,0 @@ -.home-wrapper .banner .banner-conent .hero h1{ - font-size 2.8rem!important -} -// 文档中适配 -table - width auto -.page >*:not(.footer),.card-box - box-shadow: none!important - -.page - @media (min-width $contentWidth + 80) - padding-top $navbarHeight!important -.home-wrapper .banner .banner-conent - padding 0 2.9rem - box-sizing border-box -.home-wrapper .banner .slide-banner .slide-banner-wrapper .slide-item a - h2 - margin-top 2rem - font-size 1.2rem!important - p - padding 0 1rem - -// 评论区颜色重置 -.gt-container - .gt-ico-tip - &::after - content: '。( Win + . ) or ( ⌃ + ⌘ + ␣ ) open Emoji' - color: #999 - .gt-meta - border-color var(--borderColor)!important - .gt-comments-null - color var(--textColor) - opacity .5 - .gt-header-textarea - color var(--textColor) - background rgba(180,180,180,0.1)!important - .gt-btn - border-color $accentColor!important - background-color $accentColor!important - .gt-btn-preview - background-color rgba(255,255,255,0)!important - color $accentColor!important - a - color $accentColor!important - .gt-svg svg - fill $accentColor!important - .gt-comment-content,.gt-comment-admin .gt-comment-content - background-color rgba(150,150,150,0.1)!important - &:hover - box-shadow 0 0 25px rgba(150,150,150,.5)!important - .gt-comment-body - color var(--textColor)!important - - -// qq徽章 -.qq - position: relative; -.qq::after - content: "可撩"; - background: $accentColor; - color:#fff; - padding: 0 5px; - border-radius: 10px; - font-size:12px; - position: absolute; - top: -4px; - right: -35px; - transform:scale(0.85); - -// demo模块图标颜色 -body .vuepress-plugin-demo-block__wrapper - &,.vuepress-plugin-demo-block__display - border-color rgba(160,160,160,.3) - .vuepress-plugin-demo-block__footer:hover - .vuepress-plugin-demo-block__expand::before - border-top-color: $accentColor !important; - border-bottom-color: $accentColor !important; - svg - fill: $accentColor !important; - - -// 全文搜索框 -.suggestions - overflow: auto - max-height: calc(100vh - 6rem) - @media (max-width: 719px) { - width: 90vw; - min-width: 90vw!important; - margin-right: -20px; - } - .highlight - color: $accentColor - font-weight: bold diff --git a/docs/.vuepress/styles/palette.styl b/docs/.vuepress/styles/palette.styl deleted file mode 100644 index d98e697..0000000 --- a/docs/.vuepress/styles/palette.styl +++ /dev/null @@ -1,62 +0,0 @@ - -// 原主题变量已弃用,以下是vdoing使用的变量,你可以在这个文件内修改它们。 - -//***vdoing主题-变量***// - -// // 颜色 - -// $bannerTextColor = #fff // 首页banner区(博客标题)文本颜色 -// $accentColor = #11A8CD -// $arrowBgColor = #ccc -// $badgeTipColor = #42b983 -// $badgeWarningColor = darken(#ffe564, 35%) -// $badgeErrorColor = #DA5961 - -// // 布局 -// $navbarHeight = 3.6rem -// $sidebarWidth = 18rem -// $contentWidth = 860px -// $homePageWidth = 1100px -// $rightMenuWidth = 230px // 右侧菜单 - -// // 代码块 -// $lineNumbersWrapperWidth = 2.5rem - -// 浅色模式 -.theme-mode-light - --bodyBg: rgba(255,255,255,1) - --mainBg: rgba(255,255,255,1) - --sidebarBg: rgba(255,255,255,.8) - --blurBg: rgba(255,255,255,.9) - --textColor: #004050 - --textLightenColor: #0085AD - --borderColor: rgba(0,0,0,.15) - --codeBg: #f6f6f6 - --codeColor: #525252 - codeThemeLight() - -// 深色模式 -.theme-mode-dark - --bodyBg: rgba(30,30,34,1) - --mainBg: rgba(30,30,34,1) - --sidebarBg: rgba(30,30,34,.8) - --blurBg: rgba(30,30,34,.8) - --textColor: rgb(140,140,150) - --textLightenColor: #0085AD - --borderColor: #2C2C3A - --codeBg: #252526 - --codeColor: #fff - codeThemeDark() - -// 阅读模式 -.theme-mode-read - --bodyBg: rgba(245,245,213,1) - --mainBg: rgba(245,245,213,1) - --sidebarBg: rgba(245,245,213,.8) - --blurBg: rgba(245,245,213,.9) - --textColor: #004050 - --textLightenColor: #0085AD - --borderColor: rgba(0,0,0,.15) - --codeBg: #282c34 - --codeColor: #fff - codeThemeDark() diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225\346\214\207\345\215\227.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225\346\214\207\345\215\227.md" deleted file mode 100644 index 7e0fa0b..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225\346\214\207\345\215\227.md" +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: 数据结构和算法指南 -categories: - - 数据结构和算法 - - 综合 -tags: - - 数据结构 - - 算法 -abbrlink: e74901af -date: 2015-03-10 18:29:37 -permalink: /pages/8b1bd0/ ---- -# 数据结构和算法指南 - -## 1. 为什么学习数据结构和算法 - -- **为了找到一份好工作**:大厂面试喜欢考算法 -- **更深入了解流行技术的设计思想**:数据结构和算法是计算机基础学科,很多框架、中间、底层系统设的设计,都借鉴了其思想。因此,掌握数据结构和算法,有利于更深入了解这些技术的设计思想。 -- 提升个人的编程水平 -- 不满足于做业务狗,拓展性能思考的视角 - -## 2. 如何学习数据结构和算法 - -数据结构就是指一组数据的存储结构。算法就是操作数据的一组方法。 - -数据结构和算法是相辅相成的。**数据结构是为算法服务的,算法要作用在特定的数据结构之上。** - -先要学会复杂度分析,才能识别数据结构和算法的利弊。 - -- 循序渐进 -- 边学边练,适度刷题 -- 学习并思考:学而不思则罔,思而不学则殆 -- 知识需要沉淀,不要想试图一下子掌握所有 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/02.\345\244\215\346\235\202\345\272\246\345\210\206\346\236\220.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/02.\345\244\215\346\235\202\345\272\246\345\210\206\346\236\220.md" deleted file mode 100644 index 8ff51fc..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/00.\347\273\274\345\220\210/02.\345\244\215\346\235\202\345\272\246\345\210\206\346\236\220.md" +++ /dev/null @@ -1,171 +0,0 @@ ---- -title: 复杂度分析 -categories: - - 数据结构和算法 - - 综合 -tags: - - 数据结构 - - 算法 -abbrlink: a1a87ec3 -date: 2022-03-20 23:25:17 -permalink: /pages/2a4131/ ---- - -# 复杂度分析 - -## 为什么需要复杂度分析 - -衡量算法的优劣,有两种评估方式:事前估计和后期测试。 - -后期测试有性能测试、基准测试(Benchmark)等手段。 - -但是,后期测试有以下限制: - -- **测试结果非常依赖测试环境**。如:不同机型、不同编译器版本、不同硬件配置等等,都会影响测试结果。 -- **测试结果受数据规模的影响很大**。 - -所以,需要一种方法,可以不受环境或数据规模的影响,粗略地估计算法的执行效率。这种方法就是复杂度分析。 - -## 时间复杂度分析 - -### 大 O 表示法 - -假设问题的规模为 n,则程序的时间复杂度表示为 `T(n)`。**代码的执行时间 T(n) 与每行代码的执行次数 n 成正比**。 - -当 n 增大时,T(n) 也随之增大,想要准确估计其变化比较困难。所以,可以采用大 O 时间复杂度来粗略估计其复杂度,其表达式为:**`T(n) = O(f(n))`**。 - -**大 O 表示法**实际上并不具体表示代码真正的执行时间,而是表示**代码执行时间随数据规模增长的变化趋势**,所以,也叫作**渐进时间复杂度**(asymptotic time complexity),简称**时间复杂度**。 - -### 时间复杂度分析的要点 - -- **只关注循环执行次数最多的一段代码** -- **加法法则:总复杂度等于量级最大的那段代码的复杂度** -- **乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积** - -### 最好、最坏和平均情况 - -- **最好情况时间复杂度**(best case time complexity):**在最理想的情况下,执行代码的时间复杂度**。例如:在最理想的情况下,要查找的变量 x 正好是数组的第一个元素,此时最好情况时间复杂度为 1。 -- **最坏情况时间复杂度**(worst case time complexity):**在最糟糕的情况下,执行代码的时间复杂度**。例如:在最理想的情况下,要查找的变量 x 正好是数组的最后个元素,此时最好情况时间复杂度为 n。 -- **平均情况时间复杂度**(average case time complexity):平均时间复杂度的全称应该叫**加权平均时间复杂度**或者**期望时间复杂度**。 - -### 时间复杂度分析示例 - -【示例】从 1 累加到 100 的时间复杂度是多少? - -```java -int sum = 0; -int N = 100; -for (int i = 1; i <= N; i++) { - sum = sum + i; -} -``` - -时间复杂度计算:显然,这段代码执行了 100 次加法,其时间复杂度和 N 的大小完全一致 - -``` -T(n) = O(n) -``` - -【示例】嵌套循环的时间复杂度是多少? - -```java -int M = 10; -int N = 20; -for (int i = 1; i < M; i++) { - for (int j = 1; j < N; j++) { - System.out.println("i = " + i + ", j = " + j); - } -} -``` - -时间复杂度计算: - -``` -T(n) = (M-1)(N-1) = O(M*N) ≈ O(N^2) -``` - -【示例】递归函数的时间复杂度是多少?思考一下斐波那契数列 `f(n) = f(n-1) + f(n-2)` 的时间复杂度是多少? - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320110642.png) - -``` -T(n) = O(2^N) -``` - -## 空间复杂度分析 - -时间复杂度的全称是**渐进时间复杂度**,**表示算法的执行时间与数据规模之间的增长关系**。 - -类比一下,空间复杂度全称就是**渐进空间复杂度**(asymptotic space complexity),**表示算法的存储空间与数据规模之间的增长关系**。 - -## 复杂度量级 - -复杂度有以下量级: - -- **`O(1)`**:常数复杂度 -- **`O(log n)`**:对数复杂度 -- **`O(n)`**:线性复杂度 -- **`O(nlog n)`**:线性对数阶复杂度 -- **`O(n^2)`**:平方复杂度 -- **`O(n^3)`**:立方复杂度 -- **`O(n^k)`**:K 次方复杂度 -- **`O(2^n)`**:指数复杂度 -- **`O(n!)`**:阶乘复杂度 - -在数据量比较小的时候,复杂度量级差异并不明显;但是,随着数据规模大小的变化,差异会逐渐突出。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320160627.png) - -`O(1)` 复杂度示例: - -```java -int num = 100; -System.out.println("num = " + num); -``` - -`O(log n)` 对数复杂度示例: - -```java -int max = 100; -for (int i = 1; i < max; i = i * 2) { - System.out.println("i = " + i); -} -``` - -`O(n)` 复杂度示例: - -```java -int max = 100; -for (int i = 1; i < max; i++) { - System.out.println("i = " + i); -} -``` - -`O(n^2)` 复杂度示例: - -```java -int M = 10; -int N = 20; -for (int i = 1; i < M; i++) { - for (int j = 1; j < N; j++) { - System.out.println("i = " + i + ", j = " + j); - } -} -``` - -`O(k^n)` 复杂度示例: - -```java -int max = 10; -for (int i = 1; i <= Math.pow(2, max); i++) { - System.out.println("i = " + i); -} -``` - -## 常见数据结构的复杂度 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200702071922.png) - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/01.\346\225\260\347\273\204\345\222\214\351\223\276\350\241\250.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/01.\346\225\260\347\273\204\345\222\214\351\223\276\350\241\250.md" deleted file mode 100644 index 343b216..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/01.\346\225\260\347\273\204\345\222\214\351\223\276\350\241\250.md" +++ /dev/null @@ -1,440 +0,0 @@ ---- -title: 数组和链表 -categories: - - 数据结构和算法 - - 线性表 -tags: - - 数据结构 - - 线性表 - - 数组 - - 链表 -abbrlink: 50ba53aa -date: 2015-04-10 18:46:13 -permalink: /pages/5a9bff/ ---- - -# 数组和链表 - -> 数组和链表分别代表了连续空间和不连续空间的存储方式,它们是线性表(Linear List)的典型代表。其他所有的数据结构,比如栈、队列、二叉树、B+ 树等,实际上都是这两者的结合和变化。 - -## 数组 - -数组用 **连续** 的内存空间来存储数据。 - -### 数组的访问 - -数组元素的访问是以行或列索引的单一下标表示。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320115836.png) - -在上面的例子中,数组 a 中有 5 个元素。`也就是说`,a 的长度是 6 。我们可以使用 a[0] 来表示数组中的第一个元素。因此,a[0] = A 。类似地,a[1] = B,a[2] = C,依此类推。 - -### 数组的插入 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320115848.png) - -### 数组的删除 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320115859.png) - -### 数组的特性 - -数组设计之初是在形式上依赖内存分配而成的,所以必须在使用前预先分配好空间大小。这使得数组有以下特性: - -1. **用连续的内存空间来存储数据**。 -2. **数组支持随机访问,根据下标随机访问的时间复杂度为 `O(1)`**。 -3. **数组的插入、删除操作,平均时间复杂度为 `O(n)`**。 -4. **空间大小固定**,一旦建立,不能再改变。扩容只能采用复制数组的方式。 -5. 在旧式编程语言中(如有中阶语言之称的 C),程序不会对数组的操作做下界判断,也就有潜在的越界操作的风险。 - -### 多维数组 - -数组是有下标和值组成集合。 - -如果数组的下标有多个维度,即为多维数组。比如:二维数组可以视为『数组元素为一维数组』的一维数组;三维数组可以视为『数组元素为二维数组』的一维数组;依次类推。 - -下图是由 M 个行向量,N 个列向量组成的二维数组. - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320152607.png) - -## 链表 - -> **链表用不连续的内存空间来存储数据;并通过一个指针按顺序将这些空间串起来,形成一条链**。 - -区别于数组,链表中的元素不是存储在内存中连续的一片区域,链表中的数据存储在每一个称之为「结点」复合区域里,在每一个结点除了存储数据以外,还保存了到下一个节点的指针(Pointer)。由于不必按顺序存储,链表在插入数据的时候可以达到 `O(1)` 的复杂度,但是查找一个节点或者访问特定编号的节点则需要 `O(n)` 的时间。 - -链表具有以下特性: - -- 链表允许插入和移除任意位置上的节点,其时间复杂度为 `O(1)` -- 链表没有数组的随机访问特性,**链表只支持顺序访问**,其时间复杂度为 `O(n)`。 -- 数组的空间大小是固定的,而**链表的空间大小可以动态增长**。相比于数组,链表支持扩容,显然更为灵活,但是由于多了指针域,空间开销也更大。 -- 链表相比于数组,多了头指针、尾指针(非必要),合理使用可以大大提高访问效率。 - -链表有多种类型: - -- 单链表 -- 双链表 -- 循环链表 - -### 单链表 - -单链表中的每个结点不仅包含数据值,还包含一个指针,指向其后继节点。通过这种方式,单链表将所有结点按顺序组织起来。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174829.png) - -与数组不同,我们无法在常量时间内访问单链表中的随机元素。 如果我们想要获得第 i 个元素,我们必须从头结点逐个遍历。 我们按 `索引` 来 `访问元素` 平均要花费 `O(N)` 时间,其中 N 是链表的长度。 - -#### 单链表插入 - -如果我们想在给定的结点 `prev` 之后添加新值,我们应该: - -(1)使用给定值初始化新结点 `cur`; - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174908.png) - -(2)将 `cur` 的 `next` 字段链接到 `prev` 的下一个结点 `next` ; - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174919.png) - -(3)将 `prev` 中的 `next` 字段链接到 `cur` 。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174932.png) - -与数组不同,我们不需要将所有元素移动到插入元素之后。因此,您可以在 `O(1)` 时间复杂度中将新结点插入到链表中,这非常高效。 - -#### 单链表删除 - -如果我们想从单链表中删除现有结点 `cur`,可以分两步完成: - -(1)找到 `cur` 的上一个结点 `prev` 及其下一个结点 `next` ; - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320174953.png) - -(2)接下来链接 `prev` 到 `cur` 的下一个节点 `next` 。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320175006.png) - -在我们的第一步中,我们需要找出 `prev` 和 `next`。使用 `cur` 的参考字段很容易找出 `next`,但是,我们必须从头结点遍历链表,以找出 `prev`,它的平均时间是 `O(N)`,其中 `N` 是链表的长度。因此,删除结点的时间复杂度将是 `O(N)`。 - -空间复杂度为 `O(1)`,因为我们只需要常量空间来存储指针。 - -### 双链表 - -双链表中的每个结点不仅包含数据值,还包含两个指针,分别指向指向其前驱节点和后继节点。 - -单链表的访问是单向的,而双链表的访问是双向的。显然,双链表比单链表操作更灵活,但是空间开销也更大。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181150.png) - -双链表以类似的方式工作,但`还有一个引用字段`,称为`“prev”`字段。有了这个额外的字段,您就能够知道当前结点的前一个结点。 - -#### 双链表插入 - -如果我们想在给定的结点 `prev` 之后添加新值,我们应该: - -(1)使用给定值初始化新结点 `cur`; - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181208.png) - -(2)链接 `cur` 与 `prev` 和 `next`,其中 `next` 是 `prev` 原始的下一个节点; - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181303.png) - -(3)用 `cur` 重新链接 `prev` 和 `next`。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320181504.png) - -与单链表类似,添加操作的时间和空间复杂度都是 `O(1)`。 - -#### 双链表删除 - -如果我们想从双链表中删除一个现有的结点 `cur`,我们可以简单地将它的前一个结点 `prev` 与下一个结点 `next` 链接起来。 - -与单链表不同,使用 `prev` 字段可以很容易地在常量时间内获得前一个结点。 - -因为我们不再需要遍历链表来获取前一个结点,所以时间和空间复杂度都是 `O(1)`。 - -### 循环链表 - -#### 循环单链表 - -**循环单链表是一种特殊的单链表**。它和单链表唯一的区别就在最后结点。 - -- 单链表的最后一个结点的后继指针 `next` 指向空地址。 -- 循环链表的最后一个结点的后继指针 `next` 指向第一个节点(如果有头节点,就指向头节点)。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220322190534.png) - -#### 循环双链表 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220322190423.png) - -## 数组 vs. 链表 - -- **存储方式** - - 数组用 **连续** 的内存空间来存储数据。 - - 链表用 **不连续** 的内存空间来存储数据;并通过一个指针按顺序将这些空间串起来,形成一条链。 -- **访问方式** - - 数组**支持随机访问**。根据下标随机访问的时间复杂度为 `O(1)` - - 链表**不支持随机访问**,只能顺序访问,时间复杂度为 `O(n)`。 -- **空间大小** - - 数组空间**大小固定**,扩容只能采用复制数组的方式。 - - 链表空间**大小不固定**,扩容灵活。 -- **效率比较** - - 数组的 **查找** 效率高于链表。 - - 链表的 **添加**、**删除** 效率高于数组。 - -## 数组和链表的基本操作示例 - -关于数组和链表的基本操作,网上和各种书籍、教程中已经有大量的示例,感兴趣可以自行搜索。本文只是简单展示一下数组和链表的基本操作。 - -### 一维数组的基本操作 - -```java -public class Main { - public static void main(String[] args) { - // 1. Initialize - int[] a0 = new int[5]; - int[] a1 = {1, 2, 3}; - // 2. Get Length - System.out.println("The size of a1 is: " + a1.length); - // 3. Access Element - System.out.println("The first element is: " + a1[0]); - // 4. Iterate all Elements - System.out.print("[Version 1] The contents of a1 are:"); - for (int i = 0; i < a1.length; ++i) { - System.out.print(" " + a1[i]); - } - System.out.println(); - System.out.print("[Version 2] The contents of a1 are:"); - for (int item: a1) { - System.out.print(" " + item); - } - System.out.println(); - // 5. Modify Element - a1[0] = 4; - // 6. Sort - Arrays.sort(a1); - } -} -``` - -### 二维数组的基本操作 - -```java -public class TwoDimensionArray { - private static void printArray(int[][] a) { - for (int i = 0; i < a.length; ++i) { - System.out.println(a[i]); - } - for (int i = 0; i < a.length; ++i) { - for (int j = 0; a[i] != null && j < a[i].length; ++j) { - System.out.print(a[i][j] + " "); - } - System.out.println(); - } - } - - public static void main(String[] args) { - System.out.println("Example I:"); - int[][] a = new int[2][5]; - printArray(a); - System.out.println("Example II:"); - int[][] b = new int[2][]; - printArray(b); - System.out.println("Example III:"); - b[0] = new int[3]; - b[1] = new int[5]; - printArray(b); - } -} -``` - -### 单链表的基本操作 - -单链表节点的数据结构 - -```java -public class ListNode { - E value; - ListNode next; // 指向后继节点 -} - -public class SingleLinkList { - private ListNode head; // 头节点 -} -``` - -(1)从头部添加节点(即头插法) - -```java -void addHead(E value) { - ListNode newNode = new ListNode<>(value, null); - newNode.next = this.head.next; - this.head.next = newNode; -} -``` - -(2)从尾部添加节点(即尾插法) - -```java -void addTail(E value) { - // init new node - ListNode newNode = new ListNode<>(value, null); - - // find the last node - ListNode node = this.head; - while (node.next != null) { - node = node.next; - } - - // add new node to tail - node.next = newNode; -} -``` - -(3)删除节点 - -找到要删除元素的前驱节点,将前驱节点的 next 指针指向下一个节点。 - -```java -public void remove(E value) { - ListNode prev = this.head; - while (prev.next != null) { - ListNode curr = prev.next; - if (curr.value.equals(value)) { - prev.next = curr.next; - break; - } - prev = prev.next; - } -} -``` - -(4)查找节点 - -从头开始查找,一旦发现有数值与查找值相等的节点,直接返回此节点。如果遍历结束,表明未找到节点,返回 null。 - -```java -public ListNode find(E value) { - ListNode node = this.head.next; - while (node != null) { - if (node.value.equals(value)) { - return node; - } - node = node.next; - } - return null; -} -``` - -### 双链表的基本操作 - -双链表节点的数据结构: - -```java -static class DListNode { - E value; - DListNode prev; // 指向前驱节点 - DListNode next; // 指向后继节点 -} - -public class DoubleLinkList { - /** 头节点 */ - private DListNode head; - /** 尾节点 */ - private DListNode tail; -} -``` - -(1)从头部添加节点 - -```java -public void addHead(E value) { - DListNode newNode = new DListNode<>(null, value, null); - - this.head.next.prev = newNode; - newNode.next = this.head.next; - - this.head.next = newNode; - newNode.prev = this.head; -} -``` - -(2)从尾部添加节点 - -```java -public void addTail(E value) { - DListNode newNode = new DListNode<>(null, value, null); - - this.tail.prev.next = newNode; - newNode.prev = this.tail.prev; - - this.tail.prev = newNode; - newNode.next = this.tail; -} -``` - -(3)删除节点 - -```java -public void remove(E value) { - DListNode prev = this.head; - while (prev.next != this.tail) { - DListNode curr = prev.next; - if (curr.value.equals(value)) { - prev.next = curr.next; - curr.next.prev = prev; - curr.next = null; - curr.prev = null; - break; - } - prev = prev.next; - } -} -``` - -(4)查找节点 - -```java -public DListNode find(E value) { - DListNode node = this.head.next; - while (node != this.tail) { - if (node.value.equals(value)) { - return node; - } - node = node.next; - } - return null; -} -``` - -## 练习 - -- 数组 - - [x] [724. 寻找数组的中心下标](https://leetcode-cn.com/problems/find-pivot-index/) - - [x] [35. 搜索插入位置](https://leetcode-cn.com/problems/search-insert-position/) - - [x] [56. 合并区间](https://leetcode-cn.com/problems/merge-intervals/) -- 链表 - - [ ] [设计链表](https://leetcode-cn.com/leetbook/read/linked-list/jy291/) - - [ ] [环形链表](https://leetcode-cn.com/leetbook/read/linked-list/jbex5/) - - [ ] [环形链表 II](https://leetcode-cn.com/leetbook/read/linked-list/jjhf6/) - - [ ] [相交链表](https://leetcode-cn.com/leetbook/read/linked-list/jjbj2/) - - [ ] [删除链表的倒数第 N 个节点](https://leetcode-cn.com/leetbook/read/linked-list/jf1cc/) - - [ ] [反转链表](https://leetcode-cn.com/leetbook/read/linked-list/f58sg/) - - [ ] [移除链表元素](https://leetcode-cn.com/leetbook/read/linked-list/f9izv/) - - [ ] [奇偶链表](https://leetcode-cn.com/leetbook/read/linked-list/fe0kj/) - - [ ] [回文链表](https://leetcode-cn.com/leetbook/read/linked-list/fov6t/) - - [ ] [合并两个有序链表](https://leetcode-cn.com/leetbook/read/linked-list/fnzd1/) - - [ ] [两数相加](https://leetcode-cn.com/leetbook/read/linked-list/fv6w7/) - - [ ] [扁平化多级双向链表](https://leetcode-cn.com/leetbook/read/linked-list/fw8v5/) - - [ ] [复制带随机指针的链表](https://leetcode-cn.com/leetbook/read/linked-list/fdi26/) - - [ ] [旋转链表](https://leetcode-cn.com/leetbook/read/linked-list/f00a2/) - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) -- [数据结构(C 语言版)](https://item.jd.com/12407475.html) -- [数据结构(C++语言版)](https://book.douban.com/subject/25859528/) -- [Leetcode:数组和字符串](https://leetcode-cn.com/leetbook/detail/array-and-string/) -- [Leetcode:链表](https://leetcode-cn.com/tag/linked-list/) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/02.\346\240\210\345\222\214\351\230\237\345\210\227.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/02.\346\240\210\345\222\214\351\230\237\345\210\227.md" deleted file mode 100644 index 2df6ac1..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/02.\346\240\210\345\222\214\351\230\237\345\210\227.md" +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: 栈和队列 -categories: - - 数据结构和算法 -tags: - - 数据结构 - - 线性表 - - 栈 - - 队列 -abbrlink: 8d66b5f2 -date: 2014-01-25 16:46:13 -permalink: /pages/1f15c3/ ---- - -# 栈和队列 - -> **队列**和**栈**都是**操作受限**的**线性表**:前者先进先出,后者先进后出。 - -## 栈 - -### 栈是什么 - -在 **LIFO(后进先出)** 数据结构中,将首先处理添加到队列中的最新元素。 - -**栈是一个 LIFO(后进先出) 数据结构**。**栈是一种“操作受限”的线性表**,只允许在一端插入和删除数据。通常,插入操作在栈中被称作入栈 push 。与队列类似,总是在堆栈的末尾添加一个新元素。但是,删除操作,退栈 pop ,将始终删除队列中相对于它的最后一个元素。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320200148.png) - -**当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出、先进后出的特性,我们就应该首选“栈”这种数据结构**。 - -从栈的定义可以看出,栈只支持两个基本操作:**入栈 `push()`** 和 **出栈 `pop()`** ,也就是在栈顶插入一个数据和从栈顶删除一个数据。在入栈和出栈过程中,只需要一两个临时变量存储空间,所以空间复杂度是 `O(1)`。 - -栈既可以用数组来实现,也可以用链表来实现。用数组实现的栈,我们叫作**顺序栈**,用链表实现的栈,我们叫作**链式栈**。 - -### 为什么需要栈 - -相比数组和链表,栈只是对操作进行了限制,似乎并没有任何优势。为什么不直接使用数组或者链表?为什么还要用这个“操作受限”的“栈”呢? - -特定的数据结构是对特定场景的抽象,而且,数组或链表暴露了太多的操作接口,操作上的确灵活自由,但使用时就比较不可控,自然也就更容易出错。 - -### 栈的应用场景 - -(1)**函数调用栈** - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310091000.jpg) - -(2)**表达式求值** - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310091100.jpg) - -(3)**表达式匹配** - -可以借助栈来检查表达式中的括号是否匹配 - -## 队列 - -在 FIFO 数据结构中,将首先处理添加到队列中的第一个元素。 - -队列是典型的 FIFO 数据结构。插入(insert)操作也称作入队(enqueue),新元素始终被添加在队列的末尾。 删除(delete)操作也被称为出队(dequeue)。 你只能移除第一个元素。 - -### 什么是队列 - -**队列:先进先出的线性表**。 - -**队列是一种“操作受限”的线性表**,只允许在一端插入数据,在另一端删除数据。 - -队列的最基本操作:**入队 `enqueue()`**,放一个数据到队列尾部;**出队 `dequeue()`**,从队列头部取一个元素。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320200213.png) - -队列可以用数组来实现,也可以用链表来实现。用数组实现的队列叫作**顺序队列**,用链表实现的队列叫作**链式队列**。 - -队满的判断条件是 `tail == n`,队空的判断条件是 `head == tail`。 - -### 循环队列 - -循环队列是一种较为特殊的队列。 - -循环队列的要点是确定好 **队空和队满的判定条件**。 - -在用数组实现的非循环队列中,队满的判断条件是 `(tail+1) % n == head`,队空的判断条件是 `head == tail`。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220322214822.png) - -### 为什么需要队列 - -为什么需要队列和为什么需要栈,是同样的道理,参考 为什么需要栈 - -### 队列的应用场景 - -(1)**阻塞队列** - -**阻塞队列**其实就是在队列基础上增加了阻塞操作。简单来说,就是: - -- 在队列为空的时候,从队头取数据会被阻塞。因为此时还没有数据可取,直到队列中有了数据才能返回; -- 如果队列已经满了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后再返回。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310092908.jpg) - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310093026.jpg) - -(2)**并发队列** - -线程安全的队列我们叫作**并发队列**。最简单直接的实现方式是直接在 enqueue()、dequeue() 方法上加锁,但是锁粒度大并发度会比较低,同一时刻仅允许一个存或者取操作。实际上,基于数组的循环队列,利用 CAS 原子操作,可以实现非常高效的并发队列。这也是循环队列比链式队列应用更加广泛的原因。 - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) -- [Leetcode:栈和队列](https://leetcode-cn.com/leetbook/detail/queue-stack/) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/11.\347\272\277\346\200\247\350\241\250\347\232\204\346\237\245\346\211\276.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/11.\347\272\277\346\200\247\350\241\250\347\232\204\346\237\245\346\211\276.md" deleted file mode 100644 index 1cfc918..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/11.\347\272\277\346\200\247\350\241\250\347\232\204\346\237\245\346\211\276.md" +++ /dev/null @@ -1,319 +0,0 @@ ---- -title: 线性表的查找 -categories: - - 数据结构和算法 - - 线性表 -tags: - - 数据结构 - - 线性表 - - 查找 -abbrlink: 443d1da2 -date: 2015-03-10 18:29:13 -permalink: /pages/4b1ed0/ ---- - -# 线性表的查找 - -## 查找简介 - -### 什么是查找? - -**查找**是根据给定的某个值,在表中确定一个关键字的值等于给定值的记录或数据元素。 - -### 查找算法的分类 - -若在查找的同时对表记录做修改操作(如插入和删除),则相应的表称之为**动态查找表**; - -否则,称之为**静态查找表**。 - -此外,如果查找的全过程都在内存中进行,称之为**内查找**; - -反之,如果查找过程中需要访问外存,称之为**外查找**。 - -### 查找算法性能比较的标准 - -**——平均查找长度 ASL(Average Search Length)** - -由于查找算法的主要运算是关键字的比较过程,所以通常把查找过程中对关键字需要执行的**平均比较长度**(也称为**平均比较次数**)作为衡量一个查找算法效率优劣的比较标准。 - -![img](https://upload-images.jianshu.io/upload_images/3101171-a38f84148d091364.gif?imageMogr2/auto-orient/strip) - -**选取查找算法的因素** - -(1) 使用什么数据存储结构(如线性表、树形表等)。 - -(2) 表中的次序,即对无序表还是有序表进行查找。 - -## 顺序查找 - -**要点** - -它是一种最简单的查找算法,效率也很低下。 - -**存储结构** - -没有存储结构要求,可以无序,也可以有序。 - -**基本思想** - -从数据结构线形表的**一端**开始,**顺序扫描**,**依次**将扫描到的结点关键字与给定值 k 相**比较**,若相等则表示查找成功; - -若扫描结束仍没有找到关键字等于 k 的结点,表示查找失败。 - -**核心代码** - -```java -public int orderSearch(int[] list, int length, int key) { - // 从前往后扫描list数组,如果有元素的值与key相等,直接返回其位置 - for (int i = 0; i < length; i++) { - if (key == list[i]) { - return i; - } - } - - // 如果扫描完,说明没有元素的值匹配key,返回-1,表示查找失败 - return -1; -} -``` - -**算法分析** - -顺序查找算法**最好的情况**是,第一个记录即匹配关键字,则需要比较 **1** 次; - -**最坏的情况**是,最后一个记录匹配关键字,则需要比较 **N** 次。 - -所以,顺序查找算法的平均查找长度为 - -ASL = (N + N-1 + ... + 2 + 1) / N = (N+1) / 2 - -顺序查找的**平均时间复杂度**为**O(N)**。 - -## 二分查找 - -> **二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0**。 - -**存储结构** - -使用二分查找需要两个前提: - -(1) 必须是**顺序**存储结构。 - -(2) 必须是**有序**的表。 - -**基本思想** - -首先,将表**中间位置**记录的关键字与查找关键字比较,如果两者相等,则查找成功; - -否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。 -重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。 - -**核心代码** - -```java -public int binarySearch(int[] list, int length, int key) { - int low = 0, mid = 0, high = length - 1; - while (low <= high) { - mid = (low + high) / 2; - if (list[mid] == key) { - return mid; // 查找成功,直接返回位置 - } else if (list[mid] < key) { - low = mid + 1; // 关键字大于中间位置的值,则在大值区间[mid+1, high]继续查找 - } else { - high = mid - 1; // 关键字小于中间位置的值,则在小值区间[low, mid-1]继续查找 - } - } - return -1; -} -``` - -**算法分析** - -**二分查找的过程可看成一个二叉树**。 - -把查找区间的中间位置视为树的根,左区间和右区间视为根的左子树和右子树。 - -由此得到的二叉树,称为二分查找的判定树或比较树。 - -由此可知,二分查找的**平均查找长度**实际上就是树的高度**O(log2N)**。 - -**二分查找的局限性** - -- 二分查找依赖的是顺序表结构,简单点说就是数组 -- 二分查找针对的是有序数据 -- 数据量太小不适合二分查找 -- 数据量太大也不适合二分查找 - -## 分块查找 - -**要点** - -分块查找(Blocking Search)又称**索引顺序查找**。它是一种性能介于顺序查找和二分查找之间的查找方法。 - -分块查找由于只要求索引表是有序的,对块内节点没有排序要求,因此特别适合于节点动态变化的情况。 - -**存储结构** - -分块查找表是由**“分块有序”的线性表**和**索引表**两部分构成的。 - -所谓**“分块有序”的线性表**,是指: - -假设要排序的表为 R[0...N-1],**将表均匀分成 b 块**,前 b-1 块中记录个数为 s=N/b,最后一块记录数小于等于 s; - -每一块中的关键字不一定有序,但**前一块中的最大关键字必须小于后一块中的最小关键字**。 - -**_注:这是使用分块查找的前提条件。_** - -如上将表均匀分成 b 块后,抽取各块中的**最大关键字**和**起始位置**构成一个索引表 IDX[0...b-1]。 - -由于表 R 是分块有序的,所以**索引表是一个递增有序表**。 - -下图就是一个分块查找表的存储结构示意图 - -![img](https://upload-images.jianshu.io/upload_images/3101171-b7ad44c68d0c3c75.png) - -**基本思想** - -分块查找算法有两个处理步骤: - -**(1) 首先查找索引表** - -因为分块查找表是“分块有序”的,所以我们可以通过索引表来锁定关键字所在的区间。 - -又因为索引表是递增有序的,所以查找索引可以使用顺序查找或二分查找。 - -**(2) 然后在已确定的块中进行顺序查找** - -因为块中不一定是有序的,所以只能使用顺序查找。 - -**代码范例** - -![img](http://upload-images.jianshu.io/upload_images/3101171-2737612c781e66e8.gif?imageMogr2/auto-orient/strip) - -```java -class BlockSearch { - - class IndexType { - public int key; // 分块中的最大值 - public int link; // 分块的起始位置 - } - - // 建立索引方法,n 是线性表最大长度,gap是分块的最大长度 - public IndexType[] createIndex(int[] list, int n, int gap) { - int i = 0, j = 0, max = 0; - int num = n / gap; - IndexType[] idxGroup = new IndexType[num]; // 根据步长数分配索引数组大小 - - while (i < num) { - j = 0; - idxGroup[i] = new IndexType(); - idxGroup[i].link = gap * i; // 确定当前索引组的第一个元素位置 - max = list[gap * i]; // 每次假设当前组的第一个数为最大值 - // 遍历这个分块,找到最大值 - while (j < gap) { - if (max < list[gap * i + j]) { - max = list[gap * i + j]; - } - j++; - } - idxGroup[i].key = max; - i++; - } - - return idxGroup; - } - - // 分块查找算法 - public int blockSearch(IndexType[] idxGroup, int m, int[] list, int n, int key) { - int mid = 0; - int low = 0; - int high = m -1; - int gap = n / m; // 分块大小等于线性表长度除以组数 - - // 先在索引表中进行二分查找,找到的位置存放在 low 中 - while (low <= high) { - mid = (low + high) / 2; - if (idxGroup[mid].key >= key) { - high = mid - 1; - } else { - low = mid + 1; - } - } - - // 在索引表中查找成功后,再在线性表的指定块中进行顺序查找 - if (low < m) { - for (int i = idxGroup[low].link; i < idxGroup[low].link + gap; i++) { - if (list[i] == key) - return i; - } - } - - return -1; - } - - // 打印完整序列 - public void printAll(int[] list) { - for (int value : list) { - System.out.print(value + " "); - } - System.out.println(); - } - - // 打印索引表 - public void printIDX(IndexType[] list) { - System.out.println("构造索引表如下:"); - for (IndexType elem : list) { - System.out.format("key = %d, link = %d\n", elem.key, elem.link); - } - System.out.println(); - } - - public static void main(String[] args) { - int key = 85; - int array2[] = { 8, 14, 6, 9, 10, 22, 34, 18, 19, 31, 40, 38, 54, 66, 46, 71, 78, 68, 80, 85 }; - BlockSearch search = new BlockSearch(); - - System.out.print("线性表: "); - search.printAll(array2); - - IndexType[] idxGroup = search.createIndex(array2, array2.length, 5); - search.printIDX(idxGroup); - int pos = search.blockSearch(idxGroup, idxGroup.length, array2, - array2.length, key); - if (-1 == pos) { - System.out.format("查找key = %d失败", key); - } else { - System.out.format("查找key = %d成功,位置为%d", key, pos); - } - } - -} -``` - -**运行结果** - -``` -线性表: 8 14 6 9 10 22 34 18 19 31 40 38 54 66 46 71 78 68 80 85 -构造索引表如下: -key = 14, link = 0 -key = 34, link = 5 -key = 66, link = 10 -key = 85, link = 15 - -查找key = 85成功,位置为19 -``` - -**算法分析** - -因为分块查找实际上是两次查找过程之和。若以二分查找来确定块,显然它的查找效率介于顺序查找和二分查找之间。 - -## 三种线性查找的 PK - -(1) 以平均查找长度而言,二分查找 > 分块查找 > 顺序查找。 - -(2) 从适用性而言,顺序查找无限制条件,二分查找仅适用于有序表,分块查找要求“分块有序”。 - -(3) 从存储结构而言,顺序查找和分块查找既可用于顺序表也可用于链表;而二分查找只适用于顺序表。 - -(4) 分块查找综合了顺序查找和二分查找的优点,既可以较为快速,也能使用动态变化的要求。 - -## 参考资料 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/12.\347\272\277\346\200\247\350\241\250\347\232\204\346\216\222\345\272\217.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/12.\347\272\277\346\200\247\350\241\250\347\232\204\346\216\222\345\272\217.md" deleted file mode 100644 index 2bee638..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/01.\347\272\277\346\200\247\350\241\250/12.\347\272\277\346\200\247\350\241\250\347\232\204\346\216\222\345\272\217.md" +++ /dev/null @@ -1,893 +0,0 @@ ---- -title: 线性表的排序 -categories: - - 数据结构和算法 - - 线性表 -tags: - - 数据结构 - - 线性表 - - 排序 -abbrlink: d3b2b8db -date: 2015-03-03 17:37:24 -permalink: /pages/21c5f2/ ---- - -# 线性表的排序 - -> 📦 本文已归档到:「[blog](https://github.com/dunwu/blog/tree/master/source/_posts/algorithm)」 -> -> 🔁 本文中的示例代码已归档到:「[algorithm-tutorial](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java)」 - -## 冒泡排序 - -### 要点 - -冒泡排序是一种交换排序。 - -什么是交换排序呢? - -> 交换排序:两两比较待排序的关键字,并交换不满足次序要求的那对数,直到整个表都满足次序要求为止。 - -### 算法思想 - -它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。 - -这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端,故名。 - -假设有一个大小为 N 的无序序列。冒泡排序就是要每趟排序过程中通过两两比较,找到第 i 个小(大)的元素,将其往上排。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/bubble-sort.png) - -以上图为例,演示一下冒泡排序的实际流程: - -假设有一个无序序列 { 4. 3. 1. 2, 5 } - -- 第一趟排序:通过两两比较,找到第一小的数值 1 ,将其放在序列的第一位。 -- 第二趟排序:通过两两比较,找到第二小的数值 2 ,将其放在序列的第二位。 -- 第三趟排序:通过两两比较,找到第三小的数值 3 ,将其放在序列的第三位。 - -至此,所有元素已经有序,排序结束。 - -要将以上流程转化为代码,我们需要像机器一样去思考,不然编译器可看不懂。 - -- 假设要对一个大小为 N 的无序序列进行升序排序(即从小到大)。 - - 每趟排序过程中需要通过比较找到第 i 个小的元素。 - - 所以,我们需要一个外部循环,从数组首端(下标 0) 开始,一直扫描到倒数第二个元素(即下标 N - 2) ,剩下最后一个元素,必然为最大。 -- 假设是第 i 趟排序,可知,前 i-1 个元素已经有序。现在要找第 i 个元素,只需从数组末端开始,扫描到第 i 个元素,将它们两两比较即可。 - - 所以,需要一个内部循环,从数组末端开始(下标 N - 1),扫描到 (下标 i + 1)。 - -**核心代码** - -```java -public void bubbleSort(int[] list) { - int temp = 0; // 用来交换的临时数 - - // 要遍历的次数 - for (int i = 0; i < list.length - 1; i++) { - // 从后向前依次的比较相邻两个数的大小,遍历一次后,把数组中第i小的数放在第i个位置上 - for (int j = list.length - 1; j > i; j--) { - // 比较相邻的元素,如果前面的数大于后面的数,则交换 - if (list[j - 1] > list[j]) { - temp = list[j - 1]; - list[j - 1] = list[j]; - list[j] = temp; - } - } - - System.out.format("第 %d 趟:\t", i); - printAll(list); - } -} -``` - -### 算法分析 - -**冒泡排序算法的性能** - -| 参数 | 结果 | -| ------------------ | -------- | -| 排序类别 | 交换排序 | -| 排序方法 | 冒泡排序 | -| 时间复杂度平均情况 | O(N2) | -| 时间复杂度最坏情况 | O(N3) | -| 时间复杂度最好情况 | O(N) | -| 空间复杂度 | O(1) | -| 稳定性 | 稳定 | -| 复杂性 | 简单 | - -#### 时间复杂度 - -若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数 C 和记录移动次数 M 均达到最小值:Cmin = N - 1, Mmin = 0。所以,冒泡排序最好时间复杂度为 O(N)。 - -若初始文件是反序的,需要进行 N -1 趟排序。每趟排序要进行 N - i 次关键字的比较(1 ≤ i ≤ N - 1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值: - -Cmax = N(N-1)/2 = O(N2) - -Mmax = 3N(N-1)/2 = O(N2) - -冒泡排序的最坏时间复杂度为 O(N2)。 - -因此,冒泡排序的平均时间复杂度为 O(N2)。 - -总结起来,其实就是一句话:当数据越接近正序时,冒泡排序性能越好。 - -#### 算法稳定性 - -冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。 - -所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。 - -#### 优化 - -对冒泡排序常见的改进方法是加入标志性变量 exchange,用于标志某一趟排序过程中是否有数据交换。 - -如果进行某一趟排序时并没有进行数据交换,则说明所有数据已经有序,可立即结束排序,避免不必要的比较过程。 - -**核心代码** - -```java -// 对 bubbleSort 的优化算法 -public void bubbleSort_2(int[] list) { - int temp = 0; // 用来交换的临时数 - boolean bChange = false; // 交换标志 - - // 要遍历的次数 - for (int i = 0; i < list.length - 1; i++) { - bChange = false; - // 从后向前依次的比较相邻两个数的大小,遍历一次后,把数组中第i小的数放在第i个位置上 - for (int j = list.length - 1; j > i; j--) { - // 比较相邻的元素,如果前面的数大于后面的数,则交换 - if (list[j - 1] > list[j]) { - temp = list[j - 1]; - list[j - 1] = list[j]; - list[j] = temp; - bChange = true; - } - } - - // 如果标志为false,说明本轮遍历没有交换,已经是有序数列,可以结束排序 - if (false == bChange) - break; - - System.out.format("第 %d 趟:\t", i); - printAll(list); - } -} -``` - -### 示例代码 - -[我的 Github 测试例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java) - -样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。 - -## 快速排序 - -### 要点 - -> 快速排序是一种交换排序。 - -快速排序由 C. A. R. Hoare 在 1962 年提出。 - -### 算法思想 - -它的基本思想是: - -通过一趟排序将要排序的数据分割成独立的两部分:分割点左边都是比它小的数,右边都是比它大的数。 - -然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 - -详细的图解往往比大堆的文字更有说明力,所以直接上图: - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/quick-sort.png) - -上图中,演示了快速排序的处理过程: - -1. 初始状态为一组无序的数组:2、4、5、1、3。 -2. 经过以上操作步骤后,完成了第一次的排序,得到新的数组:1、2、5、4、3。 -3. 新的数组中,以 2 为分割点,左边都是比 2 小的数,右边都是比 2 大的数。 -4. 因为 2 已经在数组中找到了合适的位置,所以不用再动。 -5. 2 左边的数组只有一个元素 1,所以显然不用再排序,位置也被确定。(注:这种情况时,left 指针和 right 指针显然是重合的。因此在代码中,我们可以通过设置判定条件 left 必须小于 right,如果不满足,则不用排序了)。 -6. 而对于 2 右边的数组 5、4、3,设置 left 指向 5,right 指向 3,开始继续重复图中的一、二、三、四步骤,对新的数组进行排序。 - -**核心代码** - -```java -public int division(int[] list, int left, int right) { - // 以最左边的数(left)为基准 - int base = list[left]; - while (left < right) { - // 从序列右端开始,向左遍历,直到找到小于base的数 - while (left < right && list[right] >= base) - right--; - // 找到了比base小的元素,将这个元素放到最左边的位置 - list[left] = list[right]; - - // 从序列左端开始,向右遍历,直到找到大于base的数 - while (left < right && list[left] <= base) - left++; - // 找到了比base大的元素,将这个元素放到最右边的位置 - list[right] = list[left]; - } - - // 最后将base放到left位置。此时,left位置的左侧数值应该都比left小; - // 而left位置的右侧数值应该都比left大。 - list[left] = base; - return left; -} - -private void quickSort(int[] list, int left, int right) { - - // 左下标一定小于右下标,否则就越界了 - if (left < right) { - // 对数组进行分割,取出下次分割的基准标号 - int base = division(list, left, right); - - System.out.format("base = %d:\t", list[base]); - printPart(list, left, right); - - // 对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序 - quickSort(list, left, base - 1); - - // 对“基准标号“右侧的一组数值进行递归的切割,以至于将这些数值完整的排序 - quickSort(list, base + 1, right); - } -} -``` - -### 算法分析 - -快速排序算法的性能 - -| 参数 | 结果 | -| ------------------ | --------- | -| 排序类别 | 交换排序 | -| 排序方法 | 快速排序 | -| 时间复杂度平均情况 | O(Nlog2N) | -| 时间复杂度最坏情况 | O(N2) | -| 时间复杂度最好情况 | O(Nlog2N) | -| 空间复杂度 | O(Nlog2N) | -| 稳定性 | 不稳定 | -| 复杂性 | 较复杂 | - -#### 时间复杂度 - -当数据有序时,以第一个关键字为基准分为两个子序列,前一个子序列为空,此时执行效率最差。 - -而当数据随机分布时,以第一个关键字为基准分为两个子序列,两个子序列的元素个数接近相等,此时执行效率最好。 - -所以,数据越随机分布时,快速排序性能越好;数据越接近有序,快速排序性能越差。 - -#### 空间复杂度 - -快速排序在每次分割的过程中,需要 1 个空间存储基准值。而快速排序的大概需要 Nlog2N 次的分割处理,所以占用空间也是 Nlog2N 个。 - -#### 算法稳定性 - -在快速排序中,相等元素可能会因为分区而交换顺序,所以它是不稳定的算法。 - -### 示例代码 - -[我的 Github 测试例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java) - -样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。 - -## 插入排序 - -### 要点 - -> 直接插入排序是一种最简单的**插入排序**。 -> -> **插入排序**:每一趟将一个待排序的记录,按照其关键字的大小插入到有序队列的合适位置里,知道全部插入完成。 - -### 算法思想 - -在讲解直接插入排序之前,先让我们脑补一下我们打牌的过程。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/insert-sort.png) - -- 先拿一张 5 在手里, -- 再摸到一张 4,比 5 小,插到 5 前面, -- 摸到一张 6,嗯,比 5 大,插到 5 后面, -- 摸到一张 8,比 6 大,插到 6 后面, -- 。。。 -- 最后一看,我靠,凑到的居然是同花顺,这下牛逼大了。 - -以上的过程,其实就是典型的**直接插入排序,每次将一个新数据插入到有序队列中的合适位置里**。 - -很简单吧,接下来,我们要将这个算法转化为编程语言。 - -假设有一组无序序列 R0, R1, ... , RN-1。 - -- 我们先将这个序列中下标为 0 的元素视为元素个数为 1 的有序序列。 -- 然后,我们要依次把 R1, R2, ... , RN-1 插入到这个有序序列中。所以,我们需要一个**外部循环**,从下标 1 扫描到 N-1 。 -- 接下来描述插入过程。假设这是要将 Ri 插入到前面有序的序列中。由前面所述,我们可知,插入 Ri 时,前 i-1 个数肯定已经是有序了。 - -所以我们需要将 Ri 和 R0 \~ Ri-1 进行比较,确定要插入的合适位置。这就需要一个**内部循环**,我们一般是从后往前比较,即从下标 i-1 开始向 0 进行扫描。 - -**核心代码** - -```java -public void insertSort(int[] list) { - // 打印第一个元素 - System.out.format("i = %d:\t", 0); - printPart(list, 0, 0); - - // 第1个数肯定是有序的,从第2个数开始遍历,依次插入有序序列 - for (int i = 1; i < list.length; i++) { - int j = 0; - int temp = list[i]; // 取出第i个数,和前i-1个数比较后,插入合适位置 - - // 因为前i-1个数都是从小到大的有序序列,所以只要当前比较的数(list[j])比temp大,就把这个数后移一位 - for (j = i - 1; j >= 0 && temp < list[j]; j--) { - list[j + 1] = list[j]; - } - list[j + 1] = temp; - - System.out.format("i = %d:\t", i); - printPart(list, 0, i); - } -} -``` - -### 算法分析 - -**直接插入排序的算法性能** - -| 参数 | 结果 | -| ------------------ | ------------ | -| 排序类别 | 插入排序 | -| 排序方法 | 直接插入排序 | -| 时间复杂度平均情况 | O(N2) | -| 时间复杂度最坏情况 | O(N2) | -| 时间复杂度最好情况 | O(N) | -| 空间复杂度 | O(1) | -| 稳定性 | 稳定 | -| 复杂性 | 简单 | - -#### 时间复杂度 - -当数据**正序**时,执行效率**最好**,每次插入都不用移动前面的元素,时间复杂度为 **O(N)**。 - -当数据**反序**时,执行效率**最差**,每次插入都要前面的元素后移,时间复杂度为 **O(N2)**。 - -所以,**数据越接近正序,直接插入排序的算法性能越好**。 - -#### 空间复杂度 - -由直接插入排序算法可知,我们在排序过程中,需要一个临时变量存储要插入的值,所以空间复杂度为 **1** 。 - -#### 算法稳定性 - -直接插入排序的过程中,不需要改变相等数值元素的位置,所以它是**稳定的**算法。 - -### 示例代码 - -[我的 Github 测试例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java) - -样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。 - -## 希尔排序 - -### 要点 - -> 希尔(Shell)排序又称为**缩小增量排序**,它是一种**插入排序**。它**是直接插入排序算法的一种威力加强版**。 - -该方法因 DL.Shell 于 1959 年提出而得名。 - -### 算法思想 - -希尔排序的**基本思想**是: - -把记录按**步长 gap** 分组,对每组记录采用**直接插入排序**方法进行排序。 -随着**步长逐渐减小**,所分成的组包含的记录越来越多,当步长的值减小到 **1** 时,整个数据合成为一组,构成一组有序记录,则完成排序。 - -我们来通过演示图,更深入的理解一下这个过程。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/shell-sort.png) - -在上面这幅图中: - -初始时,有一个大小为 10 的无序序列。 - -- 在**第一趟排序中**,我们不妨设 gap1 = N / 2 = 5,即相隔距离为 5 的元素组成一组,可以分为 5 组。 - - 接下来,按照直接插入排序的方法对每个组进行排序。 -- 在** 第二趟排序中**,我们把上次的 gap 缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组。 - - 按照直接插入排序的方法对每个组进行排序。 -- 在**第三趟排序中**,再次把 gap 缩小一半,即 gap3 = gap2 / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组。 - - 按照直接插入排序的方法对每个组进行排序。此时,**排序已经结束**。 - -需要注意一下的是,图中有两个相等数值的元素 **5** 和 **5** 。我们可以清楚的看到,在排序过程中,**两个元素位置交换了**。 - -所以,希尔排序是不稳定的算法。 - -**核心代码** - -```java -public void shellSort(int[] list) { - int gap = list.length / 2; - - while (1 <= gap) { - // 把距离为 gap 的元素编为一个组,扫描所有组 - for (int i = gap; i < list.length; i++) { - int j = 0; - int temp = list[i]; - - // 对距离为 gap 的元素组进行排序 - for (j = i - gap; j >= 0 && temp < list[j]; j = j - gap) { - list[j + gap] = list[j]; - } - list[j + gap] = temp; - } - - System.out.format("gap = %d:\t", gap); - printAll(list); - gap = gap / 2; // 减小增量 - } -} -``` - -### 算法分析 - -**希尔排序的算法性能** - -| 参数 | 结果 | -| ------------------ | --------- | -| 排序类别 | 插入排序 | -| 排序方法 | 希尔排序 | -| 时间复杂度平均情况 | O(Nlog2N) | -| 时间复杂度最坏情况 | O(N1.5) | -| 时间复杂度最好情况 | | -| 空间复杂度 | O(1) | -| 稳定性 | 不稳定 | -| 复杂性 | 较复杂 | - -#### 时间复杂度 - -步长的选择是希尔排序的重要部分。只要最终步长为 1 任何步长序列都可以工作。 - -算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为 1 进行排序。当步长为 1 时,算法变为插入排序,这就保证了数据一定会被排序。 - -Donald Shell 最初建议步长选择为 N/2 并且对步长取半直到步长达到 1。虽然这样取可以比 O(N2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长 5 进行了排序然后再以步长 3 进行排序,那么该数列不仅是以步长 3 有序,而且是以步长 5 有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。 - -已知的最好步长序列是由 Sedgewick 提出的(1, 5, 19, 41, 109,...),该序列的项来自这两个算式。 - -这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长序列的希尔排序比插入排序和堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。 - -#### 算法稳定性 - -由上文的**希尔排序算法演示图**即可知,希尔排序中相等数据可能会交换位置,所以希尔排序是**不稳定**的算法。 - -#### 直接插入排序和希尔排序的比较 - -- 直接插入排序是**稳定的**;而希尔排序是**不稳定**的。 -- 直接插入排序更适合于原始记录基本**有序**的集合。 -- 希尔排序的比较次数和移动次数都要比直接插入排序少,当 N 越大时,效果越明显。 -- 在希尔排序中,增量序列 gap 的取法必须满足:**最后一个步长必须是 1 。 ** -- 直接插入排序也**适用于链式存储结构**;希尔排序**不适用于链式结构**。 - -### 示例代码 - -[我的 Github 测试例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java) - -样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。 - -## 简单选择排序 - -### 要点 - -> 简单选择排序是一种**选择排序**。 -> -> **选择排序**:每趟从待排序的记录中选出关键字最小的记录,顺序放在已排序的记录序列末尾,直到全部排序结束为止。 - -### 算法思想 - -1. 从待排序序列中,找到关键字最小的元素; -2. 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换; -3. 从余下的 N - 1 个元素中,找出关键字最小的元素,重复 1、2 步,直到排序结束。 - -如图所示,每趟排序中,将当前**第 i 小的元素放在位置 i **上。 - -**核心代码** - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/selection-sort.png) - -### 算法分析 - -**简单选择排序算法的性能** - -| 参数 | 结果 | -| ------------------ | ------------ | -| 排序类别 | 选择排序 | -| 排序方法 | 简单选择排序 | -| 时间复杂度平均情况 | O(N2) | -| 时间复杂度最坏情况 | O(N2) | -| 时间复杂度最好情况 | O(N2) | -| 空间复杂度 | O(1) | -| 稳定性 | 不稳定 | -| 复杂性 | 简单 | - -#### 时间复杂度 - -简单选择排序的比较次数与序列的初始排序无关。 假设待排序的序列有 **N** 个元素,则**比较次数总是 N (N - 1) / 2 **。 - -而移动次数与序列的初始排序有关。当序列正序时,移动次数最少,为 **0**. - -当序列反序时,移动次数最多,为 **3N (N - 1) / 2**。 - -所以,综合以上,简单排序的时间复杂度为 **O(N2)**。 - -#### 空间复杂度 - -简单选择排序需要占用一个临时空间,在交换数值时使用。 - -### 示例代码 - -[我的 Github 测试例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java) - -样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。 - -## 堆排序 - -### 要点 - -在介绍堆排序之前,首先需要说明一下,堆是个什么玩意儿。 - -**堆**是一棵**顺序存储**的**完全二叉树**。 - -其中每个结点的关键字都**不大于**其孩子结点的关键字,这样的堆称为**小根堆**。 -其中每个结点的关键字都**不小于**其孩子结点的关键字,这样的堆称为**大根堆**。 -举例来说,对于 n 个元素的序列 {R0, R1, ... , Rn} 当且仅当满足下列关系之一时,称之为堆: - -- **Ri <= R2i+1 且 Ri <= R2i+2 (小根堆)** -- **Ri >= R2i+1 且 Ri >= R2i+2 (大根堆)** - -其中 i=1,2,…,n/2 向下取整; - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/heap-sort.png) - -如上图所示,序列 R{3, 8,15, 31, 25} 是一个典型的小根堆。 - -堆中有两个父结点,元素 3 和元素 8。 - -元素 3 在数组中以 R[0] 表示,它的左孩子结点是 R[1],右孩子结点是 R[2]。 - -元素 8 在数组中以 R[1] 表示,它的左孩子结点是 R[3],右孩子结点是 R[4],它的父结点是 R[0]。可以看出,它们**满足以下规律**: - -设当前元素在数组中以 **R[i]** 表示,那么, - -- 它的**左孩子结点**是:**R[2\*i+1]**; -- 它的**右孩子结点**是:**R[2\*i+2]**; -- 它的**父结点**是:**R[(i-1)/2]**; -- R[i] <= R[2*i+1] 且 R[i] <= R[2i+2]。 - -### 算法思想 - -- 首先,按堆的定义将数组 R[0..n]调整为堆(这个过程称为创建初始堆),交换 R[0]和 R[n]; -- 然后,将 R[0..n-1]调整为堆,交换 R[0]和 R[n-1]; -- 如此反复,直到交换了 R[0]和 R[1]为止。 - -以上思想可归纳为两个操作: - -1. 根据初始数组去**构造初始堆**(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。 -2. 每次**交换第一个和最后一个元素,输出最后一个元素**(最大值),然后把剩下元素**重新调整**为大根堆。 - -当输出完最后一个元素后,这个数组已经是按照从小到大的顺序排列了。 - -先通过详细的实例图来看一下,如何构建初始堆。 - -设有一个无序序列 { 1, 3,4, 5, 2, 6, 9, 7, 8, 0 }。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/heap-sort-02.png) - -构造了初始堆后,我们来看一下完整的堆排序处理: - -还是针对前面提到的无序序列 { 1,3, 4, 5, 2, 6, 9, 7, 8, 0 } 来加以说明。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/heap-sort-03.png) - -相信,通过以上两幅图,应该能很直观的演示堆排序的操作处理。 - -**核心代码** - -```java -public void HeapAdjust(int[] array2, int parent, int length) { - int temp = array2[parent]; // temp保存当前父节点 - int child = 2 * parent + 1; // 先获得左孩子 - - while (child < length) { - // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点 - if (child + 1 < length && array2[child] < array2[child + 1]) { - child++; - } - - // 如果父结点的值已经大于孩子结点的值,则直接结束 - if (temp >= array2[child]) - break; - - // 把孩子结点的值赋给父结点 - array2[parent] = array2[child]; - - // 选取孩子结点的左孩子结点,继续向下筛选 - parent = child; - child = 2 * child + 1; - } - - array2[parent] = temp; -} - -public void heapSort(int[] list) { - // 循环建立初始堆 - for (int i = list.length / 2; i >= 0; i--) { - HeapAdjust(list, i, list.length); - } - - // 进行n-1次循环,完成排序 - for (int i = list.length - 1; i > 0; i--) { - // 最后一个元素和第一元素进行交换 - int temp = list[i]; - list[i] = list[0]; - list[0] = temp; - - // 筛选 R[0] 结点,得到i-1个结点的堆 - HeapAdjust(list, 0, i); - System.out.format("第 %d 趟: \t", list.length - i); - printPart(list, 0, list.length - 1); - } -} -``` - -### 算法分析 - -**堆排序算法的总体情况** - -| 参数 | 结果 | -| ------------------ | --------- | -| 排序类别 | 选择排序 | -| 排序方法 | 堆排序 | -| 时间复杂度平均情况 | O(nlog2n) | -| 时间复杂度最坏情况 | O(nlog2n) | -| 时间复杂度最好情况 | O(nlog2n) | -| 空间复杂度 | O(1) | -| 稳定性 | 不稳定 | -| 复杂性 | 较复杂 | - -#### 时间复杂度 - -堆的存储表示是**顺序的**。因为堆所对应的二叉树为完全二叉树,而完全二叉树通常采用顺序存储方式。 - -当想得到一个序列中第 **k** 个最小的元素之前的部分排序序列,最好采用堆排序。 - -因为堆排序的时间复杂度是 **O(n+klog2n)**,若 **k ≤ n/log2n**,则可得到的时间复杂度为 **O(n)**。 - -#### 算法稳定性 - -堆排序是一种**不稳定**的排序方法。 - -因为在堆的调整过程中,关键字进行比较和交换所走的是该结点到叶子结点的一条路径, - -因此对于相同的关键字就可能出现排在后面的关键字被交换到前面来的情况。 - -### 示例代码 - -[我的 Github 测试例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java) - -样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。 - -## 归并排序 - -### 要点 - -> 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用**分治法(Divide and Conquer)**的一个非常典型的应用。 -> -> 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为**二路归并**。 - -### 算法思想 - -将待排序序列 R[0...n-1] 看成是 n 个长度为 1 的有序序列,将相邻的有序表成对归并,得到 n/2 个长度为 2 的有序表;将这些有序序列再次归并,得到 n/4 个长度为 4 的有序序列;如此反复进行下去,最后得到一个长度为 n 的有序序列。 - -综上可知: - -归并排序其实要做两件事: - -- “分解”——将序列每次**折半划分**。 -- “合并”——将划分后的序列段**两两合并后排序**。 - -我们先来考虑第二步,**如何合并**? - -在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。 - -这两个有序序列段分别为 R[low, mid] 和 R[mid+1, high]。 - -先将他们合并到一个局部的**暂存数组**R2 中,带合并完成后再将 R2 复制回 R 中。 - -为了方便描述,我们称 R[low, mid] 第一段,R[mid+1, high] 为第二段。 - -每次从两个段中取出一个记录进行关键字的比较,将较小者放入 R2 中。最后将各段中余下的部分直接复制到 R2 中。 - -经过这样的过程,R2 已经是一个有序的序列,再将其复制回 R 中,一次合并排序就完成了。 - -**核心代码** - -```java -public void Merge(int[] array2, int low, int mid, int high) { - int i = low; // i是第一段序列的下标 - int j = mid + 1; // j是第二段序列的下标 - int k = 0; // k是临时存放合并序列的下标 - int[] array2 = new int[high - low + 1]; // array2是临时合并序列 - - // 扫描第一段和第二段序列,直到有一个扫描结束 - while (i <= mid && j <= high) { - // 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描 - if (array2[i] <= array2[j]) { - array2[k] = array2[i]; - i++; - k++; - } else { - array2[k] = array2[j]; - j++; - k++; - } - } - - // 若第一段序列还没扫描完,将其全部复制到合并序列 - while (i <= mid) { - array2[k] = array2[i]; - i++; - k++; - } - - // 若第二段序列还没扫描完,将其全部复制到合并序列 - while (j <= high) { - array2[k] = array2[j]; - j++; - k++; - } - - // 将合并序列复制到原始序列中 - for (k = 0, i = low; i <= high; i++, k++) { - array2[i] = array2[k]; - } -} -``` - -掌握了合并的方法,接下来,让我们来了解**如何分解**。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/merge-sort.png) - -在某趟归并中,设各子表的长度为 **gap**,则归并前 R[0...n-1] 中共有 **n/gap** 个有序的子表:`R[0...gap-1]`, `R[gap...2*gap-1]`, ... , `R[(n/gap)*gap ... n-1]`。 - -调用 Merge **将相邻的子表归并**时,必须对表的特殊情况进行特殊处理。 - -若子表个数为奇数,则最后一个子表无须和其他子表归并(即本趟处理轮空):若子表个数为偶数,则要注意到最后一对子表中后一个子表区间的上限为 n-1。 - -**核心代码** - -```java -public void MergePass(int[] array2, int gap, int length) { - int i = 0; - - // 归并gap长度的两个相邻子表 - for (i = 0; i + 2 * gap - 1 < length; i = i + 2 * gap) { - Merge(array2, i, i + gap - 1, i + 2 * gap - 1); - } - - // 余下两个子表,后者长度小于gap - if (i + gap - 1 < length) { - Merge(array2, i, i + gap - 1, length - 1); - } -} - -public int[] sort(int[] list) { - for (int gap = 1; gap < list.length; gap = 2 * gap) { - MergePass(list, gap, list.length); - System.out.print("gap = " + gap + ":\t"); - this.printAll(list); - } - return list; -} -``` - -### 算法分析 - -**归并排序算法的性能** - -| 参数 | 结果 | -| ------------------ | --------- | -| 排序类别 | 归并排序 | -| 排序方法 | 归并排序 | -| 时间复杂度平均情况 | O(nlog2n) | -| 时间复杂度最坏情况 | O(nlog2n) | -| 时间复杂度最好情况 | O(nlog2n) | -| 空间复杂度 | O(n) | -| 稳定性 | 稳定 | -| 复杂性 | 较复杂 | - -#### 时间复杂度 - -归并排序的形式就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的可以得出它的时间复杂度是 **O(n\*log2n)**。 - -#### 空间复杂度 - -由前面的算法说明可知,算法处理过程中,需要一个大小为 **n** 的临时存储空间用以保存合并序列。 - -#### 算法稳定性 - -在归并排序中,相等的元素的顺序不会改变,所以它是**稳定的**算法。 - -#### 归并排序和堆排序、快速排序的比较 - -若从空间复杂度来考虑:首选堆排序,其次是快速排序,最后是归并排序。 - -若从稳定性来考虑,应选取归并排序,因为堆排序和快速排序都是不稳定的。 - -若从平均情况下的排序速度考虑,应该选择快速排序。 - -### 示例代码 - -[我的 Github 测试例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java) - -样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。 - -## 基数排序 - -### 要点 - -基数排序与本系列前面讲解的七种排序方法都不同,它**不需要比较关键字的大小**。 - -它是根据关键字中各位的值,通过对排序的 N 个元素进行若干趟“分配”与“收集”来实现排序的。 - -不妨通过一个具体的实例来展示一下,基数排序是如何进行的。 - -设有一个初始序列为: R {50, 123, 543, 187, 49, 30,0, 2, 11, 100}。 - -我们知道,任何一个阿拉伯数,它的各个位数上的基数都是以 0\~9 来表示的。 - -所以我们不妨把 0\~9 视为 10 个桶。 - -我们先根据序列的个位数的数字来进行分类,将其分到指定的桶中。例如:R[0] = 50,个位数上是 0,将这个数存入编号为 0 的桶中。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/algorithm/sort/radix-sort.png) - -分类后,我们在从各个桶中,将这些数按照从编号 0 到编号 9 的顺序依次将所有数取出来。 - -这时,得到的序列就是个位数上呈递增趋势的序列。 - -按照个位数排序: {50, 30, 0, 100, 11, 2, 123,543, 187, 49}。 - -接下来,可以对十位数、百位数也按照这种方法进行排序,最后就能得到排序完成的序列。 - -### 算法分析 - -**基数排序的性能** - -| 参数 | 结果 | -| ------------------ | --------- | -| 排序类别 | 基数排序 | -| 排序方法 | 基数排序 | -| 时间复杂度平均情况 | O(d(n+r)) | -| 时间复杂度最坏情况 | O(d(n+r)) | -| 时间复杂度最好情况 | O(d(n+r)) | -| 空间复杂度 | O(n+r) | -| 稳定性 | 稳定 | -| 复杂性 | 较复杂 | - -#### 时间复杂度 - -通过上文可知,假设在基数排序中,r 为基数,d 为位数。则基数排序的时间复杂度为 **O(d(n+r))**。 - -我们可以看出,基数排序的效率和初始序列是否有序没有关联。 - -#### 空间复杂度 - -在基数排序过程中,对于任何位数上的基数进行“装桶”操作时,都需要 **n+r** 个临时空间。 - -#### 算法稳定性 - -在基数排序过程中,每次都是将当前位数上相同数值的元素统一“装桶”,并不需要交换位置。所以基数排序是**稳定**的算法。 - -### 示例代码 - -[我的 Github 测试例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java) - -样本包含:数组个数为奇数、偶数的情况;元素重复或不重复的情况。且样本均为随机样本,实测有效。 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/01.\346\240\221\345\222\214\344\272\214\345\217\211\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/01.\346\240\221\345\222\214\344\272\214\345\217\211\346\240\221.md" deleted file mode 100644 index 8660f49..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/01.\346\240\221\345\222\214\344\272\214\345\217\211\346\240\221.md" +++ /dev/null @@ -1,183 +0,0 @@ ---- -title: 树和二叉树 -categories: - - 数据结构和算法 - - 树 -tags: - - 数据结构 - - 树 - - 二叉树 - - 完全二叉树 -abbrlink: dd5c0739 -date: 2014-06-15 15:39:23 -permalink: /pages/92e4c1/ ---- - -# 树和二叉树 - -## 树 - -### 什么是树 - -在计算机科学中,**树**(英语:tree)是一种[抽象数据类型](https://zh.wikipedia.org/wiki/抽象資料型別)(ADT)或是实现这种抽象数据类型的[数据结构](https://zh.wikipedia.org/wiki/資料結構),用来模拟具[有树状结构](https://zh.wikipedia.org/wiki/樹狀結構)性质的数据集合。它是由 n(n>0)个有限节点组成一个具有层次关系的[集合](https://zh.wikipedia.org/wiki/集合)。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 - -它具有以下的特点: - -- 每个节点都只有有限个子节点或无子节点。 -- 树有且仅有一个根节点。 -- 根节点没有父节点;非根节点有且仅有一个父节点。 -- 每个非根节点可以分为多个不相交的子树。 -- 树里面没有环路。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403163620.png) - -### 树的术语 - -- **节点的度**:一个节点含有的子树的个数称为该节点的度; -- **树的度**:一棵树中,最大的节点度称为树的度; -- **叶子节点**或**终端节点**:度为零的节点; -- **非终端节点**或**分支节点**:度不为零的节点; -- **父节点**:若一个节点含有子节点,则这个节点称为其子节点的父节点; -- **子节点**:一个节点含有的子树的根节点称为该节点的子节点; -- **兄弟节点**:具有相同父节点的节点互称为兄弟节点; -- **堂兄弟节点**:父节点在同一层的节点互为堂兄弟; -- **节点的祖先**:从根到该节点所经分支上的所有节点; -- **子孙**:以某节点为根的子树中任一节点都称为该节点的子孙。 -- **森林**:由 m(m>=0)棵互不相交的树的集合称为森林; - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403164732.png) - -- **节点的高度**:节点到叶子节点的最长路径。高度是从下往上度量。 -- **节点的深度**:根节点到该节点的最长路径。深度是从上往下度量。 -- **节点的层次**:节点的深度 + 1。 -- **树的高度**:根节点的高度。 - -### 树的性质 - -- 树中的节点数等于所有节点的度数加 1。 -- 度为 m 的树中第 `i` 层上至多有 $$m^{i-1}$$ 个节点($$i ≥ 1$$)。 -- 高度为 h 的 m 次树至多有 $$(m^h-1)/(m-1)$$ 个节点。 -- 具有 n 个节点的 m 次树的最小高度为 $$\log_m{(n(m-1)+1)}$$ 。 - -### 树的种类 - -**无序树**:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为[自由树](https://zh.wikipedia.org/wiki/自由树); - -**有序树**:树中任意节点的子节点之间有顺序关系,这种树称为有序树; - -- 二叉树:每个节点最多含有两个子树的树称为二叉树; - - **完全二叉树**:对于一颗二叉树,假设其深度为 d(d>1)。除了第 d 层外,其它各层的节点数目均已达最大值,且第 d 层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树; -- [满二叉树](https://zh.wikipedia.org/wiki/满二叉树):所有叶节点都在最底层的完全二叉树; -- [平衡二叉树](https://zh.wikipedia.org/wiki/平衡二叉树)([AVL 树](https://zh.wikipedia.org/wiki/AVL树)):当且仅当任何节点的两棵子树的高度差不大于 1 的二叉树; -- [排序二叉树](https://zh.wikipedia.org/wiki/排序二元樹)([二叉查找树](https://zh.wikipedia.org/wiki/二叉查找树)(英语:Binary Search Tree)):也称二叉搜索树、有序二叉树; -- [霍夫曼树](https://zh.wikipedia.org/wiki/霍夫曼树):[带权路径](https://zh.wikipedia.org/w/index.php?title=带权路径&action=edit&redlink=1)最短的二叉树称为哈夫曼树或最优二叉树; -- [B 树](https://zh.wikipedia.org/wiki/B树):一种对读写操作进行优化的自平衡的二叉查找树,能够保持数据有序,拥有多于两个子树。 - -## 二叉树 - -二叉树中的每个节点最多有两个子节点,分别是**左子节点**和**右子节点**。 - -### 二叉树的性质 - -1. 二叉树第 i 层上的结点数目最多为 **2i-1** (i≥1)。 -2. 深度为 k 的二叉树至多有 **2k-1** 个结点(k≥1)。 -3. 包含 n 个结点的二叉树的高度至少为 **log2(n+1)**。 -4. 在任意一棵二叉树中,若终端结点的个数为 n0,度为 2 的结点数为 n2,则 n0=n2+1。 - -### 满二叉树 - -除了叶子节点之外,每个节点都有左右两个子节点,这种二叉树就叫作**满二叉树**。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403183927.png) - -### 完全二叉树 - -叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大,这种二叉树叫作**完全二叉树**。 - -特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403183640.png) - -存储一棵二叉树,有两种方法,一种是基于指针或者引用的二叉链式存储法,一种是基于数组的顺序存储法。 - -**二叉链式存储法** - -每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403212249.png) - -**顺序存储法** - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220403214627.png) - -如果节点 X 存储在数组中下标为 i 的位置,下标为 2 _ i 的位置存储的就是左子节点,下标为 2 _ i + 1 的位置存储的就是右子节点。反过来,下标为 i/2 的位置存储就是它的父节点。通过这种方式,我们只要知道根节点存储的位置(一般情况下,为了方便计算子节点,根节点会存储在下标为 1 的位置),这样就可以通过下标计算,把整棵树都串起来。 - -如果是非完全二叉树,其实会浪费比较多的数组存储空间。所以,如果某棵二叉树是一棵完全二叉树,那用数组存储无疑是最节省内存的一种方式。因为数组的存储方式并不需要像链式存储法那样,要存储额外的左右子节点的指针。这也是 为什么完全二叉树要求最后一层的子节点都靠左的原因。 - -### 二叉树的遍历 - -二叉树的遍历有三种方式: - -- **前序遍历**:对于树中的任意节点来说,先打印这个节点,然后再打印它的左子树,最后打印它的右子树。 -- **中序遍历**:对于树中的任意节点来说,先打印它的左子树,然后再打印它本身,最后打印它的右子树。 -- **后序遍历**是指,对于树中的任意节点来说,先打印它的左子树,然后再打印它的右子树,最后打印这个节点本身。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220404201713.png) - -## 二叉查找树 - -二叉查找树是二叉树中最常用的一种类型,也叫二叉搜索树。顾名思义,二叉查找树是为了实现快速查找而生的。不过,它不仅仅支持快速查找一个数据,还支持快速插入、删除一个数据。 - -**二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。** - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405172359.png) - -### 二叉查找树的查找 - -首先,我们看如何在二叉查找树中查找一个节点。我们先取根节点,如果它等于我们要查找的数据,那就返回。如果要查找的数据比根节点的值小,那就在左子树中递归查找;如果要查找的数据比根节点的值大,那就在右子树中递归查找。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405172537.png) - -### 二叉查找树的插入 - -如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;如果不为空,就再递归遍历右子树,查找插入位置。同理,如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再递归遍历左子树,查找插入位置。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405172549.png) - -### 二叉查找树的删除 - -第一种情况是,如果要删除的节点没有子节点,我们只需要直接将父节点中,指向要删除节点的指针置为 null。 - -第二种情况是,如果要删除的节点只有一个子节点(只有左子节点或者右子节点),我们只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405200219.png) - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405200234.png) - -第三种情况是,如果要删除的节点有两个子节点,这就比较复杂了。我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上。然后再删除掉这个最小节点,因为最小节点肯定没有左子节点(如果有左子结点,那就不是最小节点了),所以,我们可以应用上面两条规则来删除这个最小节点。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405200456.png) - -### 二叉查找树的时间复杂度 - -不管操作是插入、删除还是查找,**时间复杂度其实都跟树的高度成正比,也就是 O(log n)**。 - -二叉查找树的形态各式各样。比如这个图中,对于同一组数据,我们构造了三种二叉查找树。它们的查找、插入、删除操作的执行效率都是不一样的。图中第一种二叉查找树,根节点的左右子树极度不平衡,已经退化成了链表,所以查找的时间复杂度就变成了 O(n)。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220405234630.png) - -### 为什么需要二叉查找树 - -第一,哈希表中的数据是无序存储的,如果要输出有序的数据,需要先进行排序。而对于二叉查找树来说,我们只需要中序遍历,就可以在 O(n) 的时间复杂度内,输出有序的数据序列。 - -第二,哈希表扩容耗时很多,而且当遇到散列冲突时,性能不稳定,尽管二叉查找树的性能不稳定,但是在工程中,我们最常用的平衡二叉查找树的性能非常稳定,时间复杂度稳定在 O(logn)。 - -第三,笼统地来说,尽管哈希表的查找等操作的时间复杂度是常量级的,但因为哈希冲突的存在,这个常量不一定比 logn 小,所以实际的查找速度可能不一定比 O(logn) 快。加上哈希函数的耗时,也不一定就比平衡二叉查找树的效率高。 - -第四,哈希表的构造比二叉查找树要复杂,需要考虑的东西很多。比如散列函数的设计、冲突解决办法、扩容、缩容等。平衡二叉查找树只需要考虑平衡性这一个问题,而且这个问题的解决方案比较成熟、固定。 - -最后,为了避免过多的散列冲突,哈希表装载因子不能太大,特别是基于开放寻址法解决冲突的哈希表,不然会浪费一定的存储空间。 - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/02.\345\240\206.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/02.\345\240\206.md" deleted file mode 100644 index c66e6e1..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/02.\345\240\206.md" +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: 堆 -categories: - - 数据结构和算法 - - 树 -tags: - - 数据结构 - - 树 - - 二叉树 - - 堆 -abbrlink: fab451a5 -date: 2015-03-09 16:01:27 -permalink: /pages/ce297c/ ---- - -# 堆 - -## 什么是堆? - -堆(Heap)是一个可以被看成近似完全二叉树的数组。 - -- **堆是一个完全二叉树**。完全二叉树要求,除了最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列。 -- **堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值**。 - -堆可以分为大顶堆和小顶堆。 - -- 对于每个节点的值都大于等于子树中每个节点值的堆,叫作“**大顶堆**”。 - -- 对于每个节点的值都小于等于子树中每个节点值的堆,叫作“**小顶堆**”。 - -## 如何实现堆 - -完全二叉树比较适合用数组来存储。用数组来存储完全二叉树是非常节省存储空间的。因为我们不需要存储左右子节点的指针,单纯地通过数组的下标,就可以找到一个节点的左右子节点和父节点。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220311112542.jpg) - -堆常见的操作: - -- HEAPIFY 建堆:把一个乱序的数组变成堆结构的数组,时间复杂度为 $$O(n)$$。 -- HEAPPUSH:把一个数值放进已经是堆结构的数组中,并保持堆结构,时间复杂度为 $$O(log N)$$ -- HEAPPOP:从最大堆中取出最大值或从最小堆中取出最小值,并将剩余的数组保持堆结构,时间复杂度为 $$O(log N)$$。 -- HEAPSORT:借由 HEAPFY 建堆和 HEAPPOP 堆数组进行排序,时间复杂度为$$ O(N log N)$$,空间复杂度为 $$O(1)$$。 - -## 堆的应用场景 - -### 求 TOP N - -堆结构的一个常见应用是建立优先队列(Priority Queue)。 - -求 Top K 的问题抽象成两类。一类是针对静态数据集合;另一类是针对动态数据集合 - -### 优先级队列 - -在优先级队列中,数据的出队顺序不是先进先出,而是按照优先级来,优先级最高的,最先出队。 - -堆和优先级队列非常相似:往优先级队列中插入一个元素,就相当于往堆中插入一个元素;从优先级队列中取出优先级最高的元素,就相当于取出堆顶元素。 - -> 参考:Java 的 `PriorityQueue` 类 - -### 求中位数 diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/03.B+\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/03.B+\346\240\221.md" deleted file mode 100644 index 908780d..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/03.B+\346\240\221.md" +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: B+树 -categories: - - 数据结构和算法 - - 树 -tags: - - 数据结构 - - 树 - - 二叉树 - - B+ 树 -abbrlink: 17426722 -date: 2022-03-13 22:37:27 -permalink: /pages/3fd76e/ ---- - -# B+树 - -## 什么是 B+树 - -B+树是在二叉查找树的基础上进行了改造:树中的节点并不存储数据本身,而是只是作为索引。每个叶子节点串在一条链表上,链表中的数据是从小到大有序的。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220311092926.jpg) - -改造之后,如果我们要求某个区间的数据。我们只需要拿区间的起始值,在树中进行查找,当查找到某个叶子节点之后,我们再顺着链表往后遍历,直到链表中的结点数据值大于区间的终止值为止。所有遍历到的数据,就是符合区间值的所有数据。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220311092929.jpg) - -但是,我们要为几千万、上亿的数据构建索引,如果将索引存储在内存中,尽管内存访问的速度非常快,查询的效率非常高,但是,占用的内存会非常多。 - -比如,我们给一亿个数据构建二叉查找树索引,那索引中会包含大约 1 亿个节点,每个节点假设占用 16 个字节,那就需要大约 1GB 的内存空间。给一张表建立索引,我们需要 1GB 的内存空间。如果我们要给 10 张表建立索引,那对内存的需求是无法满足的。如何解决这个索引占用太多内存的问题呢? - -我们可以借助时间换空间的思路,把索引存储在硬盘中,而非内存中。我们都知道,硬盘是一个非常慢速的存储设备。通常内存的访问速度是纳秒级别的,而磁盘访问的速度是毫秒级别的。读取同样大小的数据,从磁盘中读取花费的时间,是从内存中读取所花费时间的上万倍,甚至几十万倍。 - -这种将索引存储在硬盘中的方案,尽管减少了内存消耗,但是在数据查找的过程中,需要读取磁盘中的索引,因此数据查询效率就相应降低很多。 - -二叉查找树,经过改造之后,支持区间查找的功能就实现了。不过,为了节省内存,如果把树存储在硬盘中,那么每个节点的读取(或者访问),都对应一次磁盘 IO 操作。树的高度就等于每次查询数据时磁盘 IO 操作的次数。 - -我们前面讲到,比起内存读写操作,磁盘 IO 操作非常耗时,所以我们优化的重点就是尽量减少磁盘 IO 操作,也就是,尽量降低树的高度。那如何降低树的高度呢? - -我们来看下,如果我们把索引构建成 m 叉树,高度是不是比二叉树要小呢?如图所示,给 16 个数据构建二叉树索引,树的高度是 4,查找一个数据,就需要 4 个磁盘 IO 操作(如果根节点存储在内存中,其他结点存储在磁盘中),如果对 16 个数据构建五叉树索引,那高度只有 2,查找一个数据,对应只需要 2 次磁盘操作。如果 m 叉树中的 m 是 100,那对一亿个数据构建索引,树的高度也只是 3,最多只要 3 次磁盘 IO 就能获取到数据。磁盘 IO 变少了,查找数据的效率也就提高了。 - -## 为什么需要 B+树 - -关系型数据库中常用 B+ 树作为索引,这是为什么呢? - -思考以下经典应用场景 - -- 根据某个值查找数据,比如 `select * from user where id=1234`。 -- 根据区间值来查找某些数据,比如 `select * from user where id > 1234 and id < 2345`。 - -为了提高查询效率,需要使用索引。而对于索引的性能要求,主要考察**执行效率和存储空间**。如果让你选择一种数据结构去存储索引,你会如何考虑? - -以一些常见数据结构为例: - -- **哈希表**:哈希表的查询性能很好,时间复杂度是 `O(1)`。但是,哈希表不能支持按照区间快速查找数据。所以,哈希表不能满足我们的需求。 -- **平衡二叉查找树**:尽管平衡二叉查找树查询的性能也很高,时间复杂度是 `O(logn)`。而且,对树进行中序遍历,我们还可以得到一个从小到大有序的数据序列,但这仍然不足以支持按照区间快速查找数据。 -- **跳表**:跳表是在链表之上加上多层索引构成的。它支持快速地插入、查找、删除数据,对应的时间复杂度是 `O(logn)`。并且,跳表也支持按照区间快速地查找数据。我们只需要定位到区间起点值对应在链表中的结点,然后从这个结点开始,顺序遍历链表,直到区间终点对应的结点为止,这期间遍历得到的数据就是满足区间值的数据。 - -实际上,数据库索引所用到的数据结构跟跳表非常相似,叫作 B+ 树。不过,它是通过二叉查找树演化过来的,而非跳表。B+树的应用场景 - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/04.LSM\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/04.LSM\346\240\221.md" deleted file mode 100644 index c5d67cd..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/04.LSM\346\240\221.md" +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: LSM树 -categories: - - 数据结构和算法 - - 树 -tags: - - 数据结构 - - 树 - - LSM 树 -abbrlink: 5bf5ed66 -date: 2022-03-16 09:27:21 -permalink: /pages/4a217d/ ---- - -# LSM 树 - -## 什么是 LSM 树 - -LSM 树具有以下 3 个特点: - -1. 将索引分为内存和磁盘两部分,并在内存达到阈值时启动树合并(Merge Trees); -2. 用批量写入代替随机写入,并且用预写日志 WAL 技术(Write AheadLog,预写日志技术)保证内存数据,在系统崩溃后可以被恢复; -3. 数据采取类似日志追加写的方式写入(Log Structured)磁盘,以顺序写的方式提高写 - 入效率。 - -LSM 树的这些特点,使得它相对于 B+ 树,在写入性能上有大幅提升。所以,许多 NoSQL 系统都使用 LSM 树作为检索引擎,而且还对 LSM 树进行了优化以提升检索性能。 - -LSM 树就是根据这个思路设计了这样一个机制:当数据写入时,延迟写磁盘,将数据先存放在内存中的树里,进行常规的存储和查询。当内存中的树持续变大达到阈值时,再批量地以块为单位写入磁盘的树中。因此,LSM 树至少需要由两棵树组成,一棵是存储在内存中较小的 C0 树,另一棵是存储在磁盘中较大的 C1 树。 - -### 如何将内存数据与磁盘数据合并 - -可以参考两个有序链表归并排序的过程,将 C0 树和 C1 树的所有叶子节点中存储的数据,看作是两个有序链表,那滚动合并问题就变成了我们熟悉的两个有序链表的归并问题。不过由于涉及磁盘操作,那为了提高写入效率和检索效率,我们还需要针对磁盘的特性,在一些归并细节上进行优化。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220316105440.png) - -由于磁盘具有顺序读写效率高的特性,因此,为了提高 C1 树中节点的读写性能,除了根节点以外的节点都要尽可能地存放到连续的块中,让它们能作为一个整体单位来读写。这种包含多个节点的块就叫作多页块(Multi-Pages Block)。 - -第一步,以多页块为单位,将 C1 树的当前叶子节点从前往后读入内存。读入内存的多页块,叫作清空块(Emptying Block),意思是处理完以后会被清空。 - -第二步,将 C0 树的叶子节点和清空块中的数据进行归并排序,把归并的结果写入内存的一个新块中,叫作填充块(Filling Block)。 - -第三步,如果填充块写满了,我们就要将填充块作为新的叶节点集合顺序写入磁盘。这个时候,如果 C0 树的叶子节点和清空块都没有遍历完,我们就继续遍历归并,将数据写入新的填充块。如果清空块遍历完了,我们就去 C1 树中顺序读取新的多页块,加载到清空块中。 - -第四步,重复第三步,直到遍历完 C0 树和 C1 树的所有叶子节点,并将所有的归并结果写入到磁盘。这个时候,我们就可以同时删除 C0 树和 C1 树中被处理过的叶子节点。这样就完成了滚动归并的过程。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220316110736.png) - -### LSM 树是如何检索 - -因为同时存在 C0 和 C1 树,所以要查询一个 key 时,我们会先到 C0 树中查询。如果查询到了则直接返回;如过没有查询到,则查询 C1 树。 - -需要注意一种特殊情况:删除操作。假设某数据在 C0 树中被删除了,但是在 C1 树中仍存在。这此时查询时,可以在 C1 树中查到这个 key,这其实是过期数据了,如何应对这种情况呢?对于被删除的数据,可以将这些数据的 key 插入到 C0 树中,并标记一个删除标志。如果查到了一个带着删除标志的 key,就直接返回查询失败。 - -## 为什么需要 LSM 树 - -在关系型数据库中,通常使用 B+ 树作为索引。B+ 树的数据都存储在叶子节点中,而叶子节点一般都存储在磁盘中。因此,每次插入的新数据都需要随机写入磁盘,而随机写入的性能非常慢。如果是一个日志系统,每秒钟要写入上千条甚至上万条数据,这样的磁盘操作代价会使得系统性能急剧下降,甚至无法使用。 - -操作系统对磁盘的读写是以块为单位的,我们能否以块为单位写入,而不是每次插入一个数据都要随机写入磁盘呢?这样是不是就可以大幅度减少写入操作了呢?解决方案就是:**LSM 树**(Log Structured Merge Trees)。 - -## WAL 技术 - -LSM 树至少需要由两棵树组成,一棵是存储在内存中较小的 C0 树,另一棵是存储在磁盘中较大的 C1 树。 - -如果机器断电或系统崩溃了,那内存中还未写入磁盘的数据岂不就永远丢失了?这种情况我们该如何解决呢? - -为了保证内存中的数据在系统崩溃后能恢复,可以使用 WAL 技术(Write Ahead Log,预写日志技术)将数据第一时间高效写入磁盘进行备份。 - -WAL 技术保存和恢复数据的具体步骤如下: - -1. 内存中的程序在处理数据时,会先将对数据的修改作为一条记录,顺序写入磁盘的 log 文件作为备份。由于磁盘文件的顺序追加写入效率很高,因此许多应用场景都可以接受这种备份处理。 -2. 在数据写入 log 文件后,备份就成功了。接下来,该数据就可以长期驻留在内存中了。 -3. 系统会周期性地检查内存中的数据是否都被处理完了(比如,被删除或者写入磁盘),并且生成对应的检查点(Check Point)记录在磁盘中。然后,我们就可以随时删除被处理完的数据了。这样一来,log 文件就不会无限增长了。 -4. 系统崩溃重启,我们只需要从磁盘中读取检查点,就能知道最后一次成功处理的数据在 log 文件中的位置。接下来,我们就可以把这个位置之后未被处理的数据,从 log 文件中读出,然后重新加载到内存中。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220316104837.png) - -## 参考资料 - -- [检索技术核心 20 讲](https://time.geekbang.org/column/intro/100048401) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/05.\345\255\227\345\205\270\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/05.\345\255\227\345\205\270\346\240\221.md" deleted file mode 100644 index d5916a6..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/05.\345\255\227\345\205\270\346\240\221.md" +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: 字典树 -categories: - - 数据结构和算法 - - 树 -tags: - - 数据结构 - - 树 - - 字典树 -abbrlink: eea60a6a -date: 2022-03-13 22:37:27 -permalink: /pages/0a4984/ ---- - -# 字典树 - -## 什么是字典树 - -Trie 树(又叫「前缀树」或「字典树」)是一种用于快速查询「某个字符串/字符前缀」是否存在的数据结构。 - -- 根节点(Root)不包含字符,除根节点外的每一个节点都仅包含一个字符; -- 从根节点到某一节点路径上所经过的字符连接起来,即为该节点对应的字符串; -- 任意节点的所有子节点所包含的字符都不相同; - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181057.jpg) - -### 字典树的构造 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181243.jpg) - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181425.jpg) - -构建 Trie 树的过程,需要扫描所有的字符串,时间复杂度是 O(n)(n 表示所有字符串的长度和)。 - -**字典树非常耗费内存**。 - -用数组来存储一个节点的子节点的指针。如果字符串中包含从 a 到 z 这 26 个字符,那每个节点都要存储一个长度为 26 的数组,并且每个数组存储一个 8 字节指针(或者是 4 字节,这个大小跟 CPU、操作系统、编译器等有关)。而且,即便一个节点只有很少的子节点,远小于 26 个,比如 3、4 个,我们也要维护一个长度为 26 的数组。 - -用数组来存储一个节点的子节点的指针。如果字符串中包含从 a 到 z 这 26 个字符,那每个节点都要存储一个长度为 26 的数组,并且每个数组存储一个 8 字节指针(或者是 4 字节,这个大小跟 CPU、操作系统、编译器等有关)。而且,即便一个节点只有很少的子节点,远小于 26 个,比如 3、4 个,我们也要维护一个长度为 26 的数组。 - -用数组来存储一个节点的子节点的指针。如果字符串中包含从 a 到 z 这 26 个字符,那每个节点都要存储一个长度为 26 的数组,并且每个数组存储一个 8 字节指针(或者是 4 字节,这个大小跟 CPU、操作系统、编译器等有关)。而且,即便一个节点只有很少的子节点,远小于 26 个,比如 3、4 个,我们也要维护一个长度为 26 的数组。 - -### 字典树的查找 - -1. 每次从根结点开始搜索; -2. 获取关键词的第一个字符,根据该字符选择对应的子节点,转到该子节点继续检索; -3. 在相应的子节点上,获取关键词的第二个字符,进一步选择对应的子节点进行检索; -4. 以此类推,进行迭代过程; -5. 在某个节点处,关键词的所有字母已被取出,则读取附在该节点上的信息,查找完成。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220313181305.jpg) - -每次查询时,如果要查询的字符串长度是 k,那我们只需要比对大约 k 个节点,就能完成查询操作。跟原本那组字符串的长度和个数没有任何关系。所以说,构建好 Trie 树后,在其中查找字符串的时间复杂度是 O(k),k 表示要查找的字符串的长度。 - -## 字典树的应用场景 - -在一组字符串中查找字符串,Trie 树实际上表现得并不好。它对要处理的字符串有及其严苛的要求。 - -第一,字符串中包含的字符集不能太大。我们前面讲到,如果字符集太大,那存储空间可能就会浪费很多。即便可以优化,但也要付出牺牲查询、插入效率的代价。 - -第二,要求字符串的前缀重合比较多,不然空间消耗会变大很多。 - -第三,如果要用 Trie 树解决问题,那我们就要自己从零开始实现一个 Trie 树,还要保证没有 bug,这个在工程上是将简单问题复杂化,除非必须,一般不建议这样做。 - -第四,我们知道,通过指针串起来的数据块是不连续的,而 Trie 树中用到了指针,所以,对缓存并不友好,性能上会打个折扣。 - -在一组字符串中查找字符串,Trie 树实际上表现得并不好。它对要处理的字符串有及其严苛的要求。 - -在一组字符串中查找字符串,Trie 树实际上表现得并不好。它对要处理的字符串有及其严苛的要求。 - -(1)自动补全 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305095300.png) - -(2)拼写检查 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305101637.png) - -(3)IP 路由 (最长前缀匹配) - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305102959.gif) - -图 3. 使用 Trie 树的最长前缀匹配算法,Internet 协议(IP)路由中利用转发表选择路径。 - -(4)T9 (九宫格) 打字预测 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305103047.jpg) - -(5)单词游戏 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305103052.png) - -Trie 树可通过剪枝搜索空间来高效解决 Boggle 单词游戏 - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) -- https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shi-xian-trie-qian-zhui-shu-by-leetcode/ diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/06.\347\272\242\351\273\221\346\240\221.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/06.\347\272\242\351\273\221\346\240\221.md" deleted file mode 100644 index dde06c0..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/02.\346\240\221/06.\347\272\242\351\273\221\346\240\221.md" +++ /dev/null @@ -1,171 +0,0 @@ ---- -title: 红黑树 -categories: - - 数据结构和算法 - - 树 -tags: - - 数据结构 - - 树 - - 二叉树 - - 红黑树 -abbrlink: f89cb603 -date: 2018-06-01 21:10:23 -permalink: /pages/0a4414/ ---- - -# 红黑树 - -## 平衡二叉树 - -平衡二叉树的严格定义是这样的:二叉树中任意一个节点的左右子树的高度相差不能大于 1。 - -完全二叉树、满二叉树其实都是平衡二叉树,但是非完全二叉树也有可能是平衡二叉树。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310202113.jpg) - -**平衡二叉查找树中“平衡”的意思,其实就是让整棵树左右看起来比较“对称”、比较“平衡”,不要出现左子树很高、右子树很矮的情况。这样就能让整棵树的高度相对来说低一些,相应的插入、删除、查找等操作的效率高一些**。 - -## 什么是红黑树 - -红黑树的英文是“Red-Black Tree”,简称 R-B Tree。它是一种不严格的平衡二叉查找树。 - -红黑树中的节点,一类被标记为黑色,一类被标记为红色。除此之外,一棵红黑树还需要满足这样几个要求: - -- 根节点是黑色的; -- 每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储数据; -- 任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的; -- 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点; - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310202612.jpg) - -### 为什么说红黑树是“近似平衡”的? - -平衡二叉查找树的初衷,是为了解决二叉查找树因为动态更新导致的性能退化问题。 - -所以,**“平衡”的意思可以等价为性能不退化。“近似平衡”就等价为性能不会退化的太严重**。 - -**如果我们将红色节点从红黑树中去掉,那单纯包含黑色节点的红黑树的高度是多少呢**? - -红色节点删除之后,有些节点就没有父节点了,它们会直接拿这些节点的祖父节点(父节点的父节点)作为父节点。所以,之前的二叉树就变成了四叉树。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310202902.jpg) - -前面红黑树的定义里有这么一条:从任意节点到可达的叶子节点的每个路径包含相同数目的黑色节点。我们从四叉树中取出某些节点,放到叶节点位置,四叉树就变成了完全二叉树。所以,仅包含黑色节点的四叉树的高度,比包含相同节点个数的完全二叉树的高度还要小。 - -**现在把红色节点加回去,高度会变成多少呢**? - -在红黑树中,红色节点不能相邻,也就是说,有一个红色节点就要至少有一个黑色节点,将它跟其他红色节点隔开。红黑树中包含最多黑色节点的路径不会超过 log2n,所以加入红色节点之后,最长路径不会超过 2log2n,也就是说,红黑树的高度近似 2log2n。 - -所以,红黑树的高度只比高度平衡的 AVL 树的高度(log2n)仅仅大了一倍,在性能上,下降得并不多。这样推导出来的结果不够精确,实际上红黑树的性能更好。 - -## 为什么需要红黑树 - -AVL 树是一种高度平衡的二叉树,所以查找的效率非常高,但是,有利就有弊,AVL 树为了维持这种高度的平衡,就要付出更多的代价。每次插入、删除都要做调整,就比较复杂、耗时。所以,对于有频繁的插入、删除操作的数据集合,使用 AVL 树的代价就有点高了。 - -红黑树只是做到了近似平衡,并不是严格的平衡,所以在维护平衡的成本上,要比 AVL 树要低。 - -所以,红黑树的插入、删除、查找各种操作性能都比较稳定。对于工程应用来说,要面对各种异常情况,为了支撑这种工业级的应用,我们更倾向于这种性能稳定的平衡二叉查找树。 - -## 红黑树平衡调整 - -### 插入操作的平衡调整 - -**红黑树规定,插入的节点必须是红色的。而且,二叉查找树中新插入的节点都是放在叶子节点上**。 - -- 如果插入节点的父节点是黑色的,那我们什么都不用做,它仍然满足红黑树的定义。 -- 如果插入的节点是根节点,那我们直接改变它的颜色,把它变成黑色就可以了。 - -除此之外,其他情况都会违背红黑树的定义,于是我们就需要进行调整,调整的过程包含两种基础的操作:**左右旋转**和**改变颜色**。 - -红黑树的平衡调整过程是一个迭代的过程。我们把正在处理的节点叫作**关注节点**。关注节点会随着不停地迭代处理,而不断发生变化。最开始的关注节点就是新插入的节点。 - -新节点插入之后,如果红黑树的平衡被打破,那一般会有下面三种情况。我们只需要根据每种情况的特点,不停地调整,就可以让红黑树继续符合定义,也就是继续保持平衡。 - -**CASE 1:如果关注节点是 a,它的叔叔节点 d 是红色**,我们就依次执行下面的操作: - -- 将关注节点 a 的父节点 b、叔叔节点 d 的颜色都设置成黑色; -- 将关注节点 a 的祖父节点 c 的颜色设置成红色; -- 关注节点变成 a 的祖父节点 c; -- 跳到 CASE 2 或者 CASE 3。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310203600.jpg) - -**CASE 2:如果关注节点是 a,它的叔叔节点 d 是黑色,关注节点 a 是其父节点 b 的右子节点**,我们就依次执行下面的操作: - -- 关注节点变成节点 a 的父节点 b; -- 围绕新的关注节点 b 左旋; -- 跳到 CASE 3。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310203623.jpg) - -**CASE 3:如果关注节点是 a,它的叔叔节点 d 是黑色,关注节点 a 是其父节点 b 的左子节点**,我们就依次执行下面的操作: - -- 围绕关注节点 a 的祖父节点 c 右旋; -- 将关注节点 a 的父节点 b、兄弟节点 c 的颜色互换。 -- 调整结束。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310203645.jpg) - -### 删除操作的平衡调整 - -#### 针对删除节点初步调整 - -**CASE 1:如果要删除的节点是 a,它只有一个子节点 b**,那我们就依次进行下面的操作: - -- 删除节点 a,并且把节点 b 替换到节点 a 的位置,这一部分操作跟普通的二叉查找树的删除操作一样; -- 节点 a 只能是黑色,节点 b 也只能是红色,其他情况均不符合红黑树的定义。这种情况下,我们把节点 b 改为黑色; -- 调整结束,不需要进行二次调整。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220310204215.jpg) - -**CASE 2:如果要删除的节点 a 有两个非空子节点,并且它的后继节点就是节点 a 的右子节点 c**。我们就依次进行下面的操作: - -- 如果节点 a 的后继节点就是右子节点 c,那右子节点 c 肯定没有左子树。我们把节点 a 删除,并且将节点 c 替换到节点 a 的位置。这一部分操作跟普通的二叉查找树的删除操作无异; -- 然后把节点 c 的颜色设置为跟节点 a 相同的颜色; -- 如果节点 c 是黑色,为了不违反红黑树的最后一条定义,我们给节点 c 的右子节点 d 多加一个黑色,这个时候节点 d 就成了“红 - 黑”或者“黑 - 黑”; -- 这个时候,关注节点变成了节点 d,第二步的调整操作就会针对关注节点来做。 - -**CASE 3:如果要删除的是节点 a,它有两个非空子节点,并且节点 a 的后继节点不是右子节点**,我们就依次进行下面的操作: - -- 找到后继节点 d,并将它删除,删除后继节点 d 的过程参照 CASE 1; -- 将节点 a 替换成后继节点 d; -- 把节点 d 的颜色设置为跟节点 a 相同的颜色; -- 如果节点 d 是黑色,为了不违反红黑树的最后一条定义,我们给节点 d 的右子节点 c 多加一个黑色,这个时候节点 c 就成了“红 - 黑”或者“黑 - 黑”; -- 这个时候,关注节点变成了节点 c,第二步的调整操作就会针对关注节点来做。 - -#### 针对关注节点进行二次调整 - -**CASE 1:如果关注节点是 a,它的兄弟节点 c 是红色的**,我们就依次进行下面的操作: - -- 围绕关注节点 a 的父节点 b 左旋; -- 关注节点 a 的父节点 b 和祖父节点 c 交换颜色; -- 关注节点不变; -- 继续从四种情况中选择适合的规则来调整。 - -**CASE 2:如果关注节点是 a,它的兄弟节点 c 是黑色的,并且节点 c 的左右子节点 d、e 都是黑色的**,我们就依次进行下面的操作: - -- 将关注节点 a 的兄弟节点 c 的颜色变成红色; -- 从关注节点 a 中去掉一个黑色,这个时候节点 a 就是单纯的红色或者黑色; -- 给关注节点 a 的父节点 b 添加一个黑色,这个时候节点 b 就变成了“红 - 黑”或者“黑 - 黑”; -- 关注节点从 a 变成其父节点 b; -- 继续从四种情况中选择符合的规则来调整。 - -**CASE 3:如果关注节点是 a,它的兄弟节点 c 是黑色,c 的左子节点 d 是红色,c 的右子节点 e 是黑色**,我们就依次进行下面的操作: - -- 围绕关注节点 a 的兄弟节点 c 右旋; -- 节点 c 和节点 d 交换颜色; -- 关注节点不变; -- 跳转到 CASE 4,继续调整。 - -**CASE 4:如果关注节点 a 的兄弟节点 c 是黑色的,并且 c 的右子节点是红色的**,我们就依次进行下面的操作: - -- 围绕关注节点 a 的父节点 b 左旋; -- 将关注节点 a 的兄弟节点 c 的颜色,跟关注节点 a 的父节点 b 设置成相同的颜色; -- 将关注节点 a 的父节点 b 的颜色设置为黑色; -- 从关注节点 a 中去掉一个黑色,节点 a 就变成了单纯的红色或者黑色; -- 将关注节点 a 的叔叔节点 e 设置为黑色; -- 调整结束。 - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/03.\345\223\210\345\270\214\350\241\250.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/03.\345\223\210\345\270\214\350\241\250.md" deleted file mode 100644 index a5b9ff1..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/03.\345\223\210\345\270\214\350\241\250.md" +++ /dev/null @@ -1,157 +0,0 @@ ---- -title: 哈希表 -categories: - - 数据结构和算法 -tags: - - 数据结构和算法 - - 哈希表 -abbrlink: 850f2080 -date: 2015-03-16 14:19:59 -permalink: /pages/b501c7/ ---- - -# 哈希表 - -> **哈希表** 是一种使用 **哈希函数** 组织数据,以支持快速插入和搜索的数据结构。 -> -> 有两种不同类型的哈希表:**哈希集合** 和 **哈希映射**。 -> -> - **哈希集合** 是集合数据结构的实现之一,用于存储非重复值。 -> - **哈希映射** 是映射 数据结构的实现之一,用于存储(key, value)键值对。 - -## 什么是哈希表 - -哈希表的英文叫“Hash Table”,我们平时也叫它“散列表”或者“Hash 表”。 - -**哈希表** 是一种使用 **哈希函数** 组织数据,以支持快速插入和搜索的数据结构。 - -有两种不同类型的哈希表:**哈希集合** 和 **哈希映射**。 - -- **哈希集合** 是集合数据结构的实现之一,用于存储非重复值。 -- **哈希映射** 是映射 数据结构的实现之一,用于存储(key, value)键值对。 - -**哈希表用的是数组支持按照下标随机访问数据的特性,所以哈希表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有哈希表**。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220320201844.png) - -哈希表通过散列函数把元素的键值映射为下标,然后将数据存储在数组中对应下标的位置。按照键值查询元素时,用同样的散列函数,将键值转化数组下标,从对应的数组下标的位置取数据。 - -有两种不同类型的哈希表:哈希集合和哈希映射。 - -- `哈希集合`是`集合`数据结构的实现之一,用于存储`非重复值`。 -- `哈希映射`是`映射` 数据结构的实现之一,用于存储`(key, value)`键值对。 - -在`标准模板库`的帮助下,哈希表是`易于使用的`。大多数常见语言(如 Java,C ++ 和 Python)都支持哈希集合和哈希映射。 - -## 散列函数 - -散列函数,顾名思义,它是一个函数。我们可以把它定义成 **hash(key)**,其中 key 表示元素的键值,hash(key) 的值表示经过散列函数计算得到的散列值。 - -哈希表的关键思想是使用哈希函数将键映射到存储桶。更确切地说, - -1. 当我们插入一个新的键时,哈希函数将决定该键应该分配到哪个桶中,并将该键存储在相应的桶中; -2. 当我们想要搜索一个键时,哈希表将使用相同的哈希函数来查找对应的桶,并只在特定的桶中进行搜索。 - -散列函数将取决于 `键值的范围` 和 `桶的数量` 。 - -**散列函数设计的基本要求**: - -1. 散列函数计算得到的散列值是一个非负整数; -2. 如果 key1 = key2,那 hash(key1) == hash(key2); -3. 如果 key1 ≠ key2,那 hash(key1) ≠ hash(key2)。 - -### 散列冲突 - -即便像业界著名的[MD5](https://zh.wikipedia.org/wiki/MD5)、[SHA](https://zh.wikipedia.org/wiki/SHA家族)、[CRC](https://zh.wikipedia.org/wiki/循環冗餘校驗)等哈希算法,也无法完全避免这种**散列冲突**。 - -该如何解决散列冲突问题呢?我们常用的散列冲突解决方法有两类,开放寻址法(open addressing)和链表法(chaining)。 - -### 装载因子 - -当哈希表中空闲位置不多的时候,散列冲突的概率就会大大提高。为了尽可能保证哈希表的操作效率,一般情况下,我们会尽可能保证哈希表中有一定比例的空闲槽位。我们用**装载因子**(load factor)来表示空位的多少。 - -装载因子的计算公式是: - -``` -哈希表的装载因子 = 填入表中的元素个数 / 哈希表的长度 -``` - -**装载因子越大,说明空闲位置越少,冲突越多**,哈希表的性能会下降。不仅插入数据的过程要多次寻址或者拉很长的链,查找的过程也会因此变得很慢。 - -当装载因子过大时,就需要对哈希表扩容。新申请一个更大的哈希表,将数据搬移到这个新哈希表中。针对数组的扩容,数据搬移操作比较简单。但是,针对哈希表的扩容,数据搬移操作要复杂很多。因为哈希表的大小变了,数据的存储位置也变了,所以我们需要通过散列函数重新计算每个数据的存储位置。 - -插入一个数据,最好情况下,不需要扩容,最好时间复杂度是 O(1)。最坏情况下,哈希表装载因子过高,启动扩容,我们需要重新申请内存空间,重新计算哈希位置,并且搬移数据,所以时间复杂度是 O(n)。用摊还分析法,均摊情况下,时间复杂度接近最好情况,就是 O(1)。 - -装载因子阈值需要选择得当。如果太大,会导致冲突过多;如果太小,会导致内存浪费严重。 - -### 开放寻址法 - -开放寻址法的核心思想是,如果出现了散列冲突,我们就重新探测一个空闲位置,将其插入。 - -**当数据量比较小、装载因子小的时候,适合采用开放寻址法。这也是 Java 中的 `ThreadLocalMap` 使用开放寻址法解决散列冲突的原因**。 - -**线性探测**(Linear Probing):当我们往哈希表中插入数据时,如果某个数据经过散列函数散列之后,存储位置已经被占用了,我们就从当前位置开始,依次往后查找,看是否有空闲位置,直到找到为止。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323200359.png) - -对于使用线性探测法解决冲突的哈希表,删除操作稍微有些特别。我们不能单纯地把要删除的元素设置为空。这是为什么呢?在查找的时候,一旦我们通过线性探测方法,找到一个空闲位置,我们就可以认定哈希表中不存在这个数据。但是,如果这个空闲位置是我们后来删除的,就会导致原来的查找算法失效。本来存在的数据,会被认定为不存在。这个问题如何解决呢? - -我们可以将删除的元素,特殊标记为 deleted。当线性探测查找的时候,遇到标记为 deleted 的空间,并不是停下来,而是继续往下探测。 - -线性探测法其实存在很大问题。当哈希表中插入的数据越来越多时,散列冲突发生的可能性就会越来越大,空闲位置会越来越少,线性探测的时间就会越来越久。极端情况下,我们可能需要探测整个哈希表,所以最坏情况下的时间复杂度为 O(n)。同理,在删除和查找时,也有可能会线性探测整张哈希表,才能找到要查找或者删除的数据。 - -### 链表法 - -在哈希表中,每个“桶(bucket)”或者“槽(slot)”会对应一条链表,所有散列值相同的元素我们都放到相同槽位对应的链表中。 - -链表法比起开放寻址法,对大装载因子的容忍度更高。开放寻址法只能适用装载因子小于 1 的情况。接近 1 时,就可能会有大量的散列冲突,导致大量的探测、再散列等,性能会下降很多。但是对于链表法来说,只要散列函数的值随机均匀,即便装载因子变成 10,也就是链表的长度变长了而已,虽然查找效率有所下降,但是比起顺序查找还是快很多。 - -**基于链表的散列冲突处理方法比较适合存储大对象、大数据量的哈希表,而且,比起开放寻址法,它更加灵活,支持更多的优化策略,比如用红黑树代替链表**。 - -![](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323200419.png) - -当插入的时候,我们只需要通过散列函数计算出对应的散列槽位,将其插入到对应链表中即可,所以插入的时间复杂度是 O(1)。当查找、删除一个元素时,我们同样通过散列函数计算出对应的槽,然后遍历链表查找或者删除。那查找或删除操作的时间复杂度是多少呢? - -实际上,这两个操作的时间复杂度跟链表的长度 k 成正比,也就是 O(k)。对于散列比较均匀的散列函数来说,理论上讲,k=n/m,其中 n 表示散列中数据的个数,m 表示哈希表中“槽”的个数。 - -### 开放寻址法 vs. 链表法 - -**开放寻址法适用于数据量比较小、装载因子小的场景**。 - -**链表法适用于存储大对象、大数据量的哈希表**。**比起开放寻址法,它更加灵活,支持更多的优化策略,比如用红黑树代替链表**。 - -## 哈希表的应用场景 - -哈希算法的应用非常非常多,最常见的七个,分别是: - -- **安全加密**:如:MD5、SHA -- **唯一标识**:UUID -- 数据校验:数字签名 -- **散列函数**: -- **负载均衡**:会话粘滞(session sticky)负载均衡算法。**可以通过哈希算法,对客户端 IP 地址或者会话 ID 计算哈希值,将取得的哈希值与服务器列表的大小进行取模运算,最终得到的值就是应该被路由到的服务器编号。** 这样,我们就可以把同一个 IP 过来的所有请求,都路由到同一个后端服务器上。 -- 数据分片 -- 分布式存储:一致性哈希算法、虚拟哈希槽 - -### 典型应用场景 - -Java 的 HashMap 工具类,其 - -- HashMap 默认的初始大小是 16 -- 最大装载因子默认是 0.75,当 HashMap 中元素个数超过 0.75\*capacity(capacity 表示哈希表的容量)的时候,就会启动扩容,每次扩容都会扩容为原来的两倍大小。 -- HashMap 底层采用链表法来解决冲突。即使负载因子和散列函数设计得再合理,也免不了会出现链表过长的情况,一旦出现链表过长,则会严重影响 HashMap 的性能。在 JDK1.8 版本中,对 HashMap 做了进一步优化:引入了红黑树。当链表长度太长(默认超过 8)时,链表就转换为红黑树。我们可以利用红黑树快速增删改查的特点,提高 HashMap 的性能。当红黑树结点个数少于 8 个的时候,又会将红黑树转化为链表。因为在数据量较小的情况下,红黑树要维护平衡,比起链表来,性能上的优势并不明显。 - -## 练习 - -Leetcode 练习题: - -- [705. 设计哈希集合](https://leetcode-cn.com/problems/design-hashset/) -- [706. 设计哈希映射](https://leetcode-cn.com/problems/design-hashmap/) - -## 思考 - -1. 假设我们有 10 万条 URL 访问日志,如何按照访问次数给 URL 排序? -2. 有两个字符串数组,每个数组大约有 10 万条字符串,如何快速找出两个数组中相同的字符串? - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/04.\350\267\263\350\241\250.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/04.\350\267\263\350\241\250.md" deleted file mode 100644 index f6af72a..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/04.\350\267\263\350\241\250.md" +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: 跳表 -categories: - - 数据结构和算法 -tags: - - 数据结构和算法 - - 跳表 -abbrlink: 2e152a56 -date: 2020-10-23 09:21:13 -permalink: /pages/62671a/ ---- - -# 跳表 - -## 什么是跳表 - -对于一个有序数组,可以使用高效的二分查找法,其时间复杂度为 `O(log n)`。 - -但是,即使是有序的链表,也只能使用低效的顺序查找,其时间复杂度为 `O(n)`。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323113532.png) - -如何提高链表的查找效率呢? - -我们可以对链表加一层索引。具体来说,可以每两个结点提取一个结点到上一级,我们把抽出来的那一级叫作**索引**或**索引层**。索引节点中通过一个 down 指针,指向下一级结点。通过这样的改造,就可以支持类似二分查找的算法。我们把改造之后的数据结构叫作**跳表**(Skip list)。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323155309.png) - -随着数据的不断增长,一级索引层也变得越来越长。此时,我们可以为一级索引再增加一层索引层:二级索引层。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323155346.png) - -随着数据的膨胀,当二级索引层也变得很长时,我们可以继续为其添加新的索引层。**这种链表加多级索引的结构,就是跳表**。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323114408.png) - -### 跳表的时间复杂度 - -在一个具有多级索引的跳表中,第一级索引的结点个数大约就是 `n/2`,第二级索引的结点个数大约就是 `n/4`,第三级索引的结点个数大约就是 `n/8`,依次类推,也就是说,第 `k` 级索引的结点个数是第 `k-1` 级索引的结点个数的 `1/2`,那第 k 级索引结点的个数就是 `n/(2k)`。所以**跳表查询数据的时间复杂度就是 `O(logn)`**。 - -### 跳表的空间复杂度 - -比起单纯的单链表,跳表需要存储多级索引,肯定要消耗更多的存储空间。 - -假设原始链表大小为 n,那第一级索引大约有 n/2 个结点,第二级索引大约有 n/4 个结点,以此类推,每上升一级就减少一半,直到剩下 2 个结点。如果我们把每层索引的结点数写出来,就是一个等比数列。 - -``` -索引节点数 = n/2 + n/4 + n/8 … + 8 + 4 + 2 = n-2 -``` - -所以,跳表的空间复杂度是 `O(n)`。 - -跳表的存储空间其实还有压缩空间。比如,我们增加索引节点的范围,由『每两个节点抽一个上级索引节点』改为『每五个节点抽一个上级索引节点』,可以显著节省存储空间。 - -实际上,在软件开发中,我们不必太在意索引占用的额外空间。在讲数据结构和算法时,我们习惯性地把要处理的数据看成整数,但是在实际的软件开发中,原始链表中存储的有可能是很大的对象,而索引结点只需要存储关键值和几个指针,并不需要存储对象,所以当对象比索引结点大很多时,那索引占用的额外空间就可以忽略了。 - -## 跳表的操作 - -跳表是一种各方面性能都比较优秀的**动态数据结构**,可以支持快速的插入、删除、查找操作,写起来也不复杂,甚至可以替代[红黑树](https://zh.wikipedia.org/wiki/红黑树)(Red-black tree)。 - -### 高效的动态插入和删除 - -跳表不仅支持查找操作,还支持动态的插入、删除操作,而且插入、删除操作的时间复杂度也是 `O(logn)`。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323155933.png) - -- **插入操作**:对于纯粹的单链表,需要遍历每个结点,来找到插入的位置。但是,对于跳表来说,我们讲过查找某个结点的的时间复杂度是 `O(log n)`,所以这里查找某个数据应该插入的位置,方法也是类似的,时间复杂度也是 `O(log n)`。 -- **删除操作**:如果这个结点在索引中也有出现,我们除了要删除原始链表中的结点,还要删除索引中的。因为单链表中的删除操作需要拿到要删除结点的前驱结点,然后通过指针操作完成删除。所以在查找要删除的结点的时候,一定要获取前驱结点。当然,如果我们用的是双向链表,就不需要考虑这个问题了。 - -### 跳表索引动态更新 - -当我们不停地往跳表中插入数据时,如果我们不更新索引,就有可能出现某 2 个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220323161942.png) - -如红黑树、AVL 树这样的平衡二叉树,是通过左右旋的方式保持左右子树的大小平衡,而跳表是通过随机函数来维护前面提到的“平衡性”。 - -当我们往跳表中插入数据的时候,我们可以选择同时将这个数据插入到部分索引层中。如何选择加入哪些索引层呢?可以通过一个随机函数,来决定将这个结点插入到哪几级索引中,比如随机函数生成了值 K,那我们就将这个结点添加到第一级到第 K 级这 K 级索引中。 - -## 为什么需要跳表 - -跳表是一种动态数据结构,支持快速的插入、删除、查找操作,时间复杂度都是 `O(logn)`。 - -跳表的空间复杂度是 `O(n)`。不过,跳表的实现非常灵活,可以通过改变索引构建策略,有效平衡执行效率和内存消耗。虽然跳表的代码实现并不简单,但是作为一种动态数据结构,比起红黑树来说,实现要简单多了。所以很多时候,我们为了代码的简单、易读,比起红黑树,我们更倾向用跳表。 - -## 跳表的应用场景 - -经典实现:Redis 的 Sorted Set、JDK 的 `ConcurrentSkipListMap` 和 `ConcurrentSkipListSet` 都是基于跳表实现。 - -为什么 Redis 要用跳表来实现有序集合,而不是红黑树? - -Redis 中的有序集合支持的核心操作主要有下面这几个: - -- 插入一个数据; -- 删除一个数据; -- 查找一个数据; -- 按照区间查找数据(比如查找值在 [100, 356] 之间的数据); -- 迭代输出有序序列。 - -其中,插入、删除、查找以及迭代输出有序序列这几个操作,红黑树也可以完成,时间复杂度跟跳表是一样的。但是,按照区间来查找数据这个操作,红黑树的效率没有跳表高。 - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) diff --git "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/05.\345\233\276.md" "b/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/05.\345\233\276.md" deleted file mode 100644 index 44dc4d3..0000000 --- "a/docs/01.\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225/05.\345\233\276.md" +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: 图 -categories: - - 数据结构和算法 -tags: - - 数据结构和算法 - - 图 -abbrlink: ee040603 -date: 2015-03-24 15:31:13 -permalink: /pages/21529b/ ---- - -# 图 - -在计算机科学中,一个图就是一些*顶点*的集合,这些顶点通过一系列*边*结对(连接)。顶点用圆圈表示,边就是这些圆圈之间的连线。顶点之间通过边连接。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/cs/data-structure/graph/graph.png) - -## 什么是图 - -- **阶(Order)** - 图 G 中点集 V 的大小称作图 G 的阶。 -- **子图(Sub-Graph)** - 当图 G'=(V',E')其中 V‘包含于 V,E’包含于 E,则 G'称作图 G=(V,E)的子图。每个图都是本身的子图。 -- 生成子图(Spanning Sub-Graph) - 指满足条件 V(G') = V(G)的 G 的子图 G'。 -- 导出子图(Induced Subgraph) - 以图 G 的顶点集 V 的[非空子集](https://baike.baidu.com/item/%E9%9D%9E%E7%A9%BA%E5%AD%90%E9%9B%86/10180460)V1 为顶点集,以两端点均在 V1 中的全体边为边集的 G 的子图,称为 V1 导出的导出子图;以图 G 的边集 E 的非空子集 E1 为边集,以 E1 中边关联的顶点的全体为顶点集的 G 的子图,称为 E1 导出的导出子图。 -- **有向图** - 如果给图的每条边规定一个方向,那么得到的图称为有向图。 -- **无向图** - 边没有方向的图称为无向图。 -- **度(Degree)** - 一个顶点的度是指与该顶点相关联的边的条数,顶点 v 的度记作 d(v)。 -- **入度(In-degree)**和**出度(Out-degree)** - 对于有向图来说,一个顶点的度可细分为入度和出度。一个顶点的入度是指与其关联的各边之中,以其为终点的边数;出度则是相对的概念,指以该顶点为起点的边数。 -- **自环(Loop)** - 若一条边的两个顶点为同一顶点,则此边称作自环。 -- 路径(Path) - 从 u 到 v 的一条路径是指一个序列 v0,e1,v1,e2,v2,...ek,vk,其中 ei 的顶点为 vi 及 vi - 1,k 称作路径的长度。如果它的起止顶点相同,该路径是“闭”的,反之,则称为“开”的。一条路径称为一简单路径(simple path),如果路径中除起始与终止[顶点](https://baike.baidu.com/item/%E9%A1%B6%E7%82%B9)可以重合外,所有顶点两两不等。 -- **行迹(Trace)** - 如果路径 P(u,v)中的边各不相同,则该路径称为 u 到 v 的一条行迹。闭的行迹称作回路(Circuit)。 -- **轨迹(Track)** - 如果路径 P(u,v)中的顶点各不相同,则该路径称为 u 到 v 的一条轨迹。闭的轨迹称作圈(Cycle)。 -- **桥(Bridge)** - 若去掉一条边,便会使得整个图不连通,该边称为[桥](https://baike.baidu.com/item/%E6%A1%A5)。 - -如果图的边没有方向性,则被成为无向图。 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20220314093554.jpg) - -## 图的基本操作 - -- 创建一个图结构 - CreateGraph(G) -- 检索给定顶点 - LocateVex(G,elem) -- 获取图中某个顶点 - GetVex(G,v) -- 为图中顶点赋值 - PutVex(G,v,value) -- 返回第一个邻接点 - FirstAdjVex(G,v) -- 返回下一个邻接点 - NextAdjVex(G,v,w) -- 插入一个顶点 - InsertVex(G,v) -- 删除一个顶点 - DeleteVex(G,v) -- 插入一条边 - InsertEdge(G,v,w) -- 删除一条边 - DeleteEdge(G,v,w) -- 遍历图 - Traverse(G,v) - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) diff --git a/docs/@pages/archivesPage.md b/docs/@pages/archivesPage.md deleted file mode 100644 index 4e2d4ed..0000000 --- a/docs/@pages/archivesPage.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -archivesPage: true -title: 归档 -permalink: /archives/ -article: false ---- diff --git a/docs/@pages/categoriesPage.md b/docs/@pages/categoriesPage.md deleted file mode 100644 index 15f359b..0000000 --- a/docs/@pages/categoriesPage.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -categoriesPage: true -title: 分类 -permalink: /categories/ -article: false ---- diff --git a/docs/@pages/tagsPage.md b/docs/@pages/tagsPage.md deleted file mode 100644 index 943f890..0000000 --- a/docs/@pages/tagsPage.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -tagsPage: true -title: 标签 -permalink: /tags/ -article: false ---- diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 2e6316d..0000000 --- a/docs/README.md +++ /dev/null @@ -1,230 +0,0 @@ ---- -home: true -heroImage: img/bg.gif -heroText: ALGORITHM-TUTORIAL -tagline: 💾 algorithm-tutorial 是一个数据结构与算法教程。 -bannerBg: none -postList: none -footer: CC-BY-SA-4.0 Licensed | Copyright © 2018-Now Dunwu ---- - -

- - - star - - - - fork - - - - build - - - - code style - - -

- -

ALGORITHM-TUTORIAL

- -> 💾 algorithm-tutorial 是一个数据结构与算法教程。 -> -> 掌握数据结构与算法,你看待问题的深度,解决问题的角度就会完全不一样。 -> -> - 🔁 项目同步维护:[Github](https://github.com/dunwu/algorithm-tutorial/) | [Gitee](https://gitee.com/turnon/algorithm-tutorial/) -> - 📖 电子书阅读:[Github Pages](https://dunwu.github.io/algorithm-tutorial/) | [Gitee Pages](http://turnon.gitee.io/algorithm-tutorial/) - -## 📖 内容 - -![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200702071922.png) - -- 综合 -- [数据结构和算法指南](01.数据结构和算法/00.综合/01.数据结构和算法指南.md) -- [复杂度分析](01.数据结构和算法/00.综合/02.复杂度分析.md) - 关键词:**`时间复杂度`**、**`空间复杂度`**、**`大 O 表示法`**、**`复杂度量级`** -- 线性表 - - [数组和链表](01.数据结构和算法/01.线性表/01.数组和链表.md) - 关键词:**`线性表`**、**`一维数组`**、**`多维数组`**、**`随机访问`**、**`单链表`**、**`双链表`**、**`循环链表`** - - [栈和队列](01.数据结构和算法/01.线性表/02.栈和队列.md) - 关键词:**`先进后出`**、**`后进先出`**、**`循环队列`** - - [线性表的查找](01.数据结构和算法/01.线性表/11.线性表的查找.md) - - [线性表的排序](01.数据结构和算法/01.线性表/12.线性表的排序.md) -- 树 - - [树和二叉树](01.数据结构和算法/02.树/01.树和二叉树.md) - - [堆](01.数据结构和算法/02.树/02.堆.md) - - [B+树](01.数据结构和算法/02.树/03.B+树.md) - - [LSM 树](01.数据结构和算法/02.树/04.LSM树.md) - - [字典树](01.数据结构和算法/02.树/05.字典树.md) - - [红黑树](01.数据结构和算法/02.树/06.红黑树.md) -- [哈希表](01.数据结构和算法/03.哈希表.md) - 关键词:**`哈希函数`**、**`装载因子`**、**`哈希冲突`**、**`开放寻址法`**、**`拉链法`** -- [跳表](01.数据结构和算法/04.跳表.md) - 关键词:**`多级索引`** -- [图](01.数据结构和算法/05.图.md) - -## 💻 刷题 - -### 数组 - -- [三数之和](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/三数之和.java) -- [两数之和](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/两数之和.java) -- [二维数组](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/二维数组.java) -- [删除排序数组中的重复项](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/删除排序数组中的重复项.java) -- [加一](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/加一.java) -- [在排序数组中查找元素的第一个和最后一个位置](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/在排序数组中查找元素的第一个和最后一个位置.java) -- [在排序数组中查找数字 I](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/在排序数组中查找数字I.java) -- [存在重复元素](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/存在重复元素.java) -- [对角线遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/对角线遍历.java) -- [寻找数组的中心索引](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/寻找数组的中心索引.java) -- [将数组分成和相等的三个部分](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/将数组分成和相等的三个部分.java) -- [数组二分查找](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/数组二分查找.java) -- [数组拆分 1](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/数组拆分1.java) -- [旋转数组](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/旋转数组.java) -- [旋转矩阵](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/旋转矩阵.java) -- [最大连续 1 的个数](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/最大连续1的个数.java) -- [杨辉三角](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/杨辉三角.java) -- [杨辉三角 2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/杨辉三角2.java) -- [模拟 ArrayList1](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/模拟ArrayList1.java) -- [模拟 ArrayList2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/模拟ArrayList2.java) -- [移动零](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/移动零.java) -- [移除元素](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/移除元素.java) -- [至少是其他数字两倍的最大数](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/至少是其他数字两倍的最大数.java) -- [螺旋矩阵](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/螺旋矩阵.java) -- [长度最小的子数组](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/长度最小的子数组.java) -- [零矩阵](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/array/零矩阵.java) - -### 链表 - -- [两数相加](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/两数相加.java) -- [二进制链表转整数](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/二进制链表转整数.java) -- [删除排序链表中的重复元素](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/删除排序链表中的重复元素.java) -- [单链表示例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/单链表示例.java) -- [双链表示例](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/双链表示例.java) -- [反转链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/反转链表.java) -- [合并 K 个排序链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/合并K个排序链表.java) -- [合并 K 个排序链表解法 2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/合并K个排序链表解法2.java) -- [合并两个有序链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/合并两个有序链表.java) -- [回文链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/回文链表.java) -- [排序链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/排序链表.java) -- [环形链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/环形链表.java) -- [相交链表](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/相交链表.java) -- [移除重复节点](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/移除重复节点.java) -- [移除链表元素](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/移除链表元素.java) -- [返回倒数第 k 个节点](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/返回倒数第k个节点.java) -- [链表的中间结点](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/list/链表的中间结点.java) - -### 栈 - -- [三合一](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/三合一.java) -- [基本计算器](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/基本计算器.java) -- [最小栈](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/最小栈.java) -- [最小栈 2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/最小栈2.java) -- [有效的括号](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/有效的括号.java) -- [栈排序](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/栈排序.java) -- [棒球比赛](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/棒球比赛.java) -- [比较含退格的字符串](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/比较含退格的字符串.java) -- [用栈实现队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/用栈实现队列.java) -- [用队列实现栈](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/stack/用队列实现栈.java) - -### 队列 - -- [动态扩容数组实现的队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/动态扩容数组实现的队列.java) -- [数组实现的队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/数组实现的队列.java) -- [最近的请求次数](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/最近的请求次数.java) -- [设计循环队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/设计循环队列.java) -- [链表实现的队列](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/queue/链表实现的队列.java) - -### 字符串 - -- [二进制求和](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/AddBinary.java) -- [实现 strStr()](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ImplementStrstr.java) -- [最长公共前缀](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/LongestCommonPrefix.java) -- [反转字符串](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ReverseString.java) -- [反转字符串中的单词](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ReverseWordsInAString.java) -- [反转字符串中的单词 III](https://github.com/dunwu/algorithm/blob/master/codes/data-structure/src/main/java/io/github/dunwu/ds/str/ReverseWordsInAString3.java) - -### 树 - -- [N 叉树的最大深度](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/N叉树的最大深度.java) - -#### 二叉树 - -- [二叉树中的最大路径和](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树中的最大路径和.java) -- [二叉树的中序遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的中序遍历.java) -- [二叉树的前序遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的前序遍历.java) -- [二叉树的后序遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的后序遍历.java) -- [二叉树的层次遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的层次遍历.java) -- [二叉树的层次遍历 2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的层次遍历2.java) -- [二叉树的序列化与反序列化](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的序列化与反序列化.java) -- [二叉树的所有路径](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的所有路径.java) -- [二叉树的最大深度](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的最大深度.java) -- [二叉树的最小深度](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的最小深度.java) -- [二叉树的最近公共祖先](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的最近公共祖先.java) -- [二叉树的锯齿形层次遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的锯齿形层次遍历.java) -- [从先序遍历还原二叉树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/从先序遍历还原二叉树.java) -- [叶子相似的树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/叶子相似的树.java) -- [填充每个节点的下一个右侧节点指针](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/填充每个节点的下一个右侧节点指针.java) -- [填充每个节点的下一个右侧节点指针 II](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/填充每个节点的下一个右侧节点指针II.java) -- [对称二叉树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/对称二叉树.java) -- [平衡二叉树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/平衡二叉树.java) -- [相同的树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/相同的树.java) -- [翻转二叉树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/翻转二叉树.java) -- [路径总和](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/路径总和.java) - -#### 二叉搜索树 - -- [二叉搜索树中的插入操作](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/二叉搜索树中的插入操作.java) -- [二叉搜索树的最近公共祖先](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/二叉搜索树的最近公共祖先.java) -- [二叉搜索树节点最小距离](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/二叉搜索树节点最小距离.java) -- [将有序数组转换为二叉搜索树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/将有序数组转换为二叉搜索树.java) -- [验证二叉搜索树](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/bstree/验证二叉搜索树.java) - -## 📚 资料 - -- **书籍** - - 刷题必备 - - 《剑指 offer》 - - 《编程之美》 - - 《编程之法:面试和算法心得》 - - 《算法谜题》 都是思维题 - - 基础 - - 《[编程珠玑(第 2 版)](https://www.amazon.cn/gp/product/B00SFZH0DC/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00SFZH0DC&linkCode=as2&tag=vastwork-23)》 - - 《[编程珠玑(续)](https://www.amazon.cn/gp/product/B0150BMQDM/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B0150BMQDM&linkCode=as2&tag=vastwork-23)》 - - 《[数据结构与算法分析 : C++描述(第 4 版)](https://www.amazon.cn/gp/product/B01LDG2DSG/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01LDG2DSG&linkCode=as2&tag=vastwork-23)》 - - 《[数据结构与算法分析 : C 语言描述(第 2 版)](https://www.amazon.cn/gp/product/B002WC7NGS/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B002WC7NGS&linkCode=as2&tag=vastwork-23)》 - - 《[数据结构与算法分析 : Java 语言描述(第 2 版)](https://www.amazon.cn/gp/product/B01CNP0CG6/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B01CNP0CG6&linkCode=as2&tag=vastwork-23)》 - - 《[算法(第 4 版)](https://www.amazon.cn/gp/product/B009OCFQ0O/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B009OCFQ0O&linkCode=as2&tag=vastwork-23)》 - - 算法设计 - - 《[算法设计与分析基础(第 3 版)](https://www.amazon.cn/gp/product/B00S4HCQUI/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00S4HCQUI&linkCode=as2&tag=vastwork-23)》 - - 《Algorithm Design Manual》 - 算法设计手册 红皮书 - - [《算法导论》](https://www.amazon.cn/gp/product/B00AK7BYJY/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=536&creative=3200&creativeASIN=B00AK7BYJY&linkCode=as2&tag=vastwork-23) - 是一本对算法介绍比较全面的经典书籍 - - 《Algorithms on Strings,Trees and Sequences》 - - 《Advanced Data Structures》 - 各种诡异高级的数据结构和算法 如元胞自动机、斐波纳契堆、线段树 600 块 -- **学习网站** - - https://github.com/TheAlgorithms/Java - - https://github.com/nonstriater/Learn-Algorithms - - https://github.com/trekhleb/javascript-algorithms - - https://github.com/wangzheng0822/algo - - https://github.com/kdn251/interviews/blob/master/README-zh-cn.md#%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84 - - [July 博客](http://blog.csdn.net/v_july_v) - - 《数学建模十大经典算法》 - - 《数据挖掘领域十大经典算法》 - - 《十道海量数据处理面试题》 - - 《数字图像处理领域的二十四个经典算法》 - - 《精选微软等公司经典的算法面试 100 题》 - - [The-Art-Of-Programming-By-July](https://github.com/julycoding/The-Art-Of-Programming-By-July) - - [微软面试 100 题](http://blog.csdn.net/column/details/ms100.html) - - [程序员编程艺术](http://blog.csdn.net/v_JULY_v/article/details/6460494) -- **基本算法演示** - - - - -- **编程网站** - - [leetcode](http://leetcode-cn.com/) - - [openjudge](http://openjudge.cn/) -- **教程** - - [高级数据结构和算法](https://www.coursera.org/learn/gaoji-shuju-jiegou/) 北大教授张铭老师在 coursera 上的课程。完成这门课之时,你将掌握多维数组、广义表、Trie 树、AVL 树、伸展树等高级数据结构,并结合内排序、外排序、检索、索引有关的算法,高效地解决现实生活中一些比较复杂的应用问题。当然 coursera 上也还有很多其它算法方面的视频课程。 - - [算法设计与分析 Design and Analysis of Algorithms](https://class.coursera.org/algorithms-001/lecture) 由北大教授 Wanling Qu 在 coursera 讲授的一门算法课程。首先介绍一些与算法有关的基础知识,然后阐述经典的算法设计思想和分析技术,主要涉及的算法设计技术是:分治策略、动态规划、贪心法、回溯与分支限界等。每个视频都配有相应的讲义(pdf 文件)以便阅读和复习。 - - [算法面试通关 40 讲](https://time.geekbang.org/course/intro/100019701) - - [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) - -## 🚪 传送 - -| [技术文档归档](https://github.com/dunwu/blog) | [算法和数据结构教程系列](https://github.com/dunwu/algorithm-tutorial) | diff --git a/docs/algorithm-template.md b/docs/algorithm-template.md deleted file mode 100644 index 97f82b6..0000000 --- a/docs/algorithm-template.md +++ /dev/null @@ -1,123 +0,0 @@ -# 算法代码模板 - -> 算法代码模板即算法的常见套路。熟练记忆,活学活用。 - -## 递归 - -```java -public void recursion(int level, int param1, int param2, ...) { - // 递归终止条件 - if (level > MAX_LEVEL) { - // print - return; - } - - // 当前处理逻辑 - processData(level, param1, param2, ...); - - // 递归 - recursion(level + 1, param1, param2, ...); - - // 如有必要,还原状态 - reverseState(level, data); -} -``` - -## DFS - -```java -Set visited = new HashSet<>(); - -public void dfs(Node node, Set visited) { - visited.add(node); - for (Node n : node.children) { - if (!visited.contains(n)) { - dfs(n, visited); - } - } -} -``` - -## BFS - -```java -public List> bfs(Node root) { - List> list = new ArrayList<>(); - Queue queue = new LinkedList<>(); - queue.offer(root); - while (!queue.isEmpty()) { - List levelList = new ArrayList<>(); - - int size = queue.size(); - // 遍历当前层级所有节点 - for (int i = 0; i < size; i++) { - Node n = queue.poll(); - - // 对节点 n 做逻辑处理 - levelList.add(n.val); - - // 将 n 的所有节点加入队列 - for (Node c : n.children) { - queue.offer(c); - } - } - - list.add(levelList); - } - - return list; -} -``` - -## 二分查找 - -数组的二分查找: - -```java -int left = 0, right = nums.length - 1; -while (left <= right) { - int mid = left + (right - left) / 2; // 防止数据类型溢出 - if (nums[mid] == target) { - break or return result; - } else if (nums[mid] < target) { - left = mid + 1; - } else { - right = mid - 1; - } -} -``` - -## 动态规划 - -```java -// DP 状态定义 -int[][] dp = new int[m + 1][n + 1]; - -// 初始状态 -dp[0][0] = x; -dp[0][1] = y; - -// DP 状态推导 -for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - // 方程根据实际场景推导 - dp[i][j] = max or min { dp[i - 1][j], dp[i][j - 1], ... } - } -} - -// 返回最优解 -return dp[m][n]; -``` - -## 位运算 - -记忆常用位运算公式(无他,背就完事了) - -| | 二进制表达式 | 等价表达式 | -| -------------- | ----------------------------- | ----------------------------- | -| 判断奇偶 | `x & 1 == 1`
`x & 1 == 0` | `x % 2 == 1`
`x % 2 == 0` | -| 清零最低位的 1 | `x = x & (x - 1)` | | -| 得到最低位的 1 | `x & -x` | | - - - diff --git a/docs/hash-search.md b/docs/hash-search.md deleted file mode 100644 index 84fddb5..0000000 --- a/docs/hash-search.md +++ /dev/null @@ -1,232 +0,0 @@ -# Hash 表的查找 - -## 要点 - -### 哈希表和哈希函数 - -在记录的存储位置和它的关键字之间是建立一个确定的对应关系(映射函数),使每个关键字和一个存储位置能**唯一对应**。这个映射函数称为**哈希函数**,根据这个原则建立的表称为**哈希表(Hash Table)**,也叫**哈希表**。 - -以上描述,如果通过数学形式来描述就是: - -若查找关键字为 **key**,则其值存放在 **f(key)** 的存储位置上。由此,**不需比较便可直接取得所查记录**。 - -***注:哈希查找与线性表查找和树表查找最大的区别在于,不用数值比较。*** - -### 冲突 - -若 key1 ≠ key2 ,而 f(key1) = f(key2),这种情况称为**冲突(Collision)**。 - -根据哈希函数f(key)和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这一映射过程称为**构造哈希表**。 - -构造哈希表这个场景就像汽车找停车位,如果车位被人占了,只能找空的地方停。 - -![img](http://upload-images.jianshu.io/upload_images/3101171-4f4e0c3def86f7bb.jpg "点击查看源网页") - -## 构造哈希表 - -由以上内容可知,哈希查找本身其实不费吹灰之力,问题的关键在于如何构造哈希表和处理冲突。 - -常见的构造哈希表的方法有 `5` 种: - -### 直接定址法 - -说白了,就是小学时学过的**一元一次方程**。 - -即 f(key) = a * key + b。其中,a和b 是常数。 - -### 数字分析法 - -假设关键字是R进制数(如十进制)。并且哈希表中**可能出现的关键字都是事先知道的**,则可选取关键字的若干数位组成哈希地址。 - -选取的原则是使得到的哈希地址尽量避免冲突,即所选数位上的数字尽可能是随机的。 - -### 平方取中法 - -取关键字平方后的中间几位为哈希地址。通常在选定哈希函数时不一定能知道关键字的全部情况,仅取其中的几位为地址不一定合适; - -而一个数平方后的中间几位数和数的每一位都相关, 由此得到的哈希地址随机性更大。取的位数由表长决定。 - -### 除留余数法 - -取关键字被某个**不大于哈希表表长** m 的数 p 除后所得的余数为哈希地址。 - -即 f(key) = key % p (p ≤ m) - -这是一种**最简单、最常用**的方法,它不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。 - -注意:p的选择很重要,如果选的不好,容易产生冲突。根据经验,**一般情况下可以选p为素数**。 - -### 随机数法 - -选择一个随机函数,取关键字的随机函数值为它的哈希地址,即 f(key) = random(key)。 - -通常,在关键字长度不等时采用此法构造哈希函数较为恰当。 - -## 解决冲突 - -设计合理的哈希函数可以减少冲突,但不能完全避免冲突。 - -所以需要有解决冲突的方法,常见有两类: - -### 开放定址法 - -如果两个数据元素的哈希值相同,则在哈希表中为后插入的数据元素另外选择一个表项。 -当程序查找哈希表时,如果没有在第一个对应的哈希表项中找到符合查找要求的数据元素,程序就会继续往后查找,直到找到一个符合查找要求的数据元素,或者遇到一个空的表项。 - -**示例** - -若要将一组关键字序列 {1, 9, 25, 11, 12, 35, 17, 29} 存放到哈希表中。 - -采用除留余数法构造哈希表;采用开放定址法处理冲突。 - -不妨设选取的p和m为13,由 f(key) = key % 13 可以得到下表。 - -![img](https://upload-images.jianshu.io/upload_images/3101171-06a789e7f9b31da6.png) - -需要注意的是,在上图中有两个关键字的探查次数为 2 ,其他都是1。 - -这个过程是这样的: - -a. 12 % 13 结果是12,而它的前面有个 25 ,25 % 13 也是12,存在冲突。 - -我们使用开放定址法 (12 + 1) % 13 = 0,没有冲突,完成。 - -b. 35 % 13 结果是 9,而它的前面有个 9,9 % 13也是 9,存在冲突。 - -我们使用开放定址法 (9 + 1) % 13 = 10,没有冲突,完成。 - -### 拉链法 - -将哈希值相同的数据元素存放在一个链表中,在查找哈希表的过程中,当查找到这个链表时,必须采用线性查找方法。 - -在这种方法中,哈希表中每个单元存放的不再是记录本身,而是相应同义词单链表的头指针。 - -**示例** - -如果对开放定址法示例中提到的序列使用拉链法,得到的结果如下图所示: - -![img](https://upload-images.jianshu.io/upload_images/3101171-c14e03882e8a0f3a.png) - -## 实现一个哈希表 - -假设要实现一个哈希表,要求 - -a. 哈希函数采用**除留余数法**,即 f(key) = key % p (p ≤ m) - -b. 解决冲突采用**开放定址法**,即 f2(key) = (f(key)+i) % size (p ≤ m) - -(1)定义哈希表的数据结构 - -```java -class HashTable { - public int key = 0; // 关键字 - public int data = 0; // 数值 - public int count = 0; // 探查次数 -} -``` - -(2)在哈希表中查找关键字key - -根据设定的哈希函数,计算哈希地址。如果出现地址冲突,则按设定的处理冲突的方法寻找下一个地址。 - -如此反复,直到不冲突为止(查找成功)或某个地址为空(查找失败)。 - -```java -/** - * 查找哈希表 - * 构造哈希表采用除留取余法,即f(key) = key mod p (p ≤ size) - * 解决冲突采用开放定址法,即f2(key) = (f(key) + i) mod p (1 ≤ i ≤ size-1) - * ha为哈希表,p为模,size为哈希表大小,key为要查找的关键字 - */ -public int searchHashTable(HashTable[] ha, int p, int size, int key) { - int addr = key % p; // 采用除留取余法找哈希地址 - - // 若发生冲突,用开放定址法找下一个哈希地址 - while (ha[addr].key != NULLKEY && ha[addr].key != key) { - addr = (addr + 1) % size; - } - - if (ha[addr].key == key) { - return addr; // 查找成功 - } else { - return FAILED; // 查找失败 - } -} -``` - -(3)删除关键字为key的记录 - -在采用开放定址法处理冲突的哈希表上执行删除操作,只能在被删记录上做删除标记,而不能真正删除记录。 - -找到要删除的记录,将关键字置为删除标记DELKEY。 - -```java -public int deleteHashTable(HashTable[] ha, int p, int size, int key) { - int addr = 0; - addr = searchHashTable(ha, p, size, key); - if (FAILED != addr) { // 找到记录 - ha[addr].key = DELKEY; // 将该位置的关键字置为DELKEY - return SUCCESS; - } else { - return NULLKEY; // 查找不到记录,直接返回NULLKEY - } -} -``` - -(4)插入关键字为key的记录 - -将待插入的关键字key插入哈希表 -先调用查找算法,若在表中找到待插入的关键字,则插入失败; -若在表中找到一个开放地址,则将待插入的结点插入到其中,则插入成功。 - -```java -public void insertHashTable(HashTable[] ha, int p, int size, int key) { - int i = 1; - int addr = 0; - addr = key % p; // 通过哈希函数获取哈希地址 - if (ha[addr].key == NULLKEY || ha[addr].key == DELKEY) { // 如果没有冲突,直接插入 - ha[addr].key = key; - ha[addr].count = 1; - } else { // 如果有冲突,使用开放定址法处理冲突 - do { - addr = (addr + 1) % size; // 寻找下一个哈希地址 - i++; - } while (ha[addr].key != NULLKEY && ha[addr].key != DELKEY); - - ha[addr].key = key; - ha[addr].count = i; - } -} -``` - -(5)建立哈希表 - -先将哈希表中各关键字清空,使其地址为开放的,然后调用插入算法将给定的关键字序列依次插入。 - -```java -public void insertHashTable(HashTable[] ha, int p, int size, int key) { - int i = 1; - int addr = 0; - addr = key % p; // 通过哈希函数获取哈希地址 - if (ha[addr].key == NULLKEY || ha[addr].key == DELKEY) { // 如果没有冲突,直接插入 - ha[addr].key = key; - ha[addr].count = 1; - } else { // 如果有冲突,使用开放定址法处理冲突 - do { - addr = (addr + 1) % size; // 寻找下一个哈希地址 - i++; - } while (ha[addr].key != NULLKEY && ha[addr].key != DELKEY); - - ha[addr].key = key; - ha[addr].count = i; - } -} -``` - -### 完整示例 - -[示例代码](https://github.com/dunwu/algorithm/blob/master/codes/src/main/java/io/github/dunwu/algorithm/search/HashDemo.java) - -## 资源 - -《数据结构习题与解析》(B级第3版) diff --git "a/docs/\347\256\227\346\263\225\346\200\235\350\267\257.md" "b/docs/\347\256\227\346\263\225\346\200\235\350\267\257.md" deleted file mode 100644 index 8cec531..0000000 --- "a/docs/\347\256\227\346\263\225\346\200\235\350\267\257.md" +++ /dev/null @@ -1,114 +0,0 @@ -# 算法思路 - -## 递归 - -### 使用递归的条件 - -递归需要满足的三个条件 - -- **一个问题的解可以分解为几个子问题的解** -- **这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一样** -- **存在递归终止条件** - -### 递归代码要警惕堆栈溢出 - -函数调用会使用栈来保存临时变量。每调用一个函数,都会将临时变量封装为栈帧压入内存栈,等函数执行完成返回时,才出栈。系统栈或者虚拟机栈空间一般都不大。如果递归求解的数据规模很大,调用层次很深,一直压入栈,就会有堆栈溢出的风险。 - -那么,如何避免出现堆栈溢出呢? - -我们可以通过在代码中限制递归调用的最大深度的方式来解决这个问题 - -## 贪心算法 - -### 贪心算法思路 - -贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择,就能得到问题的答案。贪心算法需要充分挖掘题目中条件,没有固定的模式,解决有贪心算法需要一定的直觉和经验。 - -贪心算法**不是对所有问题都能得到整体最优解**。能使用贪心算法解决的问题具有「贪心选择性质」。「贪心选择性质」严格意义上需要数学证明。能使用贪心算法解决的问题必须具备「无后效性」,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。 - -### 贪心算法的应用 - -霍夫曼编码(Huffman Coding) - -Prim 和 Kruskal 最小生成树算法 - -Dijkstra 单源最短路径算法 - -## 分治算法 - -分治算法的核心就是分而治之,也就是将原问题划分成 n 个规模较小,并且结构与原问题相似的子问题,分别解决这些子问题,然后再合并其结果,得到原问题的解。 - -**分治算法是一种处理问题的思想,递归是一种编程技巧**。分治算法一般都比较适合用递归来实现。分治算法的递归实现中,每一层递归都会涉及这样三个操作: - -- 分解:将原问题分解成一系列子问题; -- 解决:递归地求解各个子问题,若子问题足够小,则直接求解; -- 合并:将子问题的结果合并成原问题。 - -分治算法能解决的问题,一般需要满足下面这几个条件: - -- 原问题与分解成的小问题具有相同的模式; -- 原问题分解成的子问题可以独立求解,子问题之间没有相关性,这一点是分治算法跟动态规划的明显区别,等我们讲到动态规划的时候,会详细对比这两种算法; -- 具有分解终止条件,也就是说,当问题足够小时,可以直接求解; -- 可以将子问题合并成原问题,而这个合并操作的复杂度不能太高,否则就起不到减小算法总体复杂度的效果了。 - -## 回溯算法 - -### 回溯算法思路 - -**回溯法** 采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况: - -- 找到一个可能存在的正确的答案; - -- 在尝试了所有可能的分步方法后宣告该问题没有答案。 - - - -**解决一个回溯问题,实际上就是一个决策树的遍历过程**。 - -- **路径**:也就是已经做出的选择。 -- **选择列表**:也就是你当前可以做的选择。 -- **结束条件**:也就是到达决策树底层,无法再做选择的条件。 - -回溯算法的骨架: - -```text -result = [] -def backtrack(路径, 选择列表): - if 满足结束条件: - result.add(路径) - return - - for 选择 in 选择列表: - 做选择 - backtrack(路径, 选择列表) - 撤销选择 -``` - -**其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」** - -### 回溯算法应用 - -回溯算法典型问题: - -- [46. 全排列(中等)](https://leetcode-cn.com/problems/permutations/) -- [47. 全排列 II(中等)](https://leetcode-cn.com/problems/permutations-ii/) -- [N 皇后(困难)](https://leetcode-cn.com/problems/n-queens/) -37. [解数独(困难)](https://leetcode-cn.com/problems/sudoku-solver/) - -> [知乎:回溯算法套路详解 - labuladong的文章](https://zhuanlan.zhihu.com/p/93530380) - -## 动态规划 - -### 动态规划思路 - -动态规划比较适合用来求解最优问题,比如求最大值、最小值等等。 - -动态规划的应用 - -买卖股票的最佳时机 - -## 参考资料 - -- [数据结构与算法之美](https://time.geekbang.org/column/intro/100017301) -- 回溯 -- [知乎:回溯算法套路详解 - labuladong的文章](https://zhuanlan.zhihu.com/p/93530380) diff --git "a/docs/\347\256\227\346\263\225\347\273\203\344\271\240-\346\240\221.md" "b/docs/\347\256\227\346\263\225\347\273\203\344\271\240-\346\240\221.md" deleted file mode 100644 index 30e2d91..0000000 --- "a/docs/\347\256\227\346\263\225\347\273\203\344\271\240-\346\240\221.md" +++ /dev/null @@ -1,42 +0,0 @@ -# 数据结构 - 树 - -## 二叉树经典题 - -### 深度优先搜索(DFS) - -在这个策略中,我们采用 深度 作为优先级,以便从跟开始一直到达某个确定的叶子,然后再返回到达另一个分支。深度优先搜索策略又可以根据根节点、左孩子和右孩子的相对顺序被细分为**先序遍历**,**中序遍历**和**后序遍历**。 - -- [二叉树的前序遍历](https://leetcode-cn.com/problems/binary-tree-preorder-traversal) -- [二叉树的中序遍历](https://leetcode-cn.com/problems/binary-tree-inorder-traversal) -- [二叉树的后序遍历](https://leetcode-cn.com/problems/binary-tree-postorder-traversal) - -### 宽度优先搜索(BFS) - -我们按照高度顺序一层一层的访问整棵树,高层次的节点将会比低层次的节点先被访问到。 - -- [二叉树的层序遍历](https://leetcode-cn.com/problems/binary-tree-level-order-traversal) - -### 二叉树和递归 - -- [二叉树的最大深度](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree) -- [对称二叉树](https://leetcode-cn.com/problems/symmetric-tree) -- [路径总和](https://leetcode-cn.com/problems/path-sum) - -### 其他 - -- [ ] [maximum-depth-of-binary-tree](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/) -- [ ] [balanced-binary-tree](https://leetcode-cn.com/problems/balanced-binary-tree/) -- [ ] [binary-tree-maximum-path-sum](https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/) -- [ ] [lowest-common-ancestor-of-a-binary-tree](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/) -- [ ] [binary-tree-level-order-traversal](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/) -- [ ] [binary-tree-level-order-traversal-ii](https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/) -- [ ] [binary-tree-zigzag-level-order-traversal](https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/) -- [ ] [validate-binary-search-tree](https://leetcode-cn.com/problems/validate-binary-search-tree/) -- [ ] [insert-into-a-binary-search-tree](https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/) - -## 二叉搜索树经典题 - -- [ ] [validate-binary-search-tree](https://leetcode-cn.com/problems/validate-binary-search-tree/) -- [ ] [insert-into-a-binary-search-tree](https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/) -- [ ] [delete-node-in-a-bst](https://leetcode-cn.com/problems/delete-node-in-a-bst/) -- [ ] [balanced-binary-tree](https://leetcode-cn.com/problems/balanced-binary-tree/) diff --git a/docs/.vuepress/public/favicon.ico b/favicon.ico similarity index 100% rename from docs/.vuepress/public/favicon.ico rename to favicon.ico diff --git a/hash-search.html b/hash-search.html new file mode 100644 index 0000000..a2fa549 --- /dev/null +++ b/hash-search.html @@ -0,0 +1,131 @@ + + + + + + Hash 表的查找 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/docs/.vuepress/public/img/bg.gif b/img/bg.gif similarity index 100% rename from docs/.vuepress/public/img/bg.gif rename to img/bg.gif diff --git a/docs/.vuepress/public/img/bg.jpeg b/img/bg.jpeg similarity index 100% rename from docs/.vuepress/public/img/bg.jpeg rename to img/bg.jpeg diff --git a/docs/.vuepress/public/img/bg.jpg b/img/bg.jpg similarity index 100% rename from docs/.vuepress/public/img/bg.jpg rename to img/bg.jpg diff --git a/docs/.vuepress/public/img/dunwu-logo.png b/img/dunwu-logo.png similarity index 100% rename from docs/.vuepress/public/img/dunwu-logo.png rename to img/dunwu-logo.png diff --git a/docs/.vuepress/public/img/favicon.ico b/img/favicon.ico similarity index 100% rename from docs/.vuepress/public/img/favicon.ico rename to img/favicon.ico diff --git a/docs/.vuepress/public/img/git.png b/img/git.png similarity index 100% rename from docs/.vuepress/public/img/git.png rename to img/git.png diff --git a/docs/.vuepress/public/img/logo.png b/img/logo.png similarity index 100% rename from docs/.vuepress/public/img/logo.png rename to img/logo.png diff --git a/docs/.vuepress/public/img/more.png b/img/more.png similarity index 100% rename from docs/.vuepress/public/img/more.png rename to img/more.png diff --git a/docs/.vuepress/public/img/other.png b/img/other.png similarity index 100% rename from docs/.vuepress/public/img/other.png rename to img/other.png diff --git a/docs/.vuepress/public/img/panda-waving.png b/img/panda-waving.png similarity index 100% rename from docs/.vuepress/public/img/panda-waving.png rename to img/panda-waving.png diff --git a/docs/.vuepress/public/img/python.png b/img/python.png similarity index 100% rename from docs/.vuepress/public/img/python.png rename to img/python.png diff --git a/docs/.vuepress/public/img/ui.png b/img/ui.png similarity index 100% rename from docs/.vuepress/public/img/ui.png rename to img/ui.png diff --git a/docs/.vuepress/public/img/web.png b/img/web.png similarity index 100% rename from docs/.vuepress/public/img/web.png rename to img/web.png diff --git a/index.html b/index.html new file mode 100644 index 0000000..1bd13e0 --- /dev/null +++ b/index.html @@ -0,0 +1,64 @@ + + + + + + ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/docs/.vuepress/public/markmap/01.html b/markmap/01.html similarity index 100% rename from docs/.vuepress/public/markmap/01.html rename to markmap/01.html diff --git a/package.json b/package.json deleted file mode 100644 index 47ccf68..0000000 --- a/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "algorithm-tutorial", - "version": "1.0.0", - "private": true, - "scripts": { - "clean": "rimraf docs/.temp", - "start": "vuepress dev docs", - "build": "vuepress build docs", - "deploy": "bash scripts/deploy.sh", - "editFm": "node utils/editFrontmatter.js", - "baiduPush": "node utils/baiduPush.js https://xugaoyi.com && bash baiduPush.sh", - "publish": "cd ./vdoing && npm publish && cd .. && yarn updateTheme", - "updateTheme": "yarn remove vuepress-theme-vdoing && rm -rf node_modules && yarn && yarn add vuepress-theme-vdoing -D", - "lint": "markdownlint -r markdownlint-rule-emphasis-style -c docs/.markdownlint.json **/*.md -i node_modules", - "lint:fix": "markdownlint -f -r markdownlint-rule-emphasis-style -c docs/.markdownlint.json **/*.md -i node_modules", - "show-help": "vuepress --help", - "view-info": "vuepress view-info ./ --temp docs/.temp" - }, - "devDependencies": { - "dayjs": "^1.9.7", - "inquirer": "^7.1.0", - "json2yaml": "^1.1.0", - "vuepress": "1.9.5", - "vuepress-plugin-baidu-autopush": "^1.0.1", - "vuepress-plugin-baidu-tongji": "^1.0.1", - "vuepress-plugin-comment": "^0.7.3", - "vuepress-plugin-demo-block": "^0.7.2", - "vuepress-plugin-fulltext-search": "^2.2.1", - "vuepress-plugin-one-click-copy": "^1.0.2", - "vuepress-plugin-thirdparty-search": "^1.0.2", - "vuepress-plugin-zooming": "^1.1.7", - "vuepress-theme-vdoing": "^1.11.2", - "yamljs": "^0.3.0", - "markdownlint-cli": "^0.25.0", - "markdownlint-rule-emphasis-style": "^1.0.1", - "rimraf": "^3.0.1", - "vue-toasted": "^1.1.25" - } -} diff --git a/pages/0a4414/index.html b/pages/0a4414/index.html new file mode 100644 index 0000000..1faad56 --- /dev/null +++ b/pages/0a4414/index.html @@ -0,0 +1,62 @@ + + + + + + 红黑树 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/0a4984/index.html b/pages/0a4984/index.html new file mode 100644 index 0000000..3142012 --- /dev/null +++ b/pages/0a4984/index.html @@ -0,0 +1,62 @@ + + + + + + 字典树 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/1f15c3/index.html b/pages/1f15c3/index.html new file mode 100644 index 0000000..f636d56 --- /dev/null +++ b/pages/1f15c3/index.html @@ -0,0 +1,62 @@ + + + + + + 栈和队列 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/21529b/index.html b/pages/21529b/index.html new file mode 100644 index 0000000..5723b39 --- /dev/null +++ b/pages/21529b/index.html @@ -0,0 +1,61 @@ + + + + + + 图 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/21c5f2/index.html b/pages/21c5f2/index.html new file mode 100644 index 0000000..b131c5f --- /dev/null +++ b/pages/21c5f2/index.html @@ -0,0 +1,302 @@ + + + + + + 线性表的排序 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/2a4131/index.html b/pages/2a4131/index.html new file mode 100644 index 0000000..6a918d7 --- /dev/null +++ b/pages/2a4131/index.html @@ -0,0 +1,98 @@ + + + + + + 复杂度分析 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/3fd76e/index.html b/pages/3fd76e/index.html new file mode 100644 index 0000000..74a830c --- /dev/null +++ b/pages/3fd76e/index.html @@ -0,0 +1,62 @@ + + + + + + B+树 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/4a217d/index.html b/pages/4a217d/index.html new file mode 100644 index 0000000..c4b237c --- /dev/null +++ b/pages/4a217d/index.html @@ -0,0 +1,63 @@ + + + + + + LSM树 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/4b1ed0/index.html b/pages/4b1ed0/index.html new file mode 100644 index 0000000..6cda9b4 --- /dev/null +++ b/pages/4b1ed0/index.html @@ -0,0 +1,193 @@ + + + + + + 线性表的查找 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/5a9bff/index.html b/pages/5a9bff/index.html new file mode 100644 index 0000000..3725cf1 --- /dev/null +++ b/pages/5a9bff/index.html @@ -0,0 +1,217 @@ + + + + + + 数组和链表 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/62671a/index.html b/pages/62671a/index.html new file mode 100644 index 0000000..44bab6d --- /dev/null +++ b/pages/62671a/index.html @@ -0,0 +1,63 @@ + + + + + + 跳表 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/8b1bd0/index.html b/pages/8b1bd0/index.html new file mode 100644 index 0000000..aeaddda --- /dev/null +++ b/pages/8b1bd0/index.html @@ -0,0 +1,60 @@ + + + + + + 数据结构和算法指南 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/92e4c1/index.html b/pages/92e4c1/index.html new file mode 100644 index 0000000..23e696c --- /dev/null +++ b/pages/92e4c1/index.html @@ -0,0 +1,63 @@ + + + + + + 树和二叉树 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/b501c7/index.html b/pages/b501c7/index.html new file mode 100644 index 0000000..9acf764 --- /dev/null +++ b/pages/b501c7/index.html @@ -0,0 +1,63 @@ + + + + + + 哈希表 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pages/ce297c/index.html b/pages/ce297c/index.html new file mode 100644 index 0000000..5337ea2 --- /dev/null +++ b/pages/ce297c/index.html @@ -0,0 +1,62 @@ + + + + + + 堆 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 9c66df2..0000000 --- a/pom.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - 4.0.0 - - io.github.dunwu - algorithm-tutorial - 1.0.0 - pom - ALGORITHM-TUTORIAL - algorithm-tutorial 示例源码 - - - codes/algorithm - - diff --git a/prettier.config.js b/prettier.config.js deleted file mode 100644 index eb6bb1f..0000000 --- a/prettier.config.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @see https://prettier.io/docs/en/options.html - * @see https://prettier.io/docs/en/configuration.html - */ -module.exports = { - tabWidth: 2, semi: false, singleQuote: true -} diff --git a/scripts/deploy.sh b/scripts/deploy.sh deleted file mode 100644 index a89fb1a..0000000 --- a/scripts/deploy.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env sh - -# ------------------------------------------------------------------------------ -# gh-pages 部署脚本 -# @author Zhang Peng -# @since 2020/2/10 -# ------------------------------------------------------------------------------ - -# 装载其它库 -ROOT_DIR=$( - cd $(dirname $0)/.. - pwd -) - -# 确保脚本抛出遇到的错误 -set -e - -# 生成静态文件 -npm run build - -# 进入生成的文件夹 -cd ${ROOT_DIR}/docs/.temp - -# 如果是发布到自定义域名 -# echo 'www.example.com' > CNAME - -if [[ ${GITHUB_TOKEN} && ${GITEE_TOKEN} ]]; then - msg='自动部署' - GITHUB_URL=https://dunwu:${GITHUB_TOKEN}@github.com/dunwu/algorithm-tutorial.git - GITEE_URL=https://turnon:${GITEE_TOKEN}@gitee.com/turnon/algorithm-tutorial.git - git config --global user.name "dunwu" - git config --global user.email "forbreak@163.com" -else - msg='手动部署' - GITHUB_URL=git@github.com:dunwu/algorithm-tutorial.git - GITEE_URL=git@gitee.com:turnon/algorithm-tutorial.git -fi -git init -git add -A -git commit -m "${msg}" -# 推送到github gh-pages分支 -git push -f "${GITHUB_URL}" master:gh-pages -git push -f "${GITEE_URL}" master:gh-pages - -cd - -rm -rf ${ROOT_DIR}/docs/.temp diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 0000000..db87df8 --- /dev/null +++ b/tags/index.html @@ -0,0 +1,67 @@ + + + + + + 标签 | ALGORITHM-TUTORIAL + + + + + + + + + + + + + + diff --git a/utils/config.yml b/utils/config.yml deleted file mode 100644 index 6fac6a2..0000000 --- a/utils/config.yml +++ /dev/null @@ -1,14 +0,0 @@ -#批量添加和修改、删除front matter配置文件 - -# 需要批量处理的路径,docs文件夹内的文件夹 (数组。映射路径:docs/arr[0]/arr[1] ... ) -path: - - docs # 第一个成员必须是docs - -# 要删除的字段 (数组) -delete: - # - test - # - tags - - # 要添加、修改front matter的数据 (front matter中没有的数据则添加,已有的数据则覆盖) -data: - article: false \ No newline at end of file diff --git a/utils/editFrontmatter.js b/utils/editFrontmatter.js deleted file mode 100644 index 8c223f4..0000000 --- a/utils/editFrontmatter.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * 批量添加和修改front matter ,需要配置 ./config.yml 文件。 - */ -const fs = require('fs'); // 文件模块 -const path = require('path'); // 路径模块 -const matter = require('gray-matter'); // front matter解析器 https://github.com/jonschlinkert/gray-matter -const jsonToYaml = require('json2yaml') -const yamlToJs = require('yamljs') -const inquirer = require('inquirer') // 命令行操作 -const chalk = require('chalk') // 命令行打印美化 -const readFileList = require('./modules/readFileList'); -const { type, repairDate} = require('./modules/fn'); -const log = console.log - -const configPath = path.join(__dirname, 'config.yml') // 配置文件的路径 - -main(); - -/** - * 主体函数 - */ -async function main() { - - const promptList = [{ - type: "confirm", - message: chalk.yellow('批量操作frontmatter有修改数据的风险,确定要继续吗?'), - name: "edit", - }]; - let edit = true; - - await inquirer.prompt(promptList).then(answers => { - edit = answers.edit - }) - - if(!edit) { // 退出操作 - return - } - - const config = yamlToJs.load(configPath) // 解析配置文件的数据转为js对象 - - if (type(config.path) !== 'array') { - log(chalk.red('路径配置有误,path字段应该是一个数组')) - return - } - - if (config.path[0] !== 'docs') { - log(chalk.red("路径配置有误,path数组的第一个成员必须是'docs'")) - return - } - - const filePath = path.join(__dirname, '..', ...config.path); // 要批量修改的文件路径 - const files = readFileList(filePath); // 读取所有md文件数据 - - files.forEach(file => { - let dataStr = fs.readFileSync(file.filePath, 'utf8');// 读取每个md文件的内容 - const fileMatterObj = matter(dataStr) // 解析md文件的front Matter。 fileMatterObj => {content:'剔除frontmatter后的文件内容字符串', data:{}, ...} - let matterData = fileMatterObj.data; // 得到md文件的front Matter - - let mark = false - // 删除操作 - if (config.delete) { - if( type(config.delete) !== 'array' ) { - log(chalk.yellow('未能完成删除操作,delete字段的值应该是一个数组!')) - } else { - config.delete.forEach(item => { - if (matterData[item]) { - delete matterData[item] - mark = true - } - }) - - } - } - - // 添加、修改操作 - if (type(config.data) === 'object') { - Object.assign(matterData, config.data) // 将配置数据合并到front Matter对象 - mark = true - } - - // 有操作时才继续 - if (mark) { - if(matterData.date && type(matterData.date) === 'date') { - matterData.date = repairDate(matterData.date) // 修复时间格式 - } - const newData = jsonToYaml.stringify(matterData).replace(/\n\s{2}/g,"\n").replace(/"/g,"") + '---\r\n' + fileMatterObj.content; - fs.writeFileSync(file.filePath, newData); // 写入 - log(chalk.green(`update frontmatter:${file.filePath} `)) - } - - }) -} diff --git a/utils/modules/fn.js b/utils/modules/fn.js deleted file mode 100644 index 48cbbd1..0000000 --- a/utils/modules/fn.js +++ /dev/null @@ -1,21 +0,0 @@ -// 类型判断 -exports.type = function (o){ - var s = Object.prototype.toString.call(o) - return s.match(/\[object (.*?)\]/)[1].toLowerCase() -} - - // 修复date时区格式的问题 - exports.repairDate = function (date) { - date = new Date(date); - return `${date.getUTCFullYear()}-${zero(date.getUTCMonth()+1)}-${zero(date.getUTCDate())} ${zero(date.getUTCHours())}:${zero(date.getUTCMinutes())}:${zero(date.getUTCSeconds())}`; -} - -// 日期的格式 -exports.dateFormat = function (date) { - return `${date.getFullYear()}-${zero(date.getMonth()+1)}-${zero(date.getDate())} ${zero(date.getHours())}:${zero(date.getMinutes())}:${zero(date.getSeconds())}` -} - -// 小于10补0 -function zero(d){ - return d.toString().padStart(2,'0') -} \ No newline at end of file diff --git a/utils/modules/readFileList.js b/utils/modules/readFileList.js deleted file mode 100644 index 8eb97c6..0000000 --- a/utils/modules/readFileList.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * 读取所有md文件数据 - */ -const fs = require('fs'); // 文件模块 -const path = require('path'); // 路径模块 -const docsRoot = path.join(__dirname, '..', '..', 'docs'); // docs文件路径 - -function readFileList(dir = docsRoot, filesList = []) { - const files = fs.readdirSync(dir); - files.forEach( (item, index) => { - let filePath = path.join(dir, item); - const stat = fs.statSync(filePath); - if (stat.isDirectory() && item !== '.vuepress') { - readFileList(path.join(dir, item), filesList); //递归读取文件 - } else { - if(path.basename(dir) !== 'docs'){ // 过滤docs目录级下的文件 - - const fileNameArr = path.basename(filePath).split('.') - let name = null, type = null; - if (fileNameArr.length === 2) { // 没有序号的文件 - name = fileNameArr[0] - type = fileNameArr[1] - } else if (fileNameArr.length === 3) { // 有序号的文件 - name = fileNameArr[1] - type = fileNameArr[2] - } else { // 超过两个‘.’的 - log(chalk.yellow(`warning: 该文件 "${filePath}" 没有按照约定命名,将忽略生成相应数据。`)) - return - } - if(type === 'md'){ // 过滤非md文件 - filesList.push({ - name, - filePath - }); - } - - } - } - }); - return filesList; -} - -module.exports = readFileList; \ No newline at end of file diff --git "a/\347\256\227\346\263\225\346\200\235\350\267\257.html" "b/\347\256\227\346\263\225\346\200\235\350\267\257.html" new file mode 100644 index 0000000..9aac1a7 --- /dev/null +++ "b/\347\256\227\346\263\225\346\200\235\350\267\257.html" @@ -0,0 +1,69 @@ + + + + + + 算法思路 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + + diff --git "a/\347\256\227\346\263\225\347\273\203\344\271\240-\346\240\221.html" "b/\347\256\227\346\263\225\347\273\203\344\271\240-\346\240\221.html" new file mode 100644 index 0000000..2e0ed57 --- /dev/null +++ "b/\347\256\227\346\263\225\347\273\203\344\271\240-\346\240\221.html" @@ -0,0 +1,59 @@ + + + + + + 数据结构 - 树 | ALGORITHM-TUTORIAL + + + + + + + + + + +
+ + +