├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── LICENSE.md
└── LICENSE.md
├── Makefile
├── README.md
├── index.py
├── index.yaml
├── leetcode
├── __init__.py
├── graphql.py
└── problems.py
├── little
├── __init__.py
├── model.py
├── render.py
├── solution.py
└── templates
│ └── README.md
└── solutions
├── 1143
└── 1.java
├── 1162
└── 1.java
├── 1372
└── 1.java
├── 1373
└── 1.java
├── 0001
└── 1.java
├── 0011
└── 1.java
├── 0019
└── 1.java
├── 0039
└── 1.java
├── 0040
└── 1.java
├── 0046
└── 1.java
├── 0047
└── 1.java
├── 0053
├── 1.java
├── 2.java
├── 3.java
├── 4.java
└── 5.java
├── 0072
└── 1.java
├── 0078
└── 1.java
├── 0090
└── 1.java
├── 0098
└── 1.java
├── 0102
└── 1.java
├── 0110
└── 1.java
├── 0112
└── 1.java
├── 0113
└── 1.java
├── 0123
└── 1.java
├── 0124
└── 1.java
├── 0141
└── 1.java
├── 0148
└── 1.java
├── 0167
└── 1.java
├── 0189
└── 1.java
├── 0198
└── 1.java
├── 0206
├── 1.cpp
└── 1.java
├── 0216
└── 1.java
├── 0240
└── 1.java
├── 0242
└── 1.java
├── 0303
└── 1.java
├── 0322
└── 1.java
├── 0377
└── 1.java
├── 0426
└── 1.java
├── 0463
└── 1.java
├── 0518
└── 1.java
├── 0543
└── 1.java
├── 0560
└── 1.java
├── 0563
└── 1.java
├── 0695
└── 1.java
├── 0718
└── 1.java
├── 0724
└── 1.java
├── 0827
└── 1.java
├── 0876
└── 1.java
└── 0978
└── 1.java
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Deploy static
2 |
3 | on:
4 | push:
5 | branches: [ "source" ]
6 | pull_request:
7 | branches: [ "source" ]
8 |
9 | # Allows you to run this workflow manually from the Actions tab
10 | workflow_dispatch:
11 |
12 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
13 | jobs:
14 | deploy:
15 | runs-on: ubuntu-latest
16 |
17 | # Steps represent a sequence of tasks that will be executed as part of the job
18 | steps:
19 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
20 | - uses: actions/checkout@v3
21 |
22 | # Runs a single command using the runners shell
23 | - name: Run a one-line script
24 | run: echo Hello, world!
25 |
26 | # Runs a set of commands using the runners shell
27 | - name: Run a multi-line script
28 | run: |
29 | echo Add other actions to build,
30 | echo test, and deploy your project.
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 |
3 | __pycache__/
4 |
--------------------------------------------------------------------------------
/LICENSE.md/LICENSE.md:
--------------------------------------------------------------------------------
1 | Attribution-ShareAlike 4.0 International
2 |
3 | =======================================================================
4 |
5 | Creative Commons Corporation ("Creative Commons") is not a law firm and
6 | does not provide legal services or legal advice. Distribution of
7 | Creative Commons public licenses does not create a lawyer-client or
8 | other relationship. Creative Commons makes its licenses and related
9 | information available on an "as-is" basis. Creative Commons gives no
10 | warranties regarding its licenses, any material licensed under their
11 | terms and conditions, or any related information. Creative Commons
12 | disclaims all liability for damages resulting from their use to the
13 | fullest extent possible.
14 |
15 | Using Creative Commons Public Licenses
16 |
17 | Creative Commons public licenses provide a standard set of terms and
18 | conditions that creators and other rights holders may use to share
19 | original works of authorship and other material subject to copyright
20 | and certain other rights specified in the public license below. The
21 | following considerations are for informational purposes only, are not
22 | exhaustive, and do not form part of our licenses.
23 |
24 | Considerations for licensors: Our public licenses are
25 | intended for use by those authorized to give the public
26 | permission to use material in ways otherwise restricted by
27 | copyright and certain other rights. Our licenses are
28 | irrevocable. Licensors should read and understand the terms
29 | and conditions of the license they choose before applying it.
30 | Licensors should also secure all rights necessary before
31 | applying our licenses so that the public can reuse the
32 | material as expected. Licensors should clearly mark any
33 | material not subject to the license. This includes other CC-
34 | licensed material, or material used under an exception or
35 | limitation to copyright. More considerations for licensors:
36 | wiki.creativecommons.org/Considerations_for_licensors
37 |
38 | Considerations for the public: By using one of our public
39 | licenses, a licensor grants the public permission to use the
40 | licensed material under specified terms and conditions. If
41 | the licensor's permission is not necessary for any reason--for
42 | example, because of any applicable exception or limitation to
43 | copyright--then that use is not regulated by the license. Our
44 | licenses grant only permissions under copyright and certain
45 | other rights that a licensor has authority to grant. Use of
46 | the licensed material may still be restricted for other
47 | reasons, including because others have copyright or other
48 | rights in the material. A licensor may make special requests,
49 | such as asking that all changes be marked or described.
50 | Although not required by our licenses, you are encouraged to
51 | respect those requests where reasonable. More considerations
52 | for the public:
53 | wiki.creativecommons.org/Considerations_for_licensees
54 |
55 | =======================================================================
56 |
57 | Creative Commons Attribution-ShareAlike 4.0 International Public
58 | License
59 |
60 | By exercising the Licensed Rights (defined below), You accept and agree
61 | to be bound by the terms and conditions of this Creative Commons
62 | Attribution-ShareAlike 4.0 International Public License ("Public
63 | License"). To the extent this Public License may be interpreted as a
64 | contract, You are granted the Licensed Rights in consideration of Your
65 | acceptance of these terms and conditions, and the Licensor grants You
66 | such rights in consideration of benefits the Licensor receives from
67 | making the Licensed Material available under these terms and
68 | conditions.
69 |
70 |
71 | Section 1 -- Definitions.
72 |
73 | a. Adapted Material means material subject to Copyright and Similar
74 | Rights that is derived from or based upon the Licensed Material
75 | and in which the Licensed Material is translated, altered,
76 | arranged, transformed, or otherwise modified in a manner requiring
77 | permission under the Copyright and Similar Rights held by the
78 | Licensor. For purposes of this Public License, where the Licensed
79 | Material is a musical work, performance, or sound recording,
80 | Adapted Material is always produced where the Licensed Material is
81 | synched in timed relation with a moving image.
82 |
83 | b. Adapter's License means the license You apply to Your Copyright
84 | and Similar Rights in Your contributions to Adapted Material in
85 | accordance with the terms and conditions of this Public License.
86 |
87 | c. BY-SA Compatible License means a license listed at
88 | creativecommons.org/compatiblelicenses, approved by Creative
89 | Commons as essentially the equivalent of this Public License.
90 |
91 | d. Copyright and Similar Rights means copyright and/or similar rights
92 | closely related to copyright including, without limitation,
93 | performance, broadcast, sound recording, and Sui Generis Database
94 | Rights, without regard to how the rights are labeled or
95 | categorized. For purposes of this Public License, the rights
96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
97 | Rights.
98 |
99 | e. Effective Technological Measures means those measures that, in the
100 | absence of proper authority, may not be circumvented under laws
101 | fulfilling obligations under Article 11 of the WIPO Copyright
102 | Treaty adopted on December 20, 1996, and/or similar international
103 | agreements.
104 |
105 | f. Exceptions and Limitations means fair use, fair dealing, and/or
106 | any other exception or limitation to Copyright and Similar Rights
107 | that applies to Your use of the Licensed Material.
108 |
109 | g. License Elements means the license attributes listed in the name
110 | of a Creative Commons Public License. The License Elements of this
111 | Public License are Attribution and ShareAlike.
112 |
113 | h. Licensed Material means the artistic or literary work, database,
114 | or other material to which the Licensor applied this Public
115 | License.
116 |
117 | i. Licensed Rights means the rights granted to You subject to the
118 | terms and conditions of this Public License, which are limited to
119 | all Copyright and Similar Rights that apply to Your use of the
120 | Licensed Material and that the Licensor has authority to license.
121 |
122 | j. Licensor means the individual(s) or entity(ies) granting rights
123 | under this Public License.
124 |
125 | k. Share means to provide material to the public by any means or
126 | process that requires permission under the Licensed Rights, such
127 | as reproduction, public display, public performance, distribution,
128 | dissemination, communication, or importation, and to make material
129 | available to the public including in ways that members of the
130 | public may access the material from a place and at a time
131 | individually chosen by them.
132 |
133 | l. Sui Generis Database Rights means rights other than copyright
134 | resulting from Directive 96/9/EC of the European Parliament and of
135 | the Council of 11 March 1996 on the legal protection of databases,
136 | as amended and/or succeeded, as well as other essentially
137 | equivalent rights anywhere in the world.
138 |
139 | m. You means the individual or entity exercising the Licensed Rights
140 | under this Public License. Your has a corresponding meaning.
141 |
142 |
143 | Section 2 -- Scope.
144 |
145 | a. License grant.
146 |
147 | 1. Subject to the terms and conditions of this Public License,
148 | the Licensor hereby grants You a worldwide, royalty-free,
149 | non-sublicensable, non-exclusive, irrevocable license to
150 | exercise the Licensed Rights in the Licensed Material to:
151 |
152 | a. reproduce and Share the Licensed Material, in whole or
153 | in part; and
154 |
155 | b. produce, reproduce, and Share Adapted Material.
156 |
157 | 2. Exceptions and Limitations. For the avoidance of doubt, where
158 | Exceptions and Limitations apply to Your use, this Public
159 | License does not apply, and You do not need to comply with
160 | its terms and conditions.
161 |
162 | 3. Term. The term of this Public License is specified in Section
163 | 6(a).
164 |
165 | 4. Media and formats; technical modifications allowed. The
166 | Licensor authorizes You to exercise the Licensed Rights in
167 | all media and formats whether now known or hereafter created,
168 | and to make technical modifications necessary to do so. The
169 | Licensor waives and/or agrees not to assert any right or
170 | authority to forbid You from making technical modifications
171 | necessary to exercise the Licensed Rights, including
172 | technical modifications necessary to circumvent Effective
173 | Technological Measures. For purposes of this Public License,
174 | simply making modifications authorized by this Section 2(a)
175 | (4) never produces Adapted Material.
176 |
177 | 5. Downstream recipients.
178 |
179 | a. Offer from the Licensor -- Licensed Material. Every
180 | recipient of the Licensed Material automatically
181 | receives an offer from the Licensor to exercise the
182 | Licensed Rights under the terms and conditions of this
183 | Public License.
184 |
185 | b. Additional offer from the Licensor -- Adapted Material.
186 | Every recipient of Adapted Material from You
187 | automatically receives an offer from the Licensor to
188 | exercise the Licensed Rights in the Adapted Material
189 | under the conditions of the Adapter's License You apply.
190 |
191 | c. No downstream restrictions. You may not offer or impose
192 | any additional or different terms or conditions on, or
193 | apply any Effective Technological Measures to, the
194 | Licensed Material if doing so restricts exercise of the
195 | Licensed Rights by any recipient of the Licensed
196 | Material.
197 |
198 | 6. No endorsement. Nothing in this Public License constitutes or
199 | may be construed as permission to assert or imply that You
200 | are, or that Your use of the Licensed Material is, connected
201 | with, or sponsored, endorsed, or granted official status by,
202 | the Licensor or others designated to receive attribution as
203 | provided in Section 3(a)(1)(A)(i).
204 |
205 | b. Other rights.
206 |
207 | 1. Moral rights, such as the right of integrity, are not
208 | licensed under this Public License, nor are publicity,
209 | privacy, and/or other similar personality rights; however, to
210 | the extent possible, the Licensor waives and/or agrees not to
211 | assert any such rights held by the Licensor to the limited
212 | extent necessary to allow You to exercise the Licensed
213 | Rights, but not otherwise.
214 |
215 | 2. Patent and trademark rights are not licensed under this
216 | Public License.
217 |
218 | 3. To the extent possible, the Licensor waives any right to
219 | collect royalties from You for the exercise of the Licensed
220 | Rights, whether directly or through a collecting society
221 | under any voluntary or waivable statutory or compulsory
222 | licensing scheme. In all other cases the Licensor expressly
223 | reserves any right to collect such royalties.
224 |
225 |
226 | Section 3 -- License Conditions.
227 |
228 | Your exercise of the Licensed Rights is expressly made subject to the
229 | following conditions.
230 |
231 | a. Attribution.
232 |
233 | 1. If You Share the Licensed Material (including in modified
234 | form), You must:
235 |
236 | a. retain the following if it is supplied by the Licensor
237 | with the Licensed Material:
238 |
239 | i. identification of the creator(s) of the Licensed
240 | Material and any others designated to receive
241 | attribution, in any reasonable manner requested by
242 | the Licensor (including by pseudonym if
243 | designated);
244 |
245 | ii. a copyright notice;
246 |
247 | iii. a notice that refers to this Public License;
248 |
249 | iv. a notice that refers to the disclaimer of
250 | warranties;
251 |
252 | v. a URI or hyperlink to the Licensed Material to the
253 | extent reasonably practicable;
254 |
255 | b. indicate if You modified the Licensed Material and
256 | retain an indication of any previous modifications; and
257 |
258 | c. indicate the Licensed Material is licensed under this
259 | Public License, and include the text of, or the URI or
260 | hyperlink to, this Public License.
261 |
262 | 2. You may satisfy the conditions in Section 3(a)(1) in any
263 | reasonable manner based on the medium, means, and context in
264 | which You Share the Licensed Material. For example, it may be
265 | reasonable to satisfy the conditions by providing a URI or
266 | hyperlink to a resource that includes the required
267 | information.
268 |
269 | 3. If requested by the Licensor, You must remove any of the
270 | information required by Section 3(a)(1)(A) to the extent
271 | reasonably practicable.
272 |
273 | b. ShareAlike.
274 |
275 | In addition to the conditions in Section 3(a), if You Share
276 | Adapted Material You produce, the following conditions also apply.
277 |
278 | 1. The Adapter's License You apply must be a Creative Commons
279 | license with the same License Elements, this version or
280 | later, or a BY-SA Compatible License.
281 |
282 | 2. You must include the text of, or the URI or hyperlink to, the
283 | Adapter's License You apply. You may satisfy this condition
284 | in any reasonable manner based on the medium, means, and
285 | context in which You Share Adapted Material.
286 |
287 | 3. You may not offer or impose any additional or different terms
288 | or conditions on, or apply any Effective Technological
289 | Measures to, Adapted Material that restrict exercise of the
290 | rights granted under the Adapter's License You apply.
291 |
292 |
293 | Section 4 -- Sui Generis Database Rights.
294 |
295 | Where the Licensed Rights include Sui Generis Database Rights that
296 | apply to Your use of the Licensed Material:
297 |
298 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
299 | to extract, reuse, reproduce, and Share all or a substantial
300 | portion of the contents of the database;
301 |
302 | b. if You include all or a substantial portion of the database
303 | contents in a database in which You have Sui Generis Database
304 | Rights, then the database in which You have Sui Generis Database
305 | Rights (but not its individual contents) is Adapted Material,
306 |
307 | including for purposes of Section 3(b); and
308 | c. You must comply with the conditions in Section 3(a) if You Share
309 | all or a substantial portion of the contents of the database.
310 |
311 | For the avoidance of doubt, this Section 4 supplements and does not
312 | replace Your obligations under this Public License where the Licensed
313 | Rights include other Copyright and Similar Rights.
314 |
315 |
316 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
317 |
318 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
319 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
320 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
321 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
322 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
323 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
324 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
325 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
326 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
327 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
328 |
329 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
330 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
331 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
332 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
333 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
334 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
335 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
336 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
337 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
338 |
339 | c. The disclaimer of warranties and limitation of liability provided
340 | above shall be interpreted in a manner that, to the extent
341 | possible, most closely approximates an absolute disclaimer and
342 | waiver of all liability.
343 |
344 |
345 | Section 6 -- Term and Termination.
346 |
347 | a. This Public License applies for the term of the Copyright and
348 | Similar Rights licensed here. However, if You fail to comply with
349 | this Public License, then Your rights under this Public License
350 | terminate automatically.
351 |
352 | b. Where Your right to use the Licensed Material has terminated under
353 | Section 6(a), it reinstates:
354 |
355 | 1. automatically as of the date the violation is cured, provided
356 | it is cured within 30 days of Your discovery of the
357 | violation; or
358 |
359 | 2. upon express reinstatement by the Licensor.
360 |
361 | For the avoidance of doubt, this Section 6(b) does not affect any
362 | right the Licensor may have to seek remedies for Your violations
363 | of this Public License.
364 |
365 | c. For the avoidance of doubt, the Licensor may also offer the
366 | Licensed Material under separate terms or conditions or stop
367 | distributing the Licensed Material at any time; however, doing so
368 | will not terminate this Public License.
369 |
370 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
371 | License.
372 |
373 |
374 | Section 7 -- Other Terms and Conditions.
375 |
376 | a. The Licensor shall not be bound by any additional or different
377 | terms or conditions communicated by You unless expressly agreed.
378 |
379 | b. Any arrangements, understandings, or agreements regarding the
380 | Licensed Material not stated herein are separate from and
381 | independent of the terms and conditions of this Public License.
382 |
383 |
384 | Section 8 -- Interpretation.
385 |
386 | a. For the avoidance of doubt, this Public License does not, and
387 | shall not be interpreted to, reduce, limit, restrict, or impose
388 | conditions on any use of the Licensed Material that could lawfully
389 | be made without permission under this Public License.
390 |
391 | b. To the extent possible, if any provision of this Public License is
392 | deemed unenforceable, it shall be automatically reformed to the
393 | minimum extent necessary to make it enforceable. If the provision
394 | cannot be reformed, it shall be severed from this Public License
395 | without affecting the enforceability of the remaining terms and
396 | conditions.
397 |
398 | c. No term or condition of this Public License will be waived and no
399 | failure to comply consented to unless expressly agreed to by the
400 | Licensor.
401 |
402 | d. Nothing in this Public License constitutes or may be interpreted
403 | as a limitation upon, or waiver of, any privileges and immunities
404 | that apply to the Licensor or You, including from the legal
405 | processes of any jurisdiction or authority.
406 |
407 |
408 | =======================================================================
409 |
410 | Creative Commons is not a party to its public licenses.
411 | Notwithstanding, Creative Commons may elect to apply one of its public
412 | licenses to material it publishes and in those instances will be
413 | considered the “Licensor.” The text of the Creative Commons public
414 | licenses is dedicated to the public domain under the CC0 Public Domain
415 | Dedication. Except for the limited purpose of indicating that material
416 | is shared under a Creative Commons public license or as otherwise
417 | permitted by the Creative Commons policies published at
418 | creativecommons.org/policies, Creative Commons does not authorize the
419 | use of the trademark "Creative Commons" or any other trademark or logo
420 | of Creative Commons without its prior written consent including,
421 | without limitation, in connection with any unauthorized modifications
422 | to any of its public licenses or any other arrangements,
423 | understandings, or agreements concerning use of licensed material. For
424 | the avoidance of doubt, this paragraph does not form part of the public
425 | licenses.
426 |
427 | Creative Commons may be contacted at creativecommons.org.
428 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all
2 |
3 | all:
4 | cp /Users/william/bloomstore/index/index.yaml .
5 | python3 index.py index.yaml
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Little Algorithm
2 |
3 | 从 2020 年初开始,我在公众号《面向大象编程》上发表面试算法、LeetCode 题解相关文章,至今收获不少好评。此仓库是公众号内容的补充,包括公众号文章涉及到的题目的参考代码,以及 LeetCode 题目到文章链接的索引。
4 |
5 | ## 如何使用本仓库
6 |
7 | 1、关注我的公众号 **面向大象编程** 获取文章更新。我的公众号坚持原创更新,干货分享,绝对是值得关注的技术公众号。
8 |
9 | 2、公众号文章目前绝大部分都是拿 LeetCode 原题作为例题,讲解算法题解题思路。从下方「参考代码」部分的表格中找到你喜欢的 LeetCode 题目,即可找到对应的参考代码以及讲解文章链接。
10 |
11 | ## 参考代码
12 |
13 | | 题号 | 题目名 | 题解代码 | 对应文章 |
14 | | :-: | --- | --- | --- |
15 | | [11](https://leetcode-cn.com/problems/container-with-most-water) | Container With Most Water
盛最多水的容器 | [Java](solutions/0011/1.java) | [LeetCode 11. 盛最多水的容器](https://mp.weixin.qq.com/s/RfTyqnIpLwJpRtzPWVZvHA) |
16 | | [19](https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list) | Remove Nth Node From End of List
删除链表的倒数第N个节点 | [Java](solutions/0019/1.java) | [LeetCode 例题精讲 \| 05 双指针×链表问题:快慢指针](https://mp.weixin.qq.com/s/2CLloKhD8tbId1-9uOsNzw) |
17 | | [39](https://leetcode-cn.com/problems/combination-sum) | Combination Sum
组合总和 | [Java](solutions/0039/1.java) | [一套代码解决 Combination Sum 系列问题(LeetCode 39/40/216)](https://mp.weixin.qq.com/s/uLd8V-YB3Fy3ZNUcQHo8jw) |
18 | | [40](https://leetcode-cn.com/problems/combination-sum-ii) | Combination Sum II
组合总和 II | [Java](solutions/0040/1.java) | [一套代码解决 Combination Sum 系列问题(LeetCode 39/40/216)](https://mp.weixin.qq.com/s/uLd8V-YB3Fy3ZNUcQHo8jw) |
19 | | [46](https://leetcode-cn.com/problems/permutations) | Permutations
全排列 | [Java](solutions/0046/1.java) | [LeetCode 例题精讲 \| 08 排列组合问题:回溯法的候选集合](https://mp.weixin.qq.com/s/b6og5Ro4vx-3--qPpi22Mw) |
20 | | [47](https://leetcode-cn.com/problems/permutations-ii) | Permutations II
全排列 II | [Java](solutions/0047/1.java) | [LeetCode 例题精讲 \| 09 排列组合问题再探:回溯法的去重策略](https://mp.weixin.qq.com/s/h-dzViBTVWmkReA-dbufXA) |
21 | | [53](https://leetcode-cn.com/problems/maximum-subarray) | Maximum Subarray
最大子序和 | Java([1](solutions/0053/5.java), [2](solutions/0053/4.java), [3](solutions/0053/3.java), [4](solutions/0053/2.java), [5](solutions/0053/1.java)) | [LeetCode 例题精讲 \| 16 最大子数组和:子数组类问题的动态规划技巧](https://mp.weixin.qq.com/s/e6L2tvWOS_D0obHR_360Gw) |
22 | | [72](https://leetcode-cn.com/problems/edit-distance) | Edit Distance
编辑距离 | [Java](solutions/0072/1.java) | [经典动态规划:编辑距离](https://mp.weixin.qq.com/s/sJZw3ECrgpNItjdzd7g-dA) |
23 | | [77](https://leetcode-cn.com/problems/combinations) | Combinations
组合 | | [LeetCode 例题精讲 \| 08 排列组合问题:回溯法的候选集合](https://mp.weixin.qq.com/s/b6og5Ro4vx-3--qPpi22Mw) |
24 | | [78](https://leetcode-cn.com/problems/subsets) | Subsets
子集 | [Java](solutions/0078/1.java) | [LeetCode 例题精讲 \| 03 从二叉树遍历到回溯算法](https://mp.weixin.qq.com/s/g5uvxi1lyxmWC4LtP0Bdlw) |
25 | | [90](https://leetcode-cn.com/problems/subsets-ii) | Subsets II
子集 II | [Java](solutions/0090/1.java) | [LeetCode 例题精讲 \| 09 排列组合问题再探:回溯法的去重策略](https://mp.weixin.qq.com/s/h-dzViBTVWmkReA-dbufXA) |
26 | | [98](https://leetcode-cn.com/problems/validate-binary-search-tree) | Validate Binary Search Tree
验证二叉搜索树 | [Java](solutions/0098/1.java) | [LeetCode 例题精讲 \| 11 二叉树转化为链表:二叉树遍历中的相邻结点](https://mp.weixin.qq.com/s/nzQmAOjKMj3ikHXeCUK1zg) |
27 | | [102](https://leetcode-cn.com/problems/binary-tree-level-order-traversal) | Binary Tree Level Order Traversal
二叉树的层序遍历 | [Java](solutions/0102/1.java) | [LeetCode 例题精讲 \| 13 BFS 的使用场景:层序遍历、最短路径问题](https://mp.weixin.qq.com/s/j6Cjn1DgaMaN1Kwc9mF13Q) |
28 | | [110](https://leetcode-cn.com/problems/balanced-binary-tree) | Balanced Binary Tree
平衡二叉树 | [Java](solutions/0110/1.java) | [LeetCode 例题精讲 \| 10 二叉树直径:二叉树遍历中的全局变量](https://mp.weixin.qq.com/s/ZDszP9ashAX6WgtVzhheaQ) |
29 | | [112](https://leetcode-cn.com/problems/path-sum) | Path Sum
路径总和 | [Java](solutions/0112/1.java) | [LeetCode 例题精讲 \| 02 Path Sum:二叉树的子问题划分](https://mp.weixin.qq.com/s/uSjnfPPXTzScCRQBv6ew1Q) |
30 | | [113](https://leetcode-cn.com/problems/path-sum-ii) | Path Sum II
路径总和 II | [Java](solutions/0113/1.java) | [LeetCode 例题精讲 \| 03 从二叉树遍历到回溯算法](https://mp.weixin.qq.com/s/g5uvxi1lyxmWC4LtP0Bdlw) |
31 | | [123](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii) | Best Time to Buy and Sell Stock III
买卖股票的最佳时机 III | [Java](solutions/0123/1.java) | [一文教你股票买卖问题实用而装逼的解法](https://mp.weixin.qq.com/s/CWGKl0Ctfc6wStcvBJsD3Q) |
32 | | [124](https://leetcode-cn.com/problems/binary-tree-maximum-path-sum) | Binary Tree Maximum Path Sum
二叉树中的最大路径和 | [Java](solutions/0124/1.java) | [LeetCode 例题精讲 \| 10 二叉树直径:二叉树遍历中的全局变量](https://mp.weixin.qq.com/s/ZDszP9ashAX6WgtVzhheaQ) |
33 | | [141](https://leetcode-cn.com/problems/linked-list-cycle) | Linked List Cycle
环形链表 | [Java](solutions/0141/1.java) | [LeetCode 例题精讲 \| 05 双指针×链表问题:快慢指针](https://mp.weixin.qq.com/s/2CLloKhD8tbId1-9uOsNzw) |
34 | | [148](https://leetcode-cn.com/problems/sort-list) | Sort List
排序链表 | [Java](solutions/0148/1.java) | [链表综合题 \| LeetCode 148. 链表排序](https://mp.weixin.qq.com/s/sg2qP5uBEp--bTOYdK_BMw) |
35 | | [167](https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted) | Two Sum II - Input array is sorted
两数之和 II - 输入有序数组 | [Java](solutions/0167/1.java) | [LeetCode 例题精讲 \| 04 用双指针解 Two Sum:缩减搜索空间](https://mp.weixin.qq.com/s/Zqy2CAu7L8zw-g1N2v76SQ) |
36 | | [189](https://leetcode-cn.com/problems/rotate-array) | Rotate Array
旋转数组 | [Java](solutions/0189/1.java) | [LeetCode 例题精讲 \| 06 旋转数组问题:基本操作的威力](https://mp.weixin.qq.com/s/S-wAKPu8OcI7FyrBkYBzQg) |
37 | | [198](https://leetcode-cn.com/problems/house-robber) | House Robber
打家劫舍 | [Java](solutions/0198/1.java) | [LeetCode 例题精讲 \| 14 打家劫舍问题:动态规划的解题四步骤](https://mp.weixin.qq.com/s/hSAID_hOPGy_DKleq3_DdA) |
38 | | [206](https://leetcode-cn.com/problems/reverse-linked-list) | Reverse Linked List
反转链表 | [Java](solutions/0206/1.java) | [LeetCode 例题精讲 \| 01 反转链表:如何轻松重构链表](https://mp.weixin.qq.com/s/KTA6Ng1C33fydEn4VDj-7Q) |
39 | | [216](https://leetcode-cn.com/problems/combination-sum-iii) | Combination Sum III
组合总和 III | [Java](solutions/0216/1.java) | [一套代码解决 Combination Sum 系列问题(LeetCode 39/40/216)](https://mp.weixin.qq.com/s/uLd8V-YB3Fy3ZNUcQHo8jw) |
40 | | [240](https://leetcode-cn.com/problems/search-a-2d-matrix-ii) | Search a 2D Matrix II
搜索二维矩阵 II | [Java](solutions/0240/1.java) | [LeetCode 例题精讲 \| 04 用双指针解 Two Sum:缩减搜索空间](https://mp.weixin.qq.com/s/Zqy2CAu7L8zw-g1N2v76SQ) |
41 | | [242](https://leetcode-cn.com/problems/valid-anagram) | Valid Anagram
有效的字母异位词 | [Java](solutions/0242/1.java) | [LeetCode 例题精讲 \| 07 变位词问题:基本数据结构的威力](https://mp.weixin.qq.com/s/aC8P2Yme35H49GzcoqhzLg) |
42 | | [303](https://leetcode-cn.com/problems/range-sum-query-immutable) | Range Sum Query - Immutable
区域和检索 - 数组不可变 | [Java](solutions/0303/1.java) | [LeetCode 例题精讲 \| 18 前缀和:空间换时间的技巧](https://mp.weixin.qq.com/s/lg4tZUfGcXoKq1jOQtpKJw) |
43 | | [322](https://leetcode-cn.com/problems/coin-change) | Coin Change
零钱兑换 | [Java](solutions/0322/1.java) | [经典动态规划:「换硬币」系列三道问题详解](https://mp.weixin.qq.com/s/pTMsIg9I0z102DQ4HMrYCA) |
44 | | [377](https://leetcode-cn.com/problems/combination-sum-iv) | Combination Sum IV
组合总和 Ⅳ | [Java](solutions/0377/1.java) | [经典动态规划:「换硬币」系列三道问题详解](https://mp.weixin.qq.com/s/pTMsIg9I0z102DQ4HMrYCA) |
45 | | [426](https://leetcode-cn.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list) | Convert Binary Search Tree to Sorted Doubly Linked List
将二叉搜索树转化为排序的双向链表 | [Java](solutions/0426/1.java) | [LeetCode 例题精讲 \| 11 二叉树转化为链表:二叉树遍历中的相邻结点](https://mp.weixin.qq.com/s/nzQmAOjKMj3ikHXeCUK1zg) |
46 | | [463](https://leetcode-cn.com/problems/island-perimeter) | Island Perimeter
岛屿的周长 | [Java](solutions/0463/1.java) | [LeetCode 例题精讲 \| 12 岛屿问题:网格结构中的 DFS](https://mp.weixin.qq.com/s/1Xi6icqr6JiT8D0jTeamzg) |
47 | | [518](https://leetcode-cn.com/problems/coin-change-2) | Coin Change 2
零钱兑换 II | [Java](solutions/0518/1.java) | [经典动态规划:「换硬币」系列三道问题详解](https://mp.weixin.qq.com/s/pTMsIg9I0z102DQ4HMrYCA) |
48 | | [543](https://leetcode-cn.com/problems/diameter-of-binary-tree) | Diameter of Binary Tree
二叉树的直径 | [Java](solutions/0543/1.java) | [LeetCode 例题精讲 \| 10 二叉树直径:二叉树遍历中的全局变量](https://mp.weixin.qq.com/s/ZDszP9ashAX6WgtVzhheaQ) |
49 | | [560](https://leetcode-cn.com/problems/subarray-sum-equals-k) | Subarray Sum Equals K
和为K的子数组 | [Java](solutions/0560/1.java) | [LeetCode 例题精讲 \| 18 前缀和:空间换时间的技巧](https://mp.weixin.qq.com/s/lg4tZUfGcXoKq1jOQtpKJw) |
50 | | [563](https://leetcode-cn.com/problems/binary-tree-tilt) | Binary Tree Tilt
二叉树的坡度 | [Java](solutions/0563/1.java) | [LeetCode 例题精讲 \| 10 二叉树直径:二叉树遍历中的全局变量](https://mp.weixin.qq.com/s/ZDszP9ashAX6WgtVzhheaQ) |
51 | | [695](https://leetcode-cn.com/problems/max-area-of-island) | Max Area of Island
岛屿的最大面积 | [Java](solutions/0695/1.java) | [LeetCode 例题精讲 \| 12 岛屿问题:网格结构中的 DFS](https://mp.weixin.qq.com/s/1Xi6icqr6JiT8D0jTeamzg) |
52 | | [718](https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray) | Maximum Length of Repeated Subarray
最长重复子数组 | [Java](solutions/0718/1.java) | [LeetCode 例题精讲 \| 16 最大子数组和:子数组类问题的动态规划技巧](https://mp.weixin.qq.com/s/e6L2tvWOS_D0obHR_360Gw) |
53 | | [724](https://leetcode-cn.com/problems/find-pivot-index) | Find Pivot Index
寻找数组的中心索引 | [Java](solutions/0724/1.java) | [LeetCode 例题精讲 \| 18 前缀和:空间换时间的技巧](https://mp.weixin.qq.com/s/lg4tZUfGcXoKq1jOQtpKJw) |
54 | | [827](https://leetcode-cn.com/problems/making-a-large-island) | Making A Large Island
最大人工岛 | [Java](solutions/0827/1.java) | [LeetCode 例题精讲 \| 12 岛屿问题:网格结构中的 DFS](https://mp.weixin.qq.com/s/1Xi6icqr6JiT8D0jTeamzg) |
55 | | [876](https://leetcode-cn.com/problems/middle-of-the-linked-list) | Middle of the Linked List
链表的中间结点 | [Java](solutions/0876/1.java) | [LeetCode 例题精讲 \| 05 双指针×链表问题:快慢指针](https://mp.weixin.qq.com/s/2CLloKhD8tbId1-9uOsNzw) |
56 | | [978](https://leetcode-cn.com/problems/longest-turbulent-subarray) | Longest Turbulent Subarray
最长湍流子数组 | [Java](solutions/0978/1.java) | [LeetCode 例题精讲 \| 17 动态规划如何拆分子问题,简化思路](https://mp.weixin.qq.com/s/TE-p4WYQBBubhxmT137O9w) |
57 | | [1143](https://leetcode-cn.com/problems/longest-common-subsequence) | Longest Common Subsequence
最长公共子序列 | [Java](solutions/1143/1.java) | [LeetCode 例题精讲 \| 15 最长公共子序列:二维动态规划的解法](https://mp.weixin.qq.com/s/dHIeiIQWAeynmYSq9IdqJg) |
58 | | [1162](https://leetcode-cn.com/problems/as-far-from-land-as-possible) | As Far from Land as Possible
地图分析 | [Java](solutions/1162/1.java) | [LeetCode 例题精讲 \| 13 BFS 的使用场景:层序遍历、最短路径问题](https://mp.weixin.qq.com/s/j6Cjn1DgaMaN1Kwc9mF13Q) |
59 | | [1372](https://leetcode-cn.com/problems/longest-zigzag-path-in-a-binary-tree) | Longest ZigZag Path in a Binary Tree
二叉树中的最长交错路径 | [Java](solutions/1372/1.java) | [二叉树问题太复杂?「三步走」方法解决它!](https://mp.weixin.qq.com/s/rweTurnXKD5XY5bH2nqlPQ) |
60 | | [1373](https://leetcode-cn.com/problems/maximum-sum-bst-in-binary-tree) | Maximum Sum BST in Binary Tree
二叉搜索子树的最大键值和 | [Java](solutions/1373/1.java) | [二叉树问题太复杂?「三步走」方法解决它!](https://mp.weixin.qq.com/s/rweTurnXKD5XY5bH2nqlPQ) |
61 |
62 |
63 | ## 公众号文章整理
64 |
65 | 可关注公众号《面向大象编程》,在公众号菜单中有文章目录。
66 |
--------------------------------------------------------------------------------
/index.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import sys
4 | from dataclasses import dataclass
5 | from typing import List
6 |
7 | import yaml
8 |
9 | import leetcode.graphql
10 | import leetcode.problems
11 | from little import render
12 | from little.model import SolutionList
13 | from little.solution import find_solutions
14 |
15 |
16 | @dataclass
17 | class Problem:
18 | fid: str
19 | slug: str
20 | title: str
21 | translated_title: str
22 | url: str
23 | solutions: SolutionList
24 |
25 | @classmethod
26 | def from_fid(cls, fid: str):
27 | problem = leetcode.problems.query_by_id(fid)
28 | # TODO add local cache
29 | translated_title = leetcode.graphql.query_translated_title_by_slug(problem.slug)
30 | solutions = find_solutions(problem.fid)
31 | # print('translated_title: ', problem.translated_title)
32 | return Problem(fid=fid,
33 | slug=problem.slug,
34 | title=problem.title,
35 | translated_title=translated_title,
36 | url=problem.url,
37 | solutions=solutions)
38 |
39 |
40 | @dataclass
41 | class ArticleInfo:
42 | title: str
43 | link: str
44 | problems: List[Problem]
45 |
46 | def __post_init__(self) -> None:
47 | if self.problems is None:
48 | self.problems = []
49 | else:
50 | self.problems = [Problem.from_fid(str(pid)) for pid in self.problems]
51 |
52 | @property
53 | def escaped_title(self) -> str:
54 | return self.title.replace('|', '\|')
55 |
56 | def md_piece(self) -> str:
57 | if self.link is None:
58 | return self.escaped_title
59 | else:
60 | return '[{}]({})'.format(self.escaped_title, self.link)
61 |
62 | def build_table(articleInfos: List[ArticleInfo]) -> None:
63 | # index = {}
64 | # for article in articleInfos:
65 | # for p in article.problems:
66 | # index[p.fid] = article
67 |
68 | render.render_readme(articleInfos)
69 |
70 |
71 | if __name__ == '__main__':
72 | filename = sys.argv[1]
73 | print(filename)
74 |
75 | with open(filename, 'r') as f:
76 | articles = yaml.load(f, Loader=yaml.Loader)
77 |
78 | articleInfos = [ArticleInfo(**article) for article in articles]
79 | build_table(articleInfos)
80 |
--------------------------------------------------------------------------------
/index.yaml:
--------------------------------------------------------------------------------
1 | - title: LeetCode 例题精讲 | 01 反转链表:如何轻松重构链表
2 | link: https://mp.weixin.qq.com/s/KTA6Ng1C33fydEn4VDj-7Q
3 | problems:
4 | - 206
5 | - title: LeetCode 例题精讲 | 02 Path Sum:二叉树的子问题划分
6 | link: https://mp.weixin.qq.com/s/uSjnfPPXTzScCRQBv6ew1Q
7 | problems:
8 | - 112
9 | - title: LeetCode 例题精讲 | 03 从二叉树遍历到回溯算法
10 | link: https://mp.weixin.qq.com/s/g5uvxi1lyxmWC4LtP0Bdlw
11 | problems:
12 | - 113
13 | - 78
14 | - title: LeetCode 例题精讲 | 04 用双指针解 Two Sum:缩减搜索空间
15 | link: https://mp.weixin.qq.com/s/Zqy2CAu7L8zw-g1N2v76SQ
16 | problems:
17 | - 167
18 | - 240
19 | - title: LeetCode 11. 盛最多水的容器
20 | link: https://mp.weixin.qq.com/s/RfTyqnIpLwJpRtzPWVZvHA
21 | problems:
22 | - 11
23 | - title: LeetCode 例题精讲 | 05 双指针×链表问题:快慢指针
24 | link: https://mp.weixin.qq.com/s/2CLloKhD8tbId1-9uOsNzw
25 | problems:
26 | - 876
27 | - 19
28 | - 141
29 | - title: 链表综合题 | LeetCode 148. 链表排序
30 | link: https://mp.weixin.qq.com/s/sg2qP5uBEp--bTOYdK_BMw
31 | problems:
32 | - 148
33 | - title: LeetCode 例题精讲 | 06 旋转数组问题:基本操作的威力
34 | link: https://mp.weixin.qq.com/s/S-wAKPu8OcI7FyrBkYBzQg
35 | problems:
36 | - 189
37 | - title: LeetCode 例题精讲 | 07 变位词问题:基本数据结构的威力
38 | link: https://mp.weixin.qq.com/s/aC8P2Yme35H49GzcoqhzLg
39 | problems:
40 | - 242
41 | - title: LeetCode 例题精讲 | 08 排列组合问题:回溯法的候选集合
42 | link: https://mp.weixin.qq.com/s/b6og5Ro4vx-3--qPpi22Mw
43 | problems:
44 | - 46
45 | - 77
46 | - title: LeetCode 例题精讲 | 09 排列组合问题再探:回溯法的去重策略
47 | link: https://mp.weixin.qq.com/s/h-dzViBTVWmkReA-dbufXA
48 | problems:
49 | - 90
50 | - 47
51 | - title: 一套代码解决 Combination Sum 系列问题(LeetCode 39/40/216)
52 | link: https://mp.weixin.qq.com/s/uLd8V-YB3Fy3ZNUcQHo8jw
53 | problems:
54 | - 39
55 | - 40
56 | - 216
57 | - title: LeetCode 例题精讲 | 10 二叉树直径:二叉树遍历中的全局变量
58 | link: https://mp.weixin.qq.com/s/ZDszP9ashAX6WgtVzhheaQ
59 | problems:
60 | - 543
61 | - 124
62 | - 110
63 | - 563
64 | - title: 二叉树问题太复杂?「三步走」方法解决它!
65 | link: https://mp.weixin.qq.com/s/rweTurnXKD5XY5bH2nqlPQ
66 | problems:
67 | - 1372
68 | - 1373
69 | - title: LeetCode 例题精讲 | 11 二叉树转化为链表:二叉树遍历中的相邻结点
70 | link: https://mp.weixin.qq.com/s/nzQmAOjKMj3ikHXeCUK1zg
71 | problems:
72 | - 98
73 | - 426
74 | - title: LeetCode 例题精讲 | 12 岛屿问题:网格结构中的 DFS
75 | link: https://mp.weixin.qq.com/s/1Xi6icqr6JiT8D0jTeamzg
76 | problems:
77 | - 463
78 | - 695
79 | - 827
80 | - title: LeetCode 例题精讲 | 13 BFS 的使用场景:层序遍历、最短路径问题
81 | link: https://mp.weixin.qq.com/s/j6Cjn1DgaMaN1Kwc9mF13Q
82 | problems:
83 | - 102
84 | - 1162
85 | - title: LeetCode 例题精讲 | 14 打家劫舍问题:动态规划的解题四步骤
86 | link: https://mp.weixin.qq.com/s/hSAID_hOPGy_DKleq3_DdA
87 | problems:
88 | - 198
89 | - title: LeetCode 例题精讲 | 15 最长公共子序列:二维动态规划的解法
90 | link: https://mp.weixin.qq.com/s/dHIeiIQWAeynmYSq9IdqJg
91 | problems:
92 | - 1143
93 | - title: 经典动态规划:编辑距离
94 | link: https://mp.weixin.qq.com/s/sJZw3ECrgpNItjdzd7g-dA
95 | problems:
96 | - 72
97 | - title: LeetCode 例题精讲 | 16 最大子数组和:子数组类问题的动态规划技巧
98 | link: https://mp.weixin.qq.com/s/e6L2tvWOS_D0obHR_360Gw
99 | problems:
100 | - 53
101 | - 718
102 | - title: LeetCode 例题精讲 | 17 动态规划如何拆分子问题,简化思路
103 | link: https://mp.weixin.qq.com/s/TE-p4WYQBBubhxmT137O9w
104 | problems:
105 | - 978
106 | - title: 一文教你股票买卖问题实用而装逼的解法
107 | link: https://mp.weixin.qq.com/s/CWGKl0Ctfc6wStcvBJsD3Q
108 | problems:
109 | - 123
110 | - title: 经典动态规划:「换硬币」系列三道问题详解
111 | link: https://mp.weixin.qq.com/s/pTMsIg9I0z102DQ4HMrYCA
112 | problems:
113 | - 322
114 | - 377
115 | - 518
116 | - title: LeetCode 例题精讲 | 18 前缀和:空间换时间的技巧
117 | link: https://mp.weixin.qq.com/s/lg4tZUfGcXoKq1jOQtpKJw
118 | problems:
119 | - 303
120 | - 724
121 | - 560
122 | - title: 时间复杂度分析快速入门:题型分类法
123 | link: https://mp.weixin.qq.com/s/Rzdz_dwS_4eOoX7XkFIALQ
124 | problems:
--------------------------------------------------------------------------------
/leetcode/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nettee/little-algorithm/0104bf3c13409e935256b186bf91cba17dc4ede3/leetcode/__init__.py
--------------------------------------------------------------------------------
/leetcode/graphql.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 |
4 | api_url = 'https://leetcode-cn.com/graphql'
5 | problem_url = 'https://leetcode-cn.com/problems/two-sum/description/'
6 |
7 |
8 | class GraphQLError(RuntimeError):
9 | pass
10 |
11 |
12 | def execute_graphql(url, payload, headers):
13 | r = requests.post(url, json=payload, headers=headers)
14 | json = r.json()
15 | if 'errors' in json:
16 | errors = json['errors']
17 | messages = [error['message'] for error in errors]
18 | raise GraphQLError(messages)
19 | return json['data']
20 |
21 |
22 | def query_problem_data(query: str, title_slug: str):
23 | payload = {
24 | "operationName": "questionData",
25 | "variables": {
26 | "titleSlug": title_slug,
27 | },
28 | "query": query,
29 | }
30 |
31 | headers = {
32 | 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
33 | 'referer': problem_url,
34 | 'content-type': "application/json",
35 | }
36 |
37 | return execute_graphql(api_url, payload=payload, headers=headers)
38 |
39 |
40 | def query_translated_title_by_slug(title_slug: str) -> str:
41 | query = '''query questionData($titleSlug: String!) {
42 | question(titleSlug: $titleSlug) {
43 | translatedTitle
44 | }
45 | }
46 | '''
47 |
48 | data = query_problem_data(query, title_slug)
49 | return data['question']['translatedTitle']
50 |
51 |
52 | if __name__ == '__main__':
53 | translated_title = query_translated_title_by_slug('two-sum')
54 | print(translated_title)
--------------------------------------------------------------------------------
/leetcode/problems.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass, field
2 |
3 | import requests
4 | import typing
5 |
6 |
7 | @dataclass(repr=False)
8 | class Difficulty:
9 | level: int
10 |
11 | def __repr__(self) -> str:
12 | if self.level == 1:
13 | return 'Easy'
14 | elif self.level == 2:
15 | return 'Medium'
16 | elif self.level == 3:
17 | return 'Hard'
18 | else:
19 | return 'Unknown'
20 |
21 |
22 | @dataclass
23 | class ProblemStat:
24 | question_id: int
25 | frontend_question_id: str
26 | question__title: str
27 | question__title_slug: str
28 | question__hide: bool = field(repr=False)
29 | total_acs: int = field(repr=False)
30 | total_submitted: int = field(repr=False)
31 | total_column_articles: int = field(repr=False)
32 | is_new_question: bool = field(repr=False)
33 |
34 |
35 | @dataclass
36 | class Problem:
37 | stat: ProblemStat
38 | difficulty: Difficulty
39 | paid_only: bool = field(repr=False)
40 | status: typing.Any = field(repr=False)
41 | is_favor: bool = field(repr=False)
42 | frequency: int = field(repr=False)
43 | progress: int = field(repr=False)
44 |
45 | def __post_init__(self) -> None:
46 | self.stat = ProblemStat(**self.stat)
47 | self.difficulty = Difficulty(**self.difficulty)
48 |
49 | @property
50 | def iid(self) -> int:
51 | return self.stat.question_id
52 |
53 | @property
54 | def fid(self) -> str:
55 | return self.stat.frontend_question_id
56 |
57 | @property
58 | def slug(self) -> str:
59 | return self.stat.question__title_slug
60 |
61 | @property
62 | def title(self) -> str:
63 | return self.stat.question__title
64 |
65 | @property
66 | def url(self) -> str:
67 | return 'https://leetcode-cn.com/problems/' + self.stat.question__title_slug
68 |
69 |
70 | api = 'https://leetcode-cn.com/api/problems/all/'
71 |
72 | problems = None
73 |
74 |
75 | def fetch_problems() -> None:
76 | global problems
77 | problems = {}
78 | r = requests.get(api)
79 | data = r.json()
80 | for p in data['stat_status_pairs']:
81 | problem = Problem(**p)
82 | problems[problem.fid] = problem
83 |
84 |
85 | def query_by_id(fid: str) -> Problem:
86 | if problems is None:
87 | fetch_problems()
88 | return problems[fid]
89 |
--------------------------------------------------------------------------------
/little/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nettee/little-algorithm/0104bf3c13409e935256b186bf91cba17dc4ede3/little/__init__.py
--------------------------------------------------------------------------------
/little/model.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from pathlib import Path
3 | from typing import List
4 |
5 |
6 | @dataclass
7 | class Solution:
8 | path: Path
9 | lang: str = 'Java'
10 |
11 | def file_name(self) -> str:
12 | return self.path.name
13 |
14 | def uri(self) -> str:
15 | return str(self.path)
16 |
17 | def md_piece(self) -> str:
18 | text = self.file_name()
19 | uri = str(self.path)
20 | return f'[{text}]({uri})'
21 |
22 |
23 | @dataclass
24 | class SolutionList:
25 | solutions: List[Solution]
26 |
27 | def md_piece(self) -> str:
28 | if len(self.solutions) == 0:
29 | return ''
30 | elif len(self.solutions) == 1:
31 | solution = self.solutions[0]
32 | return f'[{solution.lang}]({solution.uri()})'
33 | else:
34 | # TODO assert solutions are all written in Java
35 | lang = self.solutions[0].lang
36 | parts = ', '.join(f'[{i+1}]({s.uri()})' for (i, s) in enumerate(self.solutions))
37 | return f'{lang}({parts})'
38 |
39 |
--------------------------------------------------------------------------------
/little/render.py:
--------------------------------------------------------------------------------
1 | from typing import List
2 |
3 | from jinja2 import Environment, FileSystemLoader
4 |
5 | from index import ArticleInfo
6 |
7 |
8 | def render_readme(article_infos: List[ArticleInfo]) -> None:
9 | items = []
10 | for article in article_infos:
11 | for problem in article.problems:
12 | items.append((problem.fid, problem, article))
13 |
14 | items.sort(key=lambda item: '{:>6}'.format(item[0]))
15 |
16 | env = Environment(loader=FileSystemLoader('/Users/william/projects/little-algorithm/little/templates'))
17 | template = env.get_template('README.md')
18 | rendered = template.render(items=items)
19 |
20 | with open('README.md', 'w') as f:
21 | print(rendered, file=f)
22 |
23 |
--------------------------------------------------------------------------------
/little/solution.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 | from typing import List
3 |
4 | from little.model import Solution, SolutionList
5 |
6 |
7 | def find_solutions(fid: str) -> SolutionList:
8 | dir_name = fid.zfill(4)
9 |
10 | # TODO assert calling from project root
11 | project_path = Path('.')
12 | solution_path = project_path / 'solutions' / dir_name
13 | if not solution_path.exists():
14 | print(f'Warning: path for problem {fid} not exists -- No such dir: {solution_path.absolute()}')
15 | return SolutionList(solutions=list())
16 | solution_files = list(solution_path.iterdir())
17 | if len(solution_files) == 0:
18 | print(f'Warning: no solutions found for problem {fid} -- No files in dir: {solution_path.absolute()}')
19 | return SolutionList(solutions=list())
20 | return SolutionList(solutions=[Solution(path=path) for path in solution_files])
21 |
--------------------------------------------------------------------------------
/little/templates/README.md:
--------------------------------------------------------------------------------
1 | # Little Algorithm
2 |
3 | 从 2020 年初开始,我在公众号《面向大象编程》上发表面试算法、LeetCode 题解相关文章,至今收获不少好评。此仓库是公众号内容的补充,包括公众号文章涉及到的题目的参考代码,以及 LeetCode 题目到文章链接的索引。
4 |
5 | ## 如何使用本仓库
6 |
7 | 1、关注我的公众号 **面向大象编程** 获取文章更新。我的公众号坚持原创更新,干货分享,绝对是值得关注的技术公众号。
8 |
9 | 2、公众号文章目前绝大部分都是拿 LeetCode 原题作为例题,讲解算法题解题思路。从下方「参考代码」部分的表格中找到你喜欢的 LeetCode 题目,即可找到对应的参考代码以及讲解文章链接。
10 |
11 | ## 参考代码
12 |
13 | | 题号 | 题目名 | 题解代码 | 对应文章 |
14 | | :-: | --- | --- | --- |
15 | {% for item in items %}| [{{ item[1].fid }}]({{ item[1].url }}) | {{ item[1].title }}
{{ item[1].translated_title }} | {{ item[1].solutions.md_piece() }} | {{ item[2].md_piece() }} |
16 | {% endfor %}
17 |
18 | ## 公众号文章整理
19 |
20 | 可关注公众号《面向大象编程》,在公众号菜单中有文章目录。
--------------------------------------------------------------------------------
/solutions/0001/1.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nettee/little-algorithm/0104bf3c13409e935256b186bf91cba17dc4ede3/solutions/0001/1.java
--------------------------------------------------------------------------------
/solutions/0011/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int maxArea(int[] height) {
3 | int res = 0;
4 | int i = 0;
5 | int j = height.length - 1;
6 | while (i < j) {
7 | int area = (j - i) * Math.min(height[i], height[j]);
8 | res = Math.max(res, area);
9 | if (height[i] < height[j]) {
10 | i++;
11 | } else {
12 | j--;
13 | }
14 | }
15 | return res;
16 | }
17 | }
--------------------------------------------------------------------------------
/solutions/0019/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public ListNode removeNthFromEnd(ListNode head, int k) {
3 | // 将 fast 前进 k 个元素
4 | ListNode fast = head;
5 | for (int i = 0; i < k; i++) {
6 | // 这里省略了检测空指针的代码
7 | fast = fast.next;
8 | }
9 | // fast 和 slow 指针间隔 k 个同时前进
10 | // 这里使用了链表遍历框架,将 slow 指针变成两个指针 curr 和 prev
11 | ListNode curr = head;
12 | ListNode prev = null;
13 | while (fast != null) {
14 | prev = curr;
15 | curr = curr.next;
16 | fast = fast.next;
17 | }
18 | if (prev == null) {
19 | head = curr.next;
20 | } else {
21 | prev.next = curr.next;
22 | }
23 | return head;
24 | }
25 | }
--------------------------------------------------------------------------------
/solutions/0039/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public List> combinationSum(int[] candidates, int target) {
3 | Deque current = new ArrayDeque<>();
4 | List> res = new ArrayList<>();
5 | backtrack(candidates, 0, target, current, res);
6 | return res;
7 | }
8 |
9 | // 候选集合 candidates[m..N)
10 | void backtrack(int[] candidates, int m, int target, Deque current, List> res) {
11 | if (target < 0) {
12 | return;
13 | } else if (target == 0) {
14 | res.add(new ArrayList<>(current));
15 | return;
16 | }
17 |
18 | for (int i = m; i < candidates.length; i++) {
19 | // 选择数字 candidates[i]
20 | current.addLast(candidates[i]);
21 | // 代码调整处:递归调用参数
22 | // 递归调用传递 i 而不是原先的 i+1
23 | // 这样 candidates[i] 选完后仍然在候选集合里,后续仍然可以再选
24 | backtrack(candidates, i, target - candidates[i], current, res);
25 | // 撤销选择
26 | current.removeLast();
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/solutions/0040/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public List> combinationSum2(int[] candidates, int target) {
3 | Arrays.sort(candidates);
4 | Deque current = new ArrayDeque<>();
5 | List> res = new ArrayList<>();
6 | backtrack(candidates, 0, target, current, res);
7 | return res;
8 | }
9 |
10 | // 候选集合 candidates[m..N)
11 | void backtrack(int[] candidates, int m, int target, Deque current, List> res) {
12 | if (target < 0) {
13 | return;
14 | } else if (target == 0) {
15 | res.add(new ArrayList<>(current));
16 | }
17 |
18 | for (int i = m; i < candidates.length; i++) {
19 | // 代码调整处:候选集合遍历
20 | if (i > m && candidates[i] == candidates[i-1]) {
21 | // 如果 candidates[i] 与前一个元素相等,说明不是相等元素中的第一个,跳过。
22 | continue;
23 | }
24 | // 选择数字 candidates[i]
25 | current.addLast(candidates[i]);
26 | // 元素 candidates[m..i) 均失效
27 | backtrack(candidates, i+1, target - candidates[i], current, res);
28 | // 撤销选择
29 | current.removeLast();
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/solutions/0046/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public List> permute(int[] nums) {
3 | List current = new ArrayList<>();
4 | for (int n : nums) {
5 | current.add(n);
6 | }
7 | List> res = new ArrayList<>();
8 | backtrack(current, 0, res);
9 | return res;
10 | }
11 |
12 | // current[0..k) 是已选集合, current[k..N) 是候选集合
13 | void backtrack(List current, int k, List> res) {
14 | if (k == current.size()) {
15 | res.add(new ArrayList<>(current));
16 | return;
17 | }
18 | // 从候选集合中选择
19 | for (int i = k; i < current.size(); i++) {
20 | // 选择数字 current[i]
21 | Collections.swap(current, k, i);
22 | // 将 k 加一
23 | backtrack(current, k+1, res);
24 | // 撤销选择
25 | Collections.swap(current, k, i);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/solutions/0047/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public List> permuteUnique(int[] nums) {
3 | List current = new ArrayList<>();
4 | for (int n : nums) {
5 | current.add(n);
6 | }
7 | List> res = new ArrayList<>();
8 | backtrack(current, 0, res);
9 | return res;
10 | }
11 |
12 | // 已选集合 current[0..m),候选集合 current[m..N)
13 | void backtrack(List current, int m, List> res) {
14 | if (m == current.size()) {
15 | res.add(new ArrayList<>(current));
16 | return;
17 | }
18 |
19 | // 使用 set 辅助判断相等的候选元素是否已经出现过
20 | Set seen = new HashSet<>();
21 | for (int i = m; i < current.size(); i++) {
22 | int e = current.get(i);
23 | if (seen.contains(e)) {
24 | // 如果已经出现过相等的元素,则不选此元素
25 | continue;
26 | }
27 | seen.add(e);
28 | Collections.swap(current, m, i);
29 | backtrack(current, m+1, res);
30 | Collections.swap(current, m, i);
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/solutions/0053/1.java:
--------------------------------------------------------------------------------
1 | // 解法1:暴力法(会超时)
2 | class Solution {
3 | public int maxSubArray(int[] nums) {
4 | int n = nums.length;
5 | int res = Integer.MIN_VALUE;
6 | // 穷举各种可能的子数组 nums[i..j]
7 | for (int i = 0; i < n; i++) {
8 | for (int j = i; j < n; j++) {
9 | // 计算子数组 nums[i..j] 的和
10 | int sum = 0;
11 | for (int k = i; k <= j; k++) {
12 | sum += nums[k];
13 | }
14 | res = Math.max(res, sum);
15 | }
16 | }
17 | return res;
18 | }
19 | }
--------------------------------------------------------------------------------
/solutions/0053/2.java:
--------------------------------------------------------------------------------
1 | // 解法2:暴力法的改进
2 | class Solution {
3 | public int maxSubArray(int[] nums) {
4 | int n = nums.length;
5 | int res = Integer.MIN_VALUE;
6 | for (int i = 0; i < n; i++) {
7 | int sum = 0;
8 | for (int j = i; j < n; j++) {
9 | sum += nums[j];
10 | res = Math.max(res, sum);
11 | }
12 | }
13 | return res;
14 | }
15 | }
--------------------------------------------------------------------------------
/solutions/0053/3.java:
--------------------------------------------------------------------------------
1 | // 解法3:分治法
2 | class Solution {
3 | public int maxSubArray(int[] nums) {
4 | return maxSubArray(nums, 0, nums.length - 1);
5 | }
6 |
7 | // 计算 nums[lo..hi] 的最大子数组和
8 | // lo 表示 low,hi 表示 high
9 | private int maxSubArray(int[] nums, int lo, int hi) {
10 | if (hi < lo) {
11 | return Integer.MIN_VALUE;
12 | } else if (hi == lo) {
13 | return nums[lo];
14 | }
15 |
16 | int mid = lo + (hi - lo) / 2;
17 | int max_left = maxSubArray(nums, lo, mid);
18 | int max_right = maxSubArray(nums, mid+1, hi);
19 | int max_mid = maxMidSubArray(nums, lo, mid, hi);
20 | return Math.max(max_left, Math.max(max_mid, max_right));
21 | }
22 |
23 | private int maxMidSubArray(int[] nums, int lo, int mid, int hi) {
24 | int max_mid_left = 0;
25 | if (mid >= lo) {
26 | max_mid_left = nums[mid];
27 | int sum = 0;
28 | for (int i = mid; i >= lo; i--) {
29 | sum += nums[i];
30 | max_mid_left = Math.max(max_mid_left, sum);
31 | }
32 | }
33 | int max_mid_right = 0;
34 | if (mid + 1 <= hi) {
35 | max_mid_right = nums[mid+1];
36 | int sum = 0;
37 | for (int i = mid + 1; i <= hi; i++) {
38 | sum += nums[i];
39 | max_mid_right = Math.max(max_mid_right, sum);
40 | }
41 | }
42 | return max_mid_left + max_mid_right;
43 | }
44 | }
--------------------------------------------------------------------------------
/solutions/0053/4.java:
--------------------------------------------------------------------------------
1 | // 解法4:动态规划
2 | class Solution {
3 | public int maxSubArray(int[] nums) {
4 | // 子问题:
5 | // f(k) = nums[0..k) 中以 nums[k-1] 结尾的最大子数组和
6 | // 原问题 = max{ f(k) }, 0 <= k <= N
7 |
8 | // f(0) = 0
9 | // f(k) = max{ f(k-1), 0 } + nums[k-1]
10 |
11 | int N = nums.length;
12 | int[] dp = new int[N+1];
13 | dp[0] = 0;
14 |
15 | int res = Integer.MIN_VALUE;
16 | for (int k = 1; k <= N; k++) {
17 | dp[k] = Math.max(dp[k-1], 0) + nums[k-1];
18 | res = Math.max(res, dp[k]);
19 | }
20 | return res;
21 | }
22 | }
--------------------------------------------------------------------------------
/solutions/0053/5.java:
--------------------------------------------------------------------------------
1 | // 解法5:贪心法
2 | class Solution {
3 | public int maxSubArray(int[] nums) {
4 | int sum = 0; // 计算当前的部分子数组和
5 | int res = Integer.MIN_VALUE;
6 | for (int n : nums) {
7 | // 如果部分和小于零,直接舍弃,从零开始重新累加
8 | if (sum < 0) {
9 | sum = 0;
10 | }
11 | sum += n; // 加上当前元素
12 | res = Math.max(res, sum);
13 | }
14 | return res;
15 | }
16 | }
--------------------------------------------------------------------------------
/solutions/0072/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int minDistance(String s, String t) {
3 | // 子问题:
4 | // f(i, j) = s[0..i) 和 t[0..j) 的编辑距离
5 |
6 | // f(0, j) = j
7 | // f(i, 0) = i
8 | // f(i, j) = f(i-1, j-1), if s[i-1] == t[j-1]
9 | // max: f(i-1, j) + 1
10 | // f(i, j-1) + 1
11 | // f(i-1, j-1) + 1, if s[i-1] != t[j-1]
12 |
13 | int m = s.length();
14 | int n = t.length();
15 | int[][] dp = new int[m+1][n+1];
16 | for (int i = 0; i <= m; i++) {
17 | for (int j = 0; j <= n; j++) {
18 | if (i == 0) {
19 | dp[i][j] = j;
20 | } else if (j == 0) {
21 | dp[i][j] = i;
22 | } else {
23 | if (s.charAt(i-1) == t.charAt(j-1)) {
24 | dp[i][j] = dp[i-1][j-1];
25 | } else {
26 | dp[i][j] = 1 + min3(
27 | dp[i-1][j], // 删除操作
28 | dp[i][j-1], // 插入操作
29 | dp[i-1][j-1] // 替换操作
30 | );
31 | }
32 | }
33 | }
34 | }
35 | return dp[m][n];
36 | }
37 |
38 | private int min3(int x, int y, int z) {
39 | return Math.min(x, Math.min(y, z));
40 | }
41 | }
--------------------------------------------------------------------------------
/solutions/0078/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public List> subsets(int[] nums) {
3 | Deque current = new ArrayDeque<>(nums.length);
4 | List> res = new ArrayList<>();
5 | backtrack(nums, 0, current, res);
6 | return res;
7 | }
8 |
9 | void backtrack(int[] nums, int k, Deque current, List> res) {
10 | if (k == nums.length) {
11 | res.add(new ArrayList<>(current));
12 | return;
13 | }
14 |
15 | // 不选择第 k 个元素
16 | backtrack(nums, k+1, current, res);
17 |
18 | // 选择第 k 个元素
19 | current.addLast(nums[k]);
20 | backtrack(nums, k+1, current, res);
21 | current.removeLast();
22 | }
23 | }
--------------------------------------------------------------------------------
/solutions/0090/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public List> subsetsWithDup(int[] nums) {
3 | // 对元素排序,保证相等的元素相邻
4 | Arrays.sort(nums);
5 | Deque current = new ArrayDeque<>(nums.length);
6 | List> res = new ArrayList<>();
7 | backtrack(nums, 0, current, res);
8 | return res;
9 | }
10 |
11 | // 候选集合: nums[k..N)
12 | void backtrack(int[] nums, int k, Deque current, List> res) {
13 | if (k == nums.length) {
14 | res.add(new ArrayList<>(current));
15 | return;
16 | }
17 |
18 | // 选择 nums[k]
19 | current.addLast(nums[k]);
20 | backtrack(nums, k+1, current, res);
21 | current.removeLast();
22 |
23 | // 不选择 nums[k]
24 | // 将后续和 nums[k] 相等的元素 nums[k..j) 都从候选集合中删除
25 | int j = k;
26 | while (j < nums.length && nums[j] == nums[k]) {
27 | j++;
28 | }
29 | backtrack(nums, j, current, res);
30 | }
31 | }
--------------------------------------------------------------------------------
/solutions/0098/1.java:
--------------------------------------------------------------------------------
1 | TreeNode prev; // 全局变量:指向中序遍历的上一个结点
2 | boolean valid;
3 |
4 | public boolean isValidBST(TreeNode root) {
5 | valid = true;
6 | prev = null;
7 | traverse(root);
8 | return valid;
9 | }
10 |
11 | void traverse(TreeNode curr) {
12 | if (curr == null) {
13 | return;
14 | }
15 |
16 | traverse(curr.left);
17 |
18 | // 中序遍历的写法,把操作写在两个递归调用中间
19 | if (prev != null && prev.val >= curr.val) {
20 | // 如果中序遍历的相邻两个结点大小关系不对,则二叉搜索树不合法
21 | valid = false;
22 | }
23 | // 维护 prev 指针
24 | prev = curr;
25 |
26 | traverse(curr.right);
27 | }
--------------------------------------------------------------------------------
/solutions/0102/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public List> levelOrder(TreeNode root) {
3 | List> res = new ArrayList<>();
4 |
5 | Queue queue = new ArrayDeque<>();
6 | if (root != null) {
7 | queue.add(root);
8 | }
9 | while (!queue.isEmpty()) {
10 | int n = queue.size();
11 | List level = new ArrayList<>();
12 | for (int i = 0; i < n; i++) {
13 | TreeNode node = queue.poll();
14 | level.add(node.val);
15 | if (node.left != null) {
16 | queue.add(node.left);
17 | }
18 | if (node.right != null) {
19 | queue.add(node.right);
20 | }
21 | }
22 | res.add(level);
23 | }
24 |
25 | return res;
26 | }
27 | }
--------------------------------------------------------------------------------
/solutions/0110/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | boolean balanced;
3 |
4 | public boolean isBalanced(TreeNode root) {
5 | balanced = true;
6 | traverse(root);
7 | return balanced;
8 | }
9 |
10 | // 返回树的高度
11 | int traverse(TreeNode root) {
12 | if (root == null) {
13 | return 0;
14 | }
15 | int left = traverse(root.left);
16 | int right = traverse(root.right);
17 | // 判断当前子树是否平衡,修改全局变量
18 | if (Math.abs(left - right) > 1) {
19 | balanced = false;
20 | }
21 | return 1 + Math.max(left, right);
22 | }
23 | }
--------------------------------------------------------------------------------
/solutions/0112/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | boolean hasPathSum(TreeNode root, int sum) {
3 | if (root == null) {
4 | return false;
5 | }
6 | if (root.left == null && root.right == null) {
7 | return root.val == sum;
8 | }
9 | int target = sum - root.val;
10 | return hasPathSum(root.left, target)
11 | || hasPathSum(root.right, target);
12 | }
13 | }
--------------------------------------------------------------------------------
/solutions/0113/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public List> pathSum(TreeNode root, int sum) {
3 | List> res = new ArrayList<>();
4 | Deque path = new ArrayDeque<>();
5 | traverse(root, sum, path, res);
6 | return res;
7 | }
8 |
9 | void traverse(TreeNode root, int sum, Deque path, List> res) {
10 | if (root == null) {
11 | return;
12 | }
13 | path.addLast(root.val);
14 | if (root.left == null && root.right == null) {
15 | if (root.val == sum) {
16 | res.add(new ArrayList<>(path));
17 | }
18 | }
19 | int target = sum - root.val;
20 | traverse(root.left, target, path, res);
21 | traverse(root.right, target, path, res);
22 | path.removeLast();
23 | }
24 | }
--------------------------------------------------------------------------------
/solutions/0123/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int maxProfit(int[] prices) {
3 | if (prices.length == 0) {
4 | return 0;
5 | }
6 |
7 | int s1 = Integer.MIN_VALUE;
8 | int s2 = 0;
9 | int s3 = Integer.MIN_VALUE;
10 | int s4 = 0;
11 | for (int p : prices) {
12 | s4 = Math.max(s4, s3 + p);
13 | s3 = Math.max(s3, s2 - p);
14 | s2 = Math.max(s2, s1 + p);
15 | s1 = Math.max(s1, -p);
16 | }
17 | return Math.max(0, Math.max(s2, s4));
18 | }
19 | }
--------------------------------------------------------------------------------
/solutions/0124/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | int res;
3 |
4 | public int maxPathSum(TreeNode root) {
5 | res = Integer.MIN_VALUE;
6 | traverse(root);
7 | return res;
8 | }
9 |
10 | // return max root path sum
11 | int traverse(TreeNode root) {
12 | if (root == null) {
13 | return 0;
14 | }
15 |
16 | int left = traverse(root.left);
17 | int right = traverse(root.right);
18 | int maxPathSum = root.val + Math.max(0, left) + Math.max(0, right);
19 | res = Math.max(res, maxPathSum);
20 | return root.val + Math.max(0, Math.max(left, right));
21 | }
22 | }
--------------------------------------------------------------------------------
/solutions/0141/1.java:
--------------------------------------------------------------------------------
1 | public class Solution {
2 | public boolean hasCycle(ListNode head) {
3 | ListNode fast = head;
4 | ListNode slow = head;
5 | while (fast != null && fast.next != null) {
6 | fast = fast.next.next;
7 | slow = slow.next;
8 | // fast 和 slow 指向同一个结点,说明存在“套圈”
9 | if (fast == slow) {
10 | return true;
11 | }
12 | }
13 | // fast 到达链表尾部,则不存在环
14 | return false;
15 | }
16 | }
--------------------------------------------------------------------------------
/solutions/0148/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public ListNode sortList(ListNode head) {
3 | if (head == null || head.next == null) {
4 | return head;
5 | }
6 | ListNode mid = split(head);
7 | ListNode left = sortList(head);
8 | ListNode right = sortList(mid);
9 | return merge(left, right);
10 | }
11 |
12 | ListNode split(ListNode head) {
13 | ListNode fast = head;
14 | ListNode slow = head;
15 | ListNode prev = null;
16 | while (fast != null && fast.next != null) {
17 | fast = fast.next.next;
18 | prev = slow;
19 | slow = slow.next;
20 | }
21 | prev.next = null;
22 | return slow;
23 | }
24 |
25 | ListNode head;
26 | ListNode tail;
27 |
28 | ListNode merge(ListNode left, ListNode right) {
29 | head = null;
30 | tail = null;
31 | ListNode q1 = left;
32 | ListNode q2 = right;
33 | while (q1 != null || q2 != null) {
34 | if (q1 == null) {
35 | append(q2);
36 | q2 = q2.next;
37 | } else if (q2 == null) {
38 | append(q1);
39 | q1 = q1.next;
40 | } else if (q1.val < q2.val) {
41 | append(q1);
42 | q1 = q1.next;
43 | } else {
44 | append(q2);
45 | q2 = q2.next;
46 | }
47 | }
48 | return head;
49 | }
50 |
51 | void append(ListNode node) {
52 | if (head == null) {
53 | head = node;
54 | tail = node;
55 | } else {
56 | tail.next = node;
57 | tail = node;
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/solutions/0167/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int[] twoSum(int[] nums, int target) {
3 | int i = 0;
4 | int j = nums.length - 1;
5 | while (i < j) {
6 | int sum = nums[i] + nums[j];
7 | if (sum < target) {
8 | i++;
9 | } else if (sum > target) {
10 | j--;
11 | } else {
12 | return new int[]{i+1, j+1};
13 | }
14 | }
15 | return new int[]{-1, -1};
16 | }
17 | }
--------------------------------------------------------------------------------
/solutions/0189/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public void rotate(int[] nums, int k) {
3 | int N = nums.length;
4 | k %= N;
5 | reverse(nums, 0, N);
6 | reverse(nums, 0, k);
7 | reverse(nums, k, N);
8 | }
9 |
10 | void reverse(int[] nums, int begin, int end) {
11 | for (int i = begin, j = end - 1; i < j; i++, j--) {
12 | int temp = nums[i];
13 | nums[i] = nums[j];
14 | nums[j] = temp;
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/solutions/0198/1.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nettee/little-algorithm/0104bf3c13409e935256b186bf91cba17dc4ede3/solutions/0198/1.java
--------------------------------------------------------------------------------
/solutions/0206/1.cpp:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public:
3 | ListNode* reverseList(ListNode* head) {
4 | ListNode* curr = head;
5 | ListNode* prev = nullptr;
6 |
7 | while (curr != nullptr) {
8 | ListNode* cnext = curr->next;
9 | if (prev == nullptr) {
10 | curr->next = nullptr;
11 | } else {
12 | curr->next = prev;
13 | }
14 |
15 | prev = curr;
16 | curr = cnext;
17 | }
18 |
19 | return prev;
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/solutions/0206/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public ListNode reverseList(ListNode head) {
3 | ListNode prev = null;
4 | ListNode curr = head;
5 | while (curr != null) {
6 | ListNode cnext = curr.next;
7 | if (prev == null) {
8 | curr.next = null;
9 | } else {
10 | curr.next = prev;
11 | }
12 | prev = curr;
13 | curr = cnext;
14 | }
15 | return prev;
16 | }
17 | }
--------------------------------------------------------------------------------
/solutions/0216/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public List> combinationSum3(int k, int n) {
3 | Deque current = new ArrayDeque<>();
4 | List> res = new ArrayList<>();
5 | backtrack(k, 1, n, current, res);
6 | return res;
7 | }
8 |
9 | // 候选集合:整数 [m..9]
10 | // 代码调整处:加入参数 k
11 | void backtrack(int k, int m, int target, Deque current, List> res) {
12 | if (target < 0) {
13 | return;
14 | } else if (target == 0) {
15 | // 代码调整处:已选集合达到 k 个元素才收集结果
16 | if (current.size() == k) {
17 | res.add(new ArrayList<>(current));
18 | }
19 | return;
20 | }
21 | if (current.size() > k) {
22 | return;
23 | }
24 |
25 | // 从候选集合中选择
26 | for (int i = m; i <= 9; i++) {
27 | // 选择数字 i
28 | current.addLast(i);
29 | // 数字 [m..i) 均失效
30 | backtrack(k, i+1, target - i, current, res);
31 | // 撤销选择
32 | current.removeLast();
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/solutions/0240/1.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nettee/little-algorithm/0104bf3c13409e935256b186bf91cba17dc4ede3/solutions/0240/1.java
--------------------------------------------------------------------------------
/solutions/0242/1.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nettee/little-algorithm/0104bf3c13409e935256b186bf91cba17dc4ede3/solutions/0242/1.java
--------------------------------------------------------------------------------
/solutions/0303/1.java:
--------------------------------------------------------------------------------
1 | class NumArray {
2 |
3 | private int[] preSum;
4 |
5 | // 预处理阶段
6 | public NumArray(int[] nums) {
7 | int n = nums.length;
8 | // 计算前缀和数组
9 | preSum = new int[n+1];
10 | preSum[0] = 0;
11 | for (int i = 0; i < n; i++) {
12 | preSum[i+1] = preSum[i] + nums[i];
13 | }
14 | }
15 |
16 | public int sumRange(int i, int j) {
17 | return preSum[j+1] - preSum[i];
18 | }
19 | }
--------------------------------------------------------------------------------
/solutions/0322/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int coinChange(int[] coins, int amount) {
3 | // 子问题:
4 | // f(k) = 凑出金额 k 的最小硬币数
5 |
6 | // f(k) = min{ 1 + f(k - c) }
7 | // f(0) = 0
8 | int[] dp = new int[amount+1];
9 | Arrays.fill(dp, amount + 1); // DP 数组初始化为正无穷大
10 | dp[0] = 0;
11 | for (int k = 1; k <= amount; k++) {
12 | for (int c : coins) {
13 | if (k >= c) {
14 | dp[k] = Math.min(dp[k], 1 + dp[k-c]);
15 | }
16 | }
17 | }
18 | // 如果 dp[amount] > amount,认为是无效元素。
19 | if (dp[amount] > amount) {
20 | return -1;
21 | } else {
22 | return dp[amount];
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/solutions/0377/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int combinationSum4(int[] nums, int target) {
3 | int[] dp = new int[target+1]; // 默认初始化为 0
4 | dp[0] = 1; // 注意 base case
5 | for (int k = 1; k <= target; k++) {
6 | for (int n : nums) {
7 | if (k >= n) {
8 | dp[k] += dp[k-n];
9 | }
10 | }
11 | }
12 | return dp[target];
13 | }
14 | }
--------------------------------------------------------------------------------
/solutions/0426/1.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nettee/little-algorithm/0104bf3c13409e935256b186bf91cba17dc4ede3/solutions/0426/1.java
--------------------------------------------------------------------------------
/solutions/0463/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int islandPerimeter(int[][] grid) {
3 | for (int r = 0; r < grid.length; r++) {
4 | for (int c = 0; c < grid[0].length; c++) {
5 | if (grid[r][c] == 1) {
6 | // 题目限制只有一个岛屿,计算一个即可
7 | return dfs(grid, r, c);
8 | }
9 | }
10 | }
11 | return 0;
12 | }
13 |
14 | int dfs(int[][] grid, int r, int c) {
15 | // 函数因为「坐标 (r, c) 超出网格范围」返回,对应一条黄色的边
16 | if (!inArea(grid, r, c)) {
17 | return 1;
18 | }
19 | // 函数因为「当前格子是海洋格子」返回,对应一条蓝色的边
20 | if (grid[r][c] == 0) {
21 | return 1;
22 | }
23 | // 函数因为「当前格子是已遍历的陆地格子」返回,和周长没关系
24 | if (grid[r][c] != 1) {
25 | return 0;
26 | }
27 | grid[r][c] = 2;
28 | return dfs(grid, r - 1, c)
29 | + dfs(grid, r + 1, c)
30 | + dfs(grid, r, c - 1)
31 | + dfs(grid, r, c + 1);
32 | }
33 |
34 | // 判断坐标 (r, c) 是否在网格中
35 | boolean inArea(int[][] grid, int r, int c) {
36 | return 0 <= r && r < grid.length
37 | && 0 <= c && c < grid[0].length;
38 | }
39 | }
--------------------------------------------------------------------------------
/solutions/0518/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int change(int amount, int[] coins) {
3 | int m = coins.length;
4 | int[][] dp = new int[m+1][amount+1];
5 |
6 | for (int i = 0; i <= m; i++) {
7 | for (int k = 0; k <= amount; k++) {
8 | if (k == 0) {
9 | dp[i][k] = 1; // base case
10 | } else if (i == 0) {
11 | dp[i][k] = 0; // base case
12 | } else {
13 | dp[i][k] = dp[i-1][k];
14 | if (k >= coins[i-1]) {
15 | dp[i][k] += dp[i][k-coins[i-1]];
16 | }
17 | }
18 | }
19 | }
20 | return dp[m][amount];
21 | }
22 | }
--------------------------------------------------------------------------------
/solutions/0543/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | int diameter;
3 |
4 | public int diameterOfBinaryTree(TreeNode root) {
5 | diameter = 0;
6 | traverse(root);
7 | return diameter;
8 | }
9 |
10 | // 返回树的深度
11 | int traverse(TreeNode root) {
12 | if (root == null) {
13 | return 0;
14 | }
15 |
16 | int left = traverse(root.left); // 左子树的深度
17 | int right = traverse(root.right); // 右子树的深度
18 | // 直接访问全局变量
19 | diameter = Math.max(diameter, left + right);
20 | return 1 + Math.max(left, right);
21 | }
22 | }
--------------------------------------------------------------------------------
/solutions/0560/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int subarraySum(int[] nums, int k) {
3 | // 前缀和 -> 该前缀和(的值)出现的次数
4 | Map presum = new HashMap<>();
5 | // base case,前缀和 0 出现 1 次
6 | presum.put(0, 1);
7 |
8 | int sum = 0; // 前缀和
9 | int res = 0;
10 | for (int n : nums) {
11 | sum += n; // 计算前缀和
12 | // 查找有多少个 sum[i] 等于 sum[j] - k
13 | if (presum.containsKey(sum - k)) {
14 | res += presum.get(sum - k);
15 | }
16 | // 更新 sum[j] 的个数
17 | if (presum.containsKey(sum)) {
18 | presum.put(sum, presum.get(sum) + 1);
19 | } else {
20 | presum.put(sum, 1);
21 | }
22 | }
23 | return res;
24 | }
25 | }
--------------------------------------------------------------------------------
/solutions/0563/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | int tilt;
3 |
4 | public int findTilt(TreeNode root) {
5 | tilt = 0;
6 | traverse(root);
7 | return tilt;
8 | }
9 |
10 | // 返回:结点值之和
11 | int traverse(TreeNode root) {
12 | if (root == null) {
13 | return 0;
14 | }
15 | int left = traverse(root.left);
16 | int right = traverse(root.right);
17 | // 计算当前子树的坡度,累加到全局变量
18 | tilt += Math.abs(left - right);
19 | return root.val + left + right;
20 | }
21 | }
--------------------------------------------------------------------------------
/solutions/0695/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int maxAreaOfIsland(int[][] grid) {
3 | int res = 0;
4 | for (int r = 0; r < grid.length; r++) {
5 | for (int c = 0; c < grid[0].length; c++) {
6 | if (grid[r][c] == 1) {
7 | int a = area(grid, r, c);
8 | res = Math.max(res, a);
9 | }
10 | }
11 | }
12 | return res;
13 | }
14 |
15 | int area(int[][] grid, int r, int c) {
16 | if (!inArea(grid, r, c)) {
17 | return 0;
18 | }
19 | if (grid[r][c] != 1) {
20 | return 0;
21 | }
22 | grid[r][c] = 2;
23 |
24 | return 1
25 | + area(grid, r - 1, c)
26 | + area(grid, r + 1, c)
27 | + area(grid, r, c - 1)
28 | + area(grid, r, c + 1);
29 | }
30 |
31 | boolean inArea(int[][] grid, int r, int c) {
32 | return 0 <= r && r < grid.length
33 | && 0 <= c && c < grid[0].length;
34 | }
35 | }
--------------------------------------------------------------------------------
/solutions/0718/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int findLength(int[] s, int[] t) {
3 | // 子问题:
4 | // f(i, j) = s[0..i) 和 t[0..j) 中以 s[i-1] 和 t[j-1] 结尾的最长公共子数组
5 | // 原问题 = max{ f(i, j) }, 0 <= i <= m, 0 <= j <= n
6 |
7 | // f(0, *) = 0
8 | // f(*, 0) = 0
9 | // f(i, j) = max:
10 | // f(i-1, j-1) + 1, if s[i-1] == t[j-1]
11 | // 0 , if s[i-1] != t[j-1]
12 |
13 | int m = s.length;
14 | int n = t.length;
15 | int[][] dp = new int[m+1][n+1];
16 |
17 | int res = 0;
18 | for (int i = 0; i <= m; i++) {
19 | for (int j = 0; j <= n; j++) {
20 | if (i == 0 || j == 0) {
21 | dp[i][j] = 0;
22 | } else {
23 | if (s[i-1] == t[j-1]) {
24 | dp[i][j] = dp[i-1][j-1] + 1;
25 | } else {
26 | dp[i][j] = 0;
27 | }
28 | }
29 | res = Math.max(res, dp[i][j]);
30 | }
31 | }
32 | return res;
33 | }
34 | }
--------------------------------------------------------------------------------
/solutions/0724/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int pivotIndex(int[] nums) {
3 | // 首先计算所有元素之和 S
4 | int S = 0;
5 | for (int n : nums) {
6 | S += n;
7 | }
8 |
9 | int A = 0; // A 为前缀和
10 | // 迭代计算前缀和
11 | for (int i = 0; i < nums.length; i++) {
12 | int x = nums[i];
13 | if (2 * A + x == S) {
14 | // 满足公式中的关系,x 是枢纽元素
15 | return i;
16 | }
17 | A += x; // 计算前缀和
18 | }
19 | return -1;
20 | }
21 | }
--------------------------------------------------------------------------------
/solutions/0827/1.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nettee/little-algorithm/0104bf3c13409e935256b186bf91cba17dc4ede3/solutions/0827/1.java
--------------------------------------------------------------------------------
/solutions/0876/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public ListNode middleNode(ListNode head) {
3 | ListNode fast = head;
4 | ListNode slow = head;
5 | while (fast != null && fast.next != null) {
6 | // fast 一次前进两个元素,slow 一次前进一个元素
7 | fast = fast.next.next;
8 | slow = slow.next;
9 | }
10 | // 链表元素为奇数个时,slow 指向链表的中点
11 | // 链表元素为偶数个时,slow 指向链表两个中点的右边一个
12 | return slow;
13 | }
14 | }
--------------------------------------------------------------------------------
/solutions/0978/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int maxTurbulenceSize(int[] A) {
3 | if (A.length <= 1) {
4 | return A.length;
5 | }
6 |
7 | int N = A.length;
8 | // 定义两个 DP 数组 f, g
9 | int[] f = new int[N+1];
10 | int[] g = new int[N+1];
11 | f[0] = 0;
12 | g[0] = 0;
13 | f[1] = 1;
14 | g[1] = 1;
15 |
16 | int res = 1;
17 | for (int k = 2; k <= N; k++) {
18 | if (A[k-2] < A[k-1]) {
19 | f[k] = g[k-1] + 1;
20 | g[k] = 1;
21 | } else if (A[k-2] > A[k-1]) {
22 | f[k] = 1;
23 | g[k] = f[k-1] + 1;
24 | } else {
25 | f[k] = 1;
26 | g[k] = 1;
27 | }
28 | res = Math.max(res, f[k]);
29 | res = Math.max(res, g[k]);
30 | }
31 | return res;
32 | }
33 | }
--------------------------------------------------------------------------------
/solutions/1143/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int longestCommonSubsequence(String s, String t) {
3 | if (s.isEmpty() || t.isEmpty()) {
4 | return 0;
5 | }
6 | // 子问题:
7 | // f(i, j) = s[0..i) 和 t[0..j) 的最长公共子序列
8 |
9 | // f(0, *) = 0
10 | // f(*, 0) = 0
11 | // f(i, j) = f(i-1, j-1) + 1, if s[i-1] == t[j-1]
12 | // max{ f(i-1, j), f(i, j-1) }, otherwise
13 |
14 | int m = s.length();
15 | int n = t.length();
16 | int[][] dp = new int[m+1][n+1];
17 | for (int i = 0; i <= m; i++) {
18 | for (int j = 0; j <= n; j++) {
19 | if (i == 0 || j == 0) {
20 | dp[i][j] = 0;
21 | } else {
22 | if (s.charAt(i-1) == t.charAt(j-1)) {
23 | dp[i][j] = dp[i-1][j-1] + 1;
24 | } else {
25 | dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
26 | }
27 | }
28 | }
29 | }
30 | return dp[m][n];
31 | }
32 | }
--------------------------------------------------------------------------------
/solutions/1162/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | public int maxDistance(int[][] grid) {
3 | int N = grid.length;
4 |
5 | Queue queue = new ArrayDeque<>();
6 | // 将所有的陆地格子加入队列
7 | for (int i = 0; i < N; i++) {
8 | for (int j = 0; j < N; j++) {
9 | if (grid[i][j] == 1) {
10 | queue.add(new int[]{i, j});
11 | }
12 | }
13 | }
14 |
15 | // 如果地图上只有陆地或者海洋,返回 -1
16 | if (queue.isEmpty() || queue.size() == N * N) {
17 | return -1;
18 | }
19 |
20 | int[][] moves = {
21 | {-1, 0}, {1, 0}, {0, -1}, {0, 1},
22 | };
23 |
24 | int distance = -1; // 记录当前遍历的层数(距离)
25 | while (!queue.isEmpty()) {
26 | distance++;
27 | int n = queue.size();
28 | for (int i = 0; i < n; i++) {
29 | int[] node = queue.poll();
30 | int r = node[0];
31 | int c = node[1];
32 | for (int[] move : moves) {
33 | int r2 = r + move[0];
34 | int c2 = c + move[1];
35 | if (inArea(grid, r2, c2) && grid[r2][c2] == 0) {
36 | grid[r2][c2] = 2;
37 | queue.add(new int[]{r2, c2});
38 | }
39 | }
40 | }
41 | }
42 |
43 | return distance;
44 | }
45 |
46 | // 判断坐标 (r, c) 是否在网格中
47 | boolean inArea(int[][] grid, int r, int c) {
48 | return 0 <= r && r < grid.length
49 | && 0 <= c && c < grid[0].length;
50 | }
51 | }
--------------------------------------------------------------------------------
/solutions/1372/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | int res; // 全局变量:记录最长之字形路径的长度
3 |
4 | public int longestZigZag(TreeNode root) {
5 | res = 0;
6 | traverse(root);
7 | return res - 1;
8 | }
9 |
10 | // 返回两个值
11 | // 返回值 0: 最长左之根路径的长度
12 | // 返回值 1: 最长右之根路径的长度
13 | int[] traverse(TreeNode root) {
14 | // base case:空子树的左之、右之路径长度为 0
15 | if (root == null) {
16 | return new int[]{0, 0};
17 | }
18 | // 递归计算左右子树的子问题
19 | int[] left = traverse(root.left);
20 | int[] right = traverse(root.right);
21 | // 套用公式
22 | int leftzz = 1 + left[1];
23 | int rightzz = 1 + right[0];
24 | // 更新全局变量(主要子问题)
25 | res = Math.max(res, leftzz);
26 | res = Math.max(res, rightzz);
27 | // 返回值(两个辅助子问题)
28 | return new int[]{leftzz, rightzz};
29 | }
30 | }
--------------------------------------------------------------------------------
/solutions/1373/1.java:
--------------------------------------------------------------------------------
1 | class Solution {
2 | // 用一个类包装递归函数的四个返回值
3 | class TreeInfo {
4 | boolean isBST;
5 | int min;
6 | int max;
7 | int sum;
8 |
9 | TreeInfo(boolean isBST, int min, int max, int sum) {
10 | this.isBST = isBST;
11 | this.min = min;
12 | this.max = max;
13 | this.sum = sum;
14 | }
15 | }
16 |
17 | int maxSum; // 全局变量:记录二叉搜索子树的结点之和的最大值
18 |
19 | public int maxSumBST(TreeNode root) {
20 | maxSum = 0;
21 | traverse(root);
22 | return maxSum;
23 | }
24 |
25 | TreeInfo traverse(TreeNode root) {
26 | // base case:空子树是二叉搜索树,最小值、最大值不存在,和为 0
27 | if (root == null) {
28 | return new TreeInfo(true, Integer.MAX_VALUE, Integer.MIN_VALUE, 0);
29 | }
30 | // 递归计算左右子树的子问题
31 | TreeInfo left = traverse(root.left);
32 | TreeInfo right = traverse(root.right);
33 | // 套用公式:计算结点之和
34 | int sum = root.val + left.sum + right.sum;
35 | // 套用公式:判断是否是二叉搜索树
36 | if (left.isBST && right.isBST && left.max < root.val && root.val < right.min) {
37 | // 当前子树是二叉搜索树的情况
38 | maxSum = Math.max(maxSum, sum);
39 | // 套用公式:计算二叉树最小值和最大值
40 | int min = Math.min(left.min, root.val);
41 | int max = Math.max(right.max, root.val);
42 | return new TreeInfo(true, min, max, sum);
43 | } else {
44 | // 当前子树不是二叉搜索树的情况
45 | return new TreeInfo(false, Integer.MAX_VALUE, Integer.MIN_VALUE, sum);
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------