├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── array ├── 1.两数之和.js ├── 125.验证回文串.js ├── 167.两数之和-ii-输入有序数组.js ├── 209.长度最小的子数组.js ├── 26.删除有序数组中的重复项.js ├── 27.移除元素.js ├── 283.移动零.js ├── 344.反转字符串.js ├── 349.两个数组的交集.js └── 977.有序数组的平方.js ├── assets ├── frog.png ├── suanfa-vx.jpg └── suanfa.png ├── binary ├── 153.寻找旋转排序数组中的最小值.js ├── 35.搜索插入位置.js ├── 69.x-的平方根.js └── 704.二分查找.js ├── count.js ├── draft.md ├── dynamic ├── 1143.最长公共子序列.js ├── 115.不同的子序列.js ├── 121.买卖股票的最佳时机.js ├── 122.买卖股票的最佳时机-ii.js ├── 123.买卖股票的最佳时机-iii.js ├── 198.打家劫舍.js ├── 213.打家劫舍-ii.js ├── 322.零钱兑换.js ├── 337.打家劫舍-iii.js ├── 392.判断子序列.js ├── 509.斐波那契数.js ├── 518.零钱兑换-ii.js ├── 53.最大子数组和.js ├── 583.两个字符串的删除操作.js ├── 62.不同路径.js ├── 63.不同路径-ii.js ├── 674.最长连续递增序列.js ├── 70.爬楼梯.js ├── 714.买卖股票的最佳时机含手续费.js ├── 72.编辑距离.js └── 746.使用最小花费爬楼梯.js ├── greedy ├── 300.最长递增子序列.js ├── 435.无重叠区间.js ├── 45.跳跃游戏-ii.js ├── 452.用最少数量的箭引爆气球.js ├── 455.分发饼干.js ├── 55.跳跃游戏.js ├── 621.任务调度器.js ├── 649.dota-2-参议院.js └── 860.柠檬水找零.js ├── interview ├── 1472.设计浏览器历史记录.js ├── 148.排序链表.js ├── 155.最小栈.js ├── 165.compare-version.js ├── 1797.设计一个验证系统.js ├── 18.四数之和.js ├── 2.两数相加.js ├── 208.实现-trie-前缀树.js ├── 215.数组中的第k个最大元素.js ├── 217.存在重复元素.js ├── 23.合并k个升序链表.js ├── 295.数据流的中位数.js ├── 341.扁平化嵌套列表迭代器.js ├── 347.前-k-个高频元素.js ├── 380.o-1-时间插入、删除和获取随机元素.js ├── 384.打乱数组.js ├── 460.lfu-缓存.js ├── 496.下一个更大元素-i.js ├── 502.ipo.js ├── 503.下一个更大元素-ii.js ├── 707.设计链表.js ├── 739.每日温度.js ├── 933.最近的请求次数.js ├── bit.js ├── calc-launch-time.js ├── coins.js ├── frog-jump.js ├── heap.js ├── leftpad.js ├── limit-promise.js ├── limit.js ├── matrix.js ├── offer.33.二叉搜索树的后序遍历序列.js ├── 剑指offer045.剑指 Offer II 045. 二叉树最底层最左边的值.js ├── 字符串排序.js ├── 服务器启动时间.md ├── 机器人面积.md ├── 简历格式生成.html └── 简历格式生成.js ├── linklist ├── 141.环形链表.js ├── 142.环形链表-ii.js ├── 146.lru-缓存.js ├── 160.相交链表.js ├── 19.删除链表的倒数第-n-个结点.js ├── 203.移除链表元素.js ├── 206.反转链表.js ├── 21.合并两个有序链表.js ├── 234.回文链表.js ├── 876.链表的中间结点.js └── 92.反转链表-ii.js ├── other ├── 202.快乐数.js ├── 242.有效的字母异位词.js ├── 292.nim-游戏.js ├── 326.3-的幂.js ├── 383.赎金信.js └── 877.石子游戏.js ├── package.json ├── pnpm-lock.yaml ├── recursion ├── 131.分割回文串.js ├── 17.电话号码的字母组合.js ├── 37.解数独.js ├── 39.组合总和.js ├── 46.全排列.js ├── 47.全排列-ii.js ├── 51.n-皇后.js ├── 77.组合.js ├── 78.子集.js ├── 79.单词搜索.js └── 93.复原-ip-地址.js ├── sort ├── 15.三数之和.js ├── 912.排序数组.js ├── arr.js └── sort.js ├── stack ├── 1047.删除字符串中的所有相邻重复项.js ├── 150.逆波兰表达式求值.js ├── 151.颠倒字符串中的单词.js ├── 20.有效的括号.js ├── 225.用队列实现栈.js ├── 232.用栈实现队列.js └── 71.简化路径.js ├── tips.md ├── tree ├── 100.相同的树.js ├── 101.对称二叉树.js ├── 102.二叉树的层序遍历.js ├── 104.二叉树的最大深度.js ├── 107.二叉树的层序遍历-ii.js ├── 108.将有序数组转换为二叉搜索树.js ├── 109.有序链表转换二叉搜索树.js ├── 110.平衡二叉树.js ├── 111.二叉树的最小深度.js ├── 112.路径总和.js ├── 114.二叉树展开为链表.js ├── 116.填充每个节点的下一个右侧节点指针.js ├── 117.填充每个节点的下一个右侧节点指针-ii.js ├── 136.只出现一次的数字.js ├── 144.二叉树的前序遍历.js ├── 145.二叉树的后序遍历.js ├── 199.二叉树的右视图.js ├── 222.完全二叉树的节点个数.js ├── 226.翻转二叉树.js ├── 230.二叉搜索树中第k小的元素.js ├── 236.二叉树的最近公共祖先.js ├── 257.二叉树的所有路径.js ├── 404.左叶子之和.js ├── 429.n-叉树的层序遍历.js ├── 515.在每个树行中找最大值.js ├── 543.二叉树的直径.js ├── 572.另一棵树的子树.js ├── 617.合并二叉树.js ├── 637.二叉树的层平均值.js ├── 654.最大二叉树.js ├── 700.二叉搜索树中的搜索.js ├── 701.二叉搜索树中的插入操作.js ├── 94.二叉树的中序遍历.js ├── 98.验证二叉搜索树.js └── 99.恢复二叉搜索树.js └── vite.config.ts /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: https://blc.h5.xeknow.com/s/Qbtpo # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 前端啃算法 2 | 大家可以把刷算法题,当成有趣的脑筋急转弯,还有配套[视频课程](https://student-api.iyincaishijiao.com/t/iekUQKRJ/) 3 | 4 | ## 1 前端算法入门 5 | 6 | 通过简单的算法题,初步掌握算法和数据结构的门槛,并且在前端的框架源码中用到的算法和数据结构进行分析,进一步巩固算法思想 7 | 8 | 前端工程师说到的算法,不涉及到太多数学和推导,主要是工程实现,是一种高级的`脑筋急转弯`,记住套路就可以,就像中学的应用题,有了数列or三角函数公式,去套公式解题 9 | 10 | ## 目录 11 | 12 | ``` 13 | 14 | 15 | ├── array 数组 16 | ├── linklist 链表 17 | ├── stack 栈 18 | ├── tree 树 19 | 20 | ├── sort 排序 21 | ├── binary 二分 22 | ├── recursion 递归+回溯 23 | ├── dynamic 动态规划 24 | ├── greedy 贪心算法 25 | ├── interview 大厂面试相关算法 (面试真题) 26 | │ ├── bit.js 位运算 27 | │ ├── heap.js 二叉堆 28 | │ ├── leftpad.js leftpad 29 | │ ├── limit.js 并发量控制 30 | └── ...学员面试中遇见的算法题 31 | ``` 32 | 33 | * 前端框架中用到的算法 34 | * Vue3的Dom diff 35 | * 300.最长递增子序列 36 | * Vue3的静态标记 && React中的类型判断 37 | * [位运算](./interview/bit.js) 38 | * React 任务调度 39 | * 二叉堆 40 | * React Fiber 41 | * 树 --> 链表的遍历 42 | * Vue的keep alive组件 43 | * 146.lru-缓存 44 | * 虚拟Dom diff 45 | * 树形结构的遍历 46 | * 编辑距离 ‘ 47 | * event-loop 队列 48 | * ... 49 | 50 | * 解题套路总结 51 | * 面试技巧 《怎样解题》 52 | * 1. 确定面试官的限制条件 53 | * 不让你用额外空间 空间复杂度O1 54 | * 时间复杂度O1 (哈希表,对象 map) 55 | * 限制某个函数 56 | * 先暴力解 57 | * 缓存,剪枝 58 | * 动态 or 贪心的思路 59 | * 预处理,空间换时间 三数之和的预排序 60 | * 猜题型,猜解法 61 | * 公式,公式,公式 62 | 63 | 64 | ## 大厂面试题中的算法和设计套路 65 | * 字节面试题: 66 | * [异步任务并发数控制](./interview/limit.js) 67 | * [primise版本](./interview/limit-promise.js) 68 | * 1472.设计浏览器历史记录.js 69 | * [二叉树底层的最左元素](https://leetcode.cn/problems/LwUNpT/) 70 | * 滴滴面试题 71 | * 72 | * [1797.设计一个验证系统.js](./interview/1797.%E8%AE%BE%E8%AE%A1%E4%B8%80%E4%B8%AA%E9%AA%8C%E8%AF%81%E7%B3%BB%E7%BB%9F.js) 73 | * 阿里面试题 74 | * [933.最近的请求次数.js](./interview/933.%E6%9C%80%E8%BF%91%E7%9A%84%E8%AF%B7%E6%B1%82%E6%AC%A1%E6%95%B0.js) 75 | * 百度面试题 76 | * [23.合并k个升序链表.js](./interview/23.%E5%90%88%E5%B9%B6k%E4%B8%AA%E5%8D%87%E5%BA%8F%E9%93%BE%E8%A1%A8.js) 77 | * 腾讯面试题 78 | * [148.排序链表](./interview/148.%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8.js) 79 | * [341.扁平化嵌套列表迭代器 数组扁平化](./interview/341.%E6%89%81%E5%B9%B3%E5%8C%96%E5%B5%8C%E5%A5%97%E5%88%97%E8%A1%A8%E8%BF%AD%E4%BB%A3%E5%99%A8.js) 80 | * 网易面试题:洗牌算法 81 | * [384.打乱数组](./interview/384.%E6%89%93%E4%B9%B1%E6%95%B0%E7%BB%84.js) 82 | * 美团面试题 83 | * [380.o-1-时间插入、删除和获取随机元素](./interview/380.o-1-%E6%97%B6%E9%97%B4%E6%8F%92%E5%85%A5%E3%80%81%E5%88%A0%E9%99%A4%E5%92%8C%E8%8E%B7%E5%8F%96%E9%9A%8F%E6%9C%BA%E5%85%83%E7%B4%A0.js) 84 | * 小厂面试题 85 | * [2.两数相加](./interview/2.%E4%B8%A4%E6%95%B0%E7%9B%B8%E5%8A%A0.js) 86 | * [217.存在重复元素.js](./interview/217.%E5%AD%98%E5%9C%A8%E9%87%8D%E5%A4%8D%E5%85%83%E7%B4%A0.js) 87 | * 特斯拉 88 | * [青蛙跳跃最大距离](./interview/frog-jump.js) 89 | * 华为 90 | * [服务启动时间](./interview/calc-launch-time.js) 91 | * 92 | * 如何确定文件的依赖关系 webpack vite和图 93 | * React任务调度和优先级队列 94 | * 区块链和链表 95 | * 浏览器的eventloop和任务队列 96 | ## 数据结构 97 | 98 | #### 数组 99 | 100 | * 1. 两数之和 101 | * 26.删除有序数组中的重复项 102 | * 27.移除元素 103 | * 283.移动零 104 | * 977.有序数组的平方 105 | * 209.长度最小的子数组 106 | * 344.反转字符串 (数组) 107 | * 167.两数之和-ii-输入有序数组 108 | * 125.验证回文串 109 | * 349.两个数组的交集 110 | 111 | #### 链表 112 | 113 | * 141.环形链表 114 | * 203.移除链表元素 115 | * 206.反转链表 116 | * 146.lru-缓存 117 | * 19.删除链表的倒数第 N 个结点 118 | * 21.合并两个有序链表 119 | * 876.链表的中间结点 120 | * 234.回文链表 121 | * 160.相交链表 122 | * 142.环形链表 II 123 | * 92.反转链表-ii 124 | #### 位运算 125 | 126 | * 136.只出现一次的数字 127 | 128 | 129 | #### 树结构 最需要学习和刷的数据结构 130 | 131 | * 104.二叉树的最大深度 132 | * 226.翻转二叉树 133 | * 94.中序遍历 134 | * 144.前序 135 | * 145.后序 136 | * 100.相同的树 137 | * 101.对称二叉树 138 | * 111.二叉树的最小深度 139 | * 114.二叉树展开为链表 140 | * 617.合并二叉树 141 | * 236.二叉树的最近公共祖先 142 | * 543.二叉树的直径 143 | * 572.另一棵树的子树 144 | * 110.平衡二叉树 145 | * 222.完全二叉树的节点个数 146 | * 257.二叉树的所有路径 147 | * 每层对比 148 | * 102.二叉树的层序遍历 149 | * 107.二叉树的层序遍历 II 150 | * 199.二叉树的右视图.js 151 | * 637.二叉树的层平均值 152 | * 116.填充每个节点的下一个右侧节点指针 153 | * 117.填充每个节点的下一个右侧节点指针-ii 154 | * 429.n-叉树的层序遍历 155 | * 515.在每个树行中找最大值 156 | * 112.路径总和 157 | * 404.左叶子之和 158 | * 98.验证二叉搜索树 159 | * 99.恢复二叉搜索树 160 | * 108.将有序数组转换为二叉搜索树 161 | * 109.有序链表转换二叉搜索树 162 | * 654.最大二叉树 163 | * 230.二叉搜索树中第k小的元素 164 | * 700.二叉搜索树中的搜索 165 | * 701.二叉搜索树中的插入操作 166 | 167 | #### 栈 168 | 169 | * 20.有效的括号 170 | * 71.简化路径 171 | * 225.用队列实现栈 172 | * 232.用栈实现队列 173 | * 1047.删除字符串中的所有相邻重复项 174 | * 150.逆波兰表达式求值 175 | * 151.点到字符串中的单词 176 | 177 | 178 | ## 算法思想 179 | 180 | #### 排序 181 | * 912.排序数组 182 | * 15.三数之和 183 | 184 | #### 二分思想 185 | 186 | * 快排 187 | * 704.二分查找 188 | * 35.搜索插入位置 // vue3里面的diff 贪心+二分 189 | * 153.寻找旋转排序数组中的最小值 190 | * 69.x 的平方根 191 | 192 | #### 回溯和搜索 193 | 194 | * 46.全排列 195 | * 79.单词搜索 196 | * 17.电话号码的字母组合 197 | * 39.组合总和 198 | * 51.n-皇后 199 | * 37.解数独 200 | * 77.组合 201 | * 78.子集 202 | * 131.分割回文串 203 | * 93.复原-ip-地址 204 | * 47.全排列-ii 205 | 206 | #### 贪心算法(没有什么公式) 207 | 208 | * 55.跳跃游戏 209 | * 45.跳跃游戏-ii 210 | * 300.最长递增子序列 211 | * 455.分发饼干 212 | * 860.柠檬水找零 213 | * 452.用最少数量的箭引爆气球 214 | * 435.无重叠区间 215 | * 621.任务调度器 216 | * 649.dota-2-参议院 217 | 218 | #### 动态规划(面试常客)最重要的 219 | 220 | * 509.斐波那契数 221 | * 70.爬楼梯 222 | * 746.使用最小花费爬楼梯 223 | * 62.不同路径 224 | * 63.不同路径-ii 225 | * 分硬币 226 | * 硬币不限 , 硬币的种类是变量, 硬币的数量有限制, 额度差 227 | * 322.零钱兑换 done 228 | * 背包 01 完全 229 | * 打家劫舍 有没有环 230 | * 198.打家劫舍 231 | * 213.打家劫舍-ii 232 | * 337.打家劫舍-iii 233 | * 股票 只能卖卖一次,两次,多次,冷冻起,手续费 234 | * 121.买卖股票的最佳时机 235 | * 122.买卖股票的最佳时机-ii 236 | * 123.买卖股票的最佳时机-iii 237 | 239 | * 714.买卖股票的最佳时机含手续费 240 | * 序列 241 | * 53.最大子序和 242 | * 674.最长连续递增序列 243 | * 518.零钱兑换-ii 244 | * 392.判断子序列 245 | * 1143.最长公共子序列 246 | * 115.不同的子序列 247 | * 583.两个字符串的删除操作 248 | * 72.编辑距离 249 | 250 | #### 其他有趣的数据结构、算法思想、题目 251 | 252 | * 哈希表 253 | * 202.快乐数 254 | * 242.有效的字母异位词 255 | * 383.赎金信 256 | * 数字游戏 257 | * 18.四数之和 258 | * 292.nim 259 | * 877.石子 260 | * 326.3-的幂.js 261 | 262 | 263 | #### 设计题 264 | 265 | * 堆 (top k) 266 | * 215.数组中的第k个最大元素 267 | * 295.数据流的中位数 268 | * 347.前-k-个高频元素 269 | * 502.ipo 270 | * 最小栈 271 | * 155.最小栈 272 | * 单调栈 273 | * 739.每日温度 274 | * 496.下一个更大元素-i 275 | * 503.下一个更大元素-ii 276 | * 设计LFU 277 | * 460.lfu-缓存 278 | * 设计Trie树 279 | * 208.实现-trie-前缀树 280 | * 搜索提示原理 281 | * 设计链表 282 | * 707.设计链表 283 | 284 | 285 | 286 | 287 | * @next 288 | * 图 289 | * 其他数据结构和算法思想扩展 290 | * 并查集 291 | * 跳表 292 | * 位图 293 | * 布隆过滤器 294 | * .... 295 | -------------------------------------------------------------------------------- /array/1.两数之和.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} target 4 | * @return {number[]} 5 | */ 6 | // 复杂度: 7 | // 数组长度是n 算法大概执行了多少次 时间复杂度是O(n^2) 8 | // 空间复杂度:i和j都是一个普通的数字 O(1) 9 | 10 | var twoSum = function(nums, target) { 11 | let obj = {} 12 | for(let i=0;itarget){ 26 | right-- 27 | }else if(sumtarget){ 44 | // right-- 45 | // }else{ 46 | // left++ 47 | // } 48 | // } 49 | // @lc code=end 50 | 51 | -------------------------------------------------------------------------------- /array/209.长度最小的子数组.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=209 lang=javascript 3 | * 4 | * [209] 长度最小的子数组 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} target 10 | * @param {number[]} nums 11 | * @return {number} 12 | */ 13 | var minSubArrayLen = function(target, nums) { 14 | // let len = nums.length 15 | // let result = len+1 16 | // for (let i = 0; i < len; i++) { 17 | // let sum = 0 18 | // for (let j = i; j < len; j++) { 19 | // sum+= nums[j] 20 | // if(sum>=target){ 21 | // let subLen = j-i+1 22 | // result = resultlen?0:result 29 | // slow fast一起,fast走的快 30 | // [2,3,1,2,4,3] 31 | // | | 32 | let len = nums.length 33 | let slow = fast = 0 34 | let sum = 0 35 | let result = len+1 36 | while(fast=target){ 39 | let subLen = fast-slow 40 | result = (resultlen?0:result 45 | }; 46 | // @lc code=end 47 | 48 | -------------------------------------------------------------------------------- /array/26.删除有序数组中的重复项.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=26 lang=javascript 3 | * 4 | * [26] 删除有序数组中的重复项 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @return {number} 11 | */ 12 | var removeDuplicates = function(nums) { 13 | // [1,1,2,2,3,3,3] 14 | // [1,2,3,2,3,3,4,] 15 | // [1,2,3,4,3,4,4] 16 | // slow fast 17 | // [] 18 | if(nums.length===0){ 19 | return 0 20 | } 21 | let slow = 0 22 | let fast = 0 23 | while(fastnums2.includes(i)))] 15 | 16 | let retSet = new Set() 17 | let num1Set = new Set(nums1) 18 | for(let i of nums2){ 19 | if(num1Set.has(i)){ 20 | retSet.add(i) 21 | } 22 | } 23 | return [...retSet] 24 | }; 25 | // @lc code=end 26 | 27 | -------------------------------------------------------------------------------- /array/977.有序数组的平方.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=977 lang=javascript 3 | * 4 | * [977] 有序数组的平方 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @return {number[]} 11 | */ 12 | // 原地 13 | var sortedSquares = function(nums) { 14 | // return nums.map(v=>v*v).sort((a,b)=>a-b) 15 | let left = 0 16 | let right = nums.length-1 17 | let arr = Array(nums.length) 18 | let k = right 19 | while(left<=right){ 20 | let l =nums[left] * nums[left] 21 | let r = nums[right] * nums[right] 22 | if(l>1) 21 | if(nums[mid]nums[right]){ 24 | left = mid+1 25 | } 26 | } 27 | return nums[left] 28 | }; 29 | // @lc code=end 30 | 31 | -------------------------------------------------------------------------------- /binary/35.搜索插入位置.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=35 lang=javascript 3 | * 4 | * [35] 搜索插入位置 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @param {number} target 11 | * @return {number} 12 | */ 13 | 14 | var searchInsert = function(nums, target) { 15 | let left = 0 16 | let right = nums.length-1 17 | while(left<=right){ 18 | let mid = left + ((right-left)>>1) 19 | if(nums[mid]target){ 22 | right = mid-1 23 | }else if(nums[mid]===target){ 24 | return mid 25 | } 26 | } 27 | return left 28 | 29 | }; 30 | // @lc code=end 31 | 32 | -------------------------------------------------------------------------------- /binary/69.x-的平方根.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=69 lang=javascript 3 | * 4 | * [69] x 的平方根 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} x 10 | * @return {number} 11 | */ 12 | var mySqrt = function(x) { 13 | 14 | // [0,1,2,3,4,5,6,7,8] 15 | let left = 0 16 | let right = x 17 | while(left<=right){ 18 | let mid = left + ((right-left)>>1) 19 | if(mid*midx){ 22 | right = mid-1 23 | }else if(mid*mid===x){ 24 | return mid 25 | } 26 | } 27 | return left-1 28 | }; 29 | // @lc code=end 30 | 31 | -------------------------------------------------------------------------------- /binary/704.二分查找.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=704 lang=javascript 3 | * 4 | * [704] 二分查找 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @param {number} target 11 | * @return {number} 12 | */ 13 | var search = function(nums, target) { 14 | // 总结二分的大概公式 15 | // 先看中点的值 16 | //5,9,12] [-1,0,3, 17 | // 9 18 | let left = 0 19 | let right = nums.length-1 //我们是可以访问到right的 20 | while(left<=right){ // left == right-1 21 | // let mid = (left+right)>>1 // 22 | let mid = left + ((right-left)>>1) 23 | // 其实这么写 也有小隐患 最稳妥的 位运算 24 | // left right相加,可能会越界 25 | 26 | // 如果数组的长度限制是10 27 | // left 5 right 7 5+7 = 12 28 | // mid 6 29 | 30 | if(nums[mid]target){ 34 | // 在mid左边继续查找 35 | right = mid-1 36 | }else if(nums[mid]===target){ 37 | return mid 38 | } 39 | } 40 | return -1 41 | // return nums[left]===target?left:-1 42 | // for (let i = 0; i < nums.length; i++) { 43 | // if(nums[i]===target){ 44 | // return i 45 | // } 46 | // } 47 | // return -1 48 | }; 49 | // @lc code=end 50 | 51 | -------------------------------------------------------------------------------- /count.js: -------------------------------------------------------------------------------- 1 | // const fs = require('fs') 2 | // const path = require('path') 3 | // const dir = path.resolve(__dirname,'./') 4 | 5 | // let files = fs.readdirSync(dir) 6 | // let len = files.filter(f=>/^\d+\..+\.js$/.test(f)).length 7 | // console.log('一共刷了'+len+'题,加油!') 8 | 9 | const fs = require('fs') 10 | const path = require('path') 11 | const dir = path.resolve(__dirname, './') 12 | 13 | let ret = fs.readdirSync(dir) 14 | let arr = ret.filter((v) => /^\d+\..+\.js$/.test(v)) 15 | let len = arr.length 16 | console.log(`你刷了${len}个题`) 17 | // console.log(len) 18 | const md = fs.readFileSync(path.resolve(__dirname, './README.md'), 'utf8') 19 | arr 20 | .sort((a, b) => { 21 | return Date(fs.statSync(a).ctime) - Date(fs.statSync(b).ctime) 22 | }) 23 | .forEach((file) => { 24 | let str = '* ' + file.split('.')[0] + '.' 25 | if (md.indexOf(str) == -1) { 26 | console.log(' * ' + file + ' 不存在') 27 | } 28 | }) 29 | 30 | let msgs = `有点意思 31 | 好顶赞 32 | 有点东西 33 | 点赞 34 | 1 35 | 卡了吗 36 | 太强了 37 | 关注关注 38 | 关注关注` 39 | .split('\n') 40 | .filter((v) => v) 41 | .map((v) => v.trim()) 42 | 43 | function send() { 44 | let i = Math.floor(Math.random() * msgs.length) 45 | let msg = msgs.splice(i, 1) 46 | let input = document.querySelectorAll('.chat-input')[1] 47 | input.value = msg 48 | 49 | ev = document.createEvent('HTMLEvents') 50 | //event.initEvent(eventType,canBubble,cancelable) 51 | //eventType:字符串值,事件的类型 52 | //canBubble:事件是否冒泡 53 | //cancelable:是否可以用preventDefault()方法取消事件 54 | ev.initEvent('input', false, true) 55 | input.dispatchEvent(ev) 56 | document 57 | .querySelector( 58 | '.bl-button.live-skin-highlight-button-bg.live-skin-button-text.bl-button--primary.bl-button--small' 59 | ) 60 | .click() 61 | } 62 | send() 63 | setInterval(() => { 64 | send() 65 | }, 1000 * 60 * 10) 66 | -------------------------------------------------------------------------------- /draft.md: -------------------------------------------------------------------------------- 1 | # algorithm 2 | 前端啃算法 3 | 4 | 5 | ​ 6 | 7 | [1,2,3,4,5] 8 | ​ 9 | 10 | 1=>2=>3=>4 11 | ​ 12 | 13 | 数据结构的增删改查 14 | 15 | 16 | arr[0] arr[1] 随机访问 O(1) 17 | ​ 18 | 19 | [1 ,2,3,6,4,5] 新增元素复杂度是O(n) 20 | ​ 21 | 22 | ​ 23 | 24 | 链表: 25 | -----> 26 | 1 2 3=>4 =7=>5=>6 27 | 随机访问的复杂度是O(n) 28 | 删除 和插入元素复杂度都是O1 29 | 30 | 31 | 32 | 33 | 34 | 搜索 排序,都是基础问题 35 | 36 | 排序算法:如何把一个数组变成有序的 37 | arr = [3,2,1,4] 38 | 增删改查几个操作 39 | 冒泡排序 40 | 41 | 42 | 43 | 44 | 45 | 排序 46 | 二分 47 | 递归 48 | 回溯 49 | 贪心 50 | 动态规划 51 | 52 | 53 | 全排列 54 | 57 | 58 | 1. 需要全部答案的路径 59 | ``` 60 | let list = [] 61 | function backtrack(list,临时路径,输入){ 62 | 63 | 结束条件: 64 | 临时路径.新增一个路径 65 | 66 | 循环{ 67 | 选择一个数据 (选择其他数据) 68 | 递归 backtrack(list,临时路径,输入) 69 | 撤回选择的数据 70 | } 71 | } 72 | 73 | backtrack(list) 74 | 75 | ``` 76 | 77 | 2 不需要全部路径,只需要true或者false 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | ## 贪心 86 | 每一步都选择当前最优解,跟之前的选择没关系 87 | 1. 找零钱(最少的张数) 88 | 1. 100,50,20,10,5,1(无限) 89 | 2. 每一次都可以按照这个当前能找的最大值 最终能够得出全局最后解 (没有反例) 90 | 91 | ## 动态规划 递推公式 92 | 求极值 93 | 每一步的状态,是前一步推导而来 94 | 95 | 101 | 102 | 菲波那切数列 103 | [0,1,1,2,3,5,8,13....] 104 | 105 | dp[i] 中间值的推导 106 | 确定推导的公式 107 | 确定初始化 和遍历顺序 108 | 109 | Vue中的虚拟dom diff 最长递增子序列 (刷题) -------------------------------------------------------------------------------- /dynamic/1143.最长公共子序列.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=1143 lang=javascript 3 | * 4 | * [1143] 最长公共子序列 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} text1 10 | * @param {string} text2 11 | * @return {number} 12 | */ 13 | 14 | // 111 15 | // 111 16 | // 111 17 | var longestCommonSubsequence = function(text1, text2) { 18 | // dp[i][j] 19 | // text1的i之前的字符串和 text2的j之前的字符串的最长公共子序列的长度就是dp[i][j] 20 | let dp = new Array(text1.length+1).fill(0).map(i=>{ 21 | return new Array(text2.length+1).fill(0) 22 | }) 23 | for(let i=1;i<=text1.length;i++){ 24 | for(j=1;j<=text2.length;j++){ 25 | if(text1[i-1]===text2[j-1]){ 26 | dp[i][j] = dp[i-1][j-1]+1 27 | }else{ 28 | dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]) 29 | } 30 | } 31 | } 32 | return dp[text1.length][text2.length] 33 | }; 34 | // @lc code=end 35 | 36 | -------------------------------------------------------------------------------- /dynamic/115.不同的子序列.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=115 lang=javascript 3 | * 4 | * [115] 不同的子序列 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} s 10 | * @param {string} t 11 | * @return {number} 12 | */ 13 | var numDistinct = function(s, t) { 14 | // 遍历s 15 | // 遍历t 16 | // dp[i][j] s中以i结尾的子序列中,出现t中j之前的字符串的个数dp[i][j] 17 | 18 | // babgbag 19 | // bag 20 | 21 | // s[i] t[j] 相等 22 | // 用s[i-1] 之前的字符串匹配 dp[i-1][j-1] 23 | // 不用s[i-1] 之前dp[i-1][j] 24 | // s[i] t[j] 不相等 25 | // s[i-1]来匹配 d[i-1][j] 26 | let dp = new Array(s.length+1).fill(0).map(item=>{ 27 | return new Array(t.length+1).fill(0) 28 | }) 29 | 30 | for(let i=0;i<=s.length;i++){ 31 | dp[i][0] = 1 32 | } 33 | 34 | for(let i=1;i<=s.length;i++){ 35 | for(let j=1;j<=t.length;j++){ 36 | if(s[i-1]==t[j-1]){ 37 | dp[i][j] = dp[i-1][j-1]+dp[i-1][j] 38 | }else{ 39 | dp[i][j] = dp[i-1][j] 40 | } 41 | } 42 | } 43 | // console.log(dp) 44 | return dp[s.length][t.length] 45 | }; 46 | // numDistinct('babgbag','bag') 47 | // @lc code=end 48 | 49 | -------------------------------------------------------------------------------- /dynamic/121.买卖股票的最佳时机.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=121 lang=javascript 3 | * 4 | * [121] 买卖股票的最佳时机 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} prices 10 | * @return {number} 11 | */ 12 | var maxProfit = function(prices) { 13 | // let low = Infinity 14 | // let ret = 0 15 | // for(let i=0;i0){ 32 | ret += prices[i]-prices[i-1] 33 | } 34 | // resut += Math.max(prices[i]-prices[i-1],0) 35 | } 36 | 37 | return ret 38 | }; 39 | // @lc code=end 40 | 41 | -------------------------------------------------------------------------------- /dynamic/123.买卖股票的最佳时机-iii.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=123 lang=javascript 3 | * 4 | * [123] 买卖股票的最佳时机 III 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} prices 10 | * @return {number} 11 | */ 12 | var maxProfit = function(prices) { 13 | // 只能两次买卖 14 | // 不买卖 0 15 | // 买卖一次 16 | // 买卖两次 17 | // 买买 卖卖 18 | 19 | // dp[i][0] 不买也不卖 20 | // dp[i][1] 第i天,你买入股票的状态 21 | // dp[i][2]卖出 22 | // dp[i][3]第二次买入 23 | // dp[i][3]第二次卖出 24 | // dp[i-1][0]-prices[i] 25 | // let len = prices.length 26 | // let dp = new Array(len).fill(0).map(x=>{ 27 | // return new Array(5).fill(0) 28 | // }) 29 | // dp[0][1] = -prices[0] 30 | // dp[0][3] = -prices[0] 31 | // for(let i=1;i{ 27 | return new Array(n+1).fill(0) 28 | }) 29 | for(let i=1;i<=m;i++){ 30 | for(let j=1;j<=n;j++){ 31 | 32 | if(s[i-1]===t[j-1]){ 33 | dp[i][j] = dp[i-1][j-1]+1 34 | }else{ 35 | dp[i][j] = dp[i][j-1] 36 | } 37 | } 38 | } 39 | return dp[m][n] == m 40 | // dp 41 | // 下标i结尾的字符串s,和下边j结尾的字符串t,相同子序列的长度 42 | // // dp[i][j] 43 | 44 | // if(s[i-1]===t[j-1]){ 45 | 46 | // }else{ 47 | // // 删除元素 48 | // } 49 | }; 50 | // @lc code=end 51 | 52 | -------------------------------------------------------------------------------- /dynamic/509.斐波那契数.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=509 lang=javascript 3 | * 4 | * [509] 斐波那契数 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} n 10 | * @return {number} 11 | */ 12 | 13 | // 递推 14 | function helper(memo,n){ 15 | if(n<=1){ 16 | return n 17 | } 18 | if(memo[n]){ 19 | return memo[n] //返回缓存的结果 20 | } 21 | memo[n] = helper(memo,n-1)+helper(memo,n-2) 22 | return memo[n] 23 | } 24 | var fib = function(n) { 25 | // let memo = [] 26 | // return helper(memo,n) 27 | 28 | 29 | // 带一个备忘录 缓存中间的计算结果 30 | // if(n<=1){ 31 | // return n 32 | // } 33 | // return fib(n-1)+fib(n-2) 34 | // dp[i] 就是第i个值得数字 35 | // dp[i] = dp[i-1]+dp[i-2] 36 | // [0,1] 37 | // let dp = [0,1] 38 | 39 | // for(let i=2;i<=n;i++){ 40 | // dp[i] = dp[i-1]+dp[i-2] 41 | // } 42 | // return dp[n] 43 | // 数组优化成两个数字 44 | // 数学公式 45 | // 还可以用矩阵去优化公式中浮点数的N次方计算 46 | if(n<=1){ 47 | return n 48 | } 49 | let dp1 = 0 50 | let dp2 = 1 51 | let dp3 52 | for(let i=2;i<=n;i++){ 53 | dp3 = dp1+dp2 54 | dp1 = dp2 55 | dp2 = dp3 56 | } 57 | return dp3 58 | }; 59 | // @lc code=end 60 | 61 | -------------------------------------------------------------------------------- /dynamic/518.零钱兑换-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=518 lang=javascript 3 | * 4 | * [518] 零钱兑换 II 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} amount 10 | * @param {number[]} coins 11 | * @return {number} 12 | */ 13 | var change = function(amount, coins) { 14 | // dp[i] 凑齐i块钱的不同金额种类 15 | // 1,2,5 16 | // dp[i] 17 | // i=100 18 | // 99,98,95 19 | let dp = new Array(amount+1).fill(0) 20 | dp[0] = 1 21 | for(let i=0;iret){ 30 | ret = count 31 | } 32 | if(count<0){ 33 | count=0 34 | } 35 | } 36 | return ret 37 | }; 38 | // @lc code=end 39 | 40 | -------------------------------------------------------------------------------- /dynamic/583.两个字符串的删除操作.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=583 lang=javascript 3 | * 4 | * [583] 两个字符串的删除操作 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} word1 10 | * @param {string} word2 11 | * @return {number} 12 | */ 13 | var minDistance = function(word1, word2) { 14 | // dp[i][j] 15 | // word1的slice(0,i) word2.slice(0,j)相互删除字符达到相同所需要的步数 16 | 17 | // word1[i-1]和word2[j-1] 18 | // 相同 19 | // bag 20 | // eag 21 | // dp[i-1][j-1] 22 | // 不相同 23 | // bag 24 | // eat 25 | 26 | // dp[i-1][j] 27 | // dp[i][j-1] 28 | // dp[i-1][j-1] 29 | // 取最小值 30 | let dp = new Array(word1.length+1).fill(0).map(item=>{ 31 | return new Array(word2.length+1).fill(0) 32 | }) 33 | // word1 '' word2是任意字符串,都是删除全部字符得到 34 | for(let i=1;i<=word1.length;i++){ 35 | dp[i][0] = i 36 | } 37 | for(let j=1;j<=word2.length;j++){ 38 | dp[0][j] = j 39 | } 40 | // ba 41 | // ea 42 | 43 | for(let i=1;i<=word1.length;i++){ 44 | for(let j=1;j<=word2.length;j++){ 45 | if(word1[i-1]==word2[j-1]){ 46 | dp[i][j] = dp[i-1][j-1] 47 | }else{ 48 | dp[i][j] = Math.min( 49 | dp[i][j-1] +1 , 50 | dp[i-1][j] +1 , 51 | dp[i-1][j-1]+2 52 | ) 53 | } 54 | } 55 | } 56 | // console.log(dp) 57 | return dp[word1.length][word2.length] 58 | 59 | 60 | }; 61 | // @lc code=end 62 | 63 | -------------------------------------------------------------------------------- /dynamic/62.不同路径.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=62 lang=javascript 3 | * 4 | * [62] 不同路径 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} m 10 | * @param {number} n 11 | * @return {number} 12 | */ 13 | // [ 1, 1, 1, 1 ], [ 1, 000], [ 1, 000 ], [ 000, 1 ] 14 | var uniquePaths = function(m, n) { 15 | // const dp = new Array(n).fill(m).map(()=>{ 16 | // return new Array(n).fill(1) 17 | // }) 18 | const dp = new Array(m).fill('').map(i=>new Array(n).fill('')) 19 | for(let i=0;i{ 16 | return new Array(n).fill(0) 17 | }) 18 | for(let i=0;inums[i]){ 17 | dp[i+1] = dp[i]+1 18 | } 19 | } 20 | return Math.max(...dp) 21 | 22 | }; 23 | // @lc code=end 24 | 25 | -------------------------------------------------------------------------------- /dynamic/70.爬楼梯.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=70 lang=javascript 3 | * 4 | * [70] 爬楼梯 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} n 10 | * @return {number} 11 | */ 12 | var climbStairs = function(n) { 13 | // n层台阶 有多少种方法 14 | // n-1层 +1 15 | // n-2层 +2 16 | let dp = [1,2] 17 | for(let i=2;i=minPrice && prices[i]<=minPrice+fee){ 35 | continue 36 | } 37 | if(prices[i]>minPrice+fee){ 38 | ret += prices[i]-minPrice-fee 39 | minPrice = prices[i]-fee 40 | } 41 | } 42 | 43 | return ret 44 | }; 45 | // @lc code=end 46 | 47 | -------------------------------------------------------------------------------- /dynamic/72.编辑距离.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=72 lang=javascript 3 | * 4 | * [72] 编辑距离 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} word1 10 | * @param {string} word2 11 | * @return {number} 12 | */ 13 | var minDistance = function(word1, word2) { 14 | 15 | let dp = new Array(word1.length+1).fill(0).map(item=>{ 16 | return new Array(word2.length+1).fill(0) 17 | }) 18 | for(let i=1;i<=word1.length;i++){ 19 | dp[i][0] = i 20 | } 21 | for(let j=1;j<=word2.length;j++){ 22 | dp[0][j] = j 23 | } 24 | // ba 25 | // ea 26 | 27 | for(let i=1;i<=word1.length;i++){ 28 | for(let j=1;j<=word2.length;j++){ 29 | if(word1[i-1]==word2[j-1]){ 30 | dp[i][j] = dp[i-1][j-1] 31 | }else{ 32 | dp[i][j] = Math.min( 33 | dp[i][j-1] +1 , 34 | dp[i-1][j] +1 , 35 | dp[i-1][j-1]+1 36 | ) 37 | } 38 | } 39 | } 40 | // console.log(dp) 41 | return dp[word1.length][word2.length] 42 | 43 | 44 | }; 45 | // @lc code=end 46 | 47 | -------------------------------------------------------------------------------- /dynamic/746.使用最小花费爬楼梯.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=746 lang=javascript 3 | * 4 | * [746] 使用最小花费爬楼梯 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} cost 10 | * @return {number} 11 | */ 12 | // 规划这个最小值 13 | // dp 你到哪第一个台阶所需要的最小花费 是dp[i] 14 | var minCostClimbingStairs = function(cost) { 15 | // [10,15,20] 16 | // dp其实不需要一个这么长的数组 17 | let dp = [cost[0],cost[1]] 18 | for(let i=2;iarr[arr.length-1]){ 24 | arr.push(nums[i]) 25 | }else{ 26 | // 找到arr中第一个num[i]大的数组,修改它 27 | let left = 0 28 | let right = arr.length-1 29 | while(left>1 31 | if(arr[mid]nums[j]){ 56 | // dp[i] = Math.max(dp[i],dp[j]+1) 57 | // } 58 | // } 59 | // } 60 | // return Math.max(...dp) 61 | }; 62 | // @lc code=end 63 | 64 | -------------------------------------------------------------------------------- /greedy/435.无重叠区间.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=435 lang=javascript 3 | * 4 | * [435] 无重叠区间 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[][]} intervals 10 | * @return {number} 11 | */ 12 | var eraseOverlapIntervals = function(intervals) { 13 | intervals.sort((a,b)=>a[1]-b[1]) 14 | let count = 1 15 | let end = intervals[0][1] 16 | for(let i=1;i=end){ 19 | end = inv[1] 20 | // 额外的区间 21 | count++ 22 | } 23 | } 24 | return intervals.length-count 25 | }; 26 | // @lc code=end 27 | 28 | -------------------------------------------------------------------------------- /greedy/45.跳跃游戏-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=45 lang=javascript 3 | * 4 | * [45] 跳跃游戏 II 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @return {number} 11 | */ 12 | var jump = function(nums) { 13 | let curIndex = 0 14 | let nextIndex = 0 15 | let step = 0 16 | for(let i=0;ia[0]-b[0]) 14 | // 气球重叠的部分,一起用一支箭 15 | let result = 1 16 | // 开始的部分就是有一支箭 17 | for(let i=1;i points[i-1][1]){ 19 | // 者之间没有交叉 20 | result++ 21 | }else{ 22 | // 尽可能的找重叠层数最多的 23 | points[i][1] = Math.min(points[i-1][1],points[i][1]) 24 | } 25 | } 26 | return result 27 | }; 28 | // @lc code=end 29 | 30 | -------------------------------------------------------------------------------- /greedy/455.分发饼干.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=455 lang=javascript 3 | * 4 | * [455] 分发饼干 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} g 10 | * @param {number[]} s 11 | * @return {number} 12 | */ 13 | var findContentChildren = function(g, s) { 14 | g = g.sort((a,b)=>a-b) 15 | s = s.sort((a,b)=>a-b) 16 | // 饼干满足胃口尽可能大的小朋友 17 | let ret = 0 18 | let index = s.length-1 19 | for(let i=g.length-1;i>=0;i--){ 20 | if(index>=0 && s[index]>=g[i]){ 21 | ret++ 22 | index-- 23 | } 24 | } 25 | return ret 26 | 27 | 28 | }; 29 | // @lc code=end 30 | 31 | -------------------------------------------------------------------------------- /greedy/55.跳跃游戏.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=55 lang=javascript 3 | * 4 | * [55] 跳跃游戏 5 | */ 6 | 7 | 8 | // @lc code=start 9 | /** 10 | * @param {number[]} nums 11 | * @return {boolean} 12 | */ 13 | var canJump = function(nums) { 14 | // 跳跃的范围 15 | let cover = 0 //cover比num.length-1大 16 | for(let i=0;i<=cover;i++){ 17 | cover = Math.max(cover, i+nums[i]) 18 | if(cover>=nums.length-1){ 19 | return true 20 | } 21 | } 22 | return false 23 | }; 24 | // @lc code=end 25 | 26 | -------------------------------------------------------------------------------- /greedy/621.任务调度器.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=621 lang=javascript 3 | * 4 | * [621] 任务调度器 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {character[]} tasks 10 | * @param {number} n 11 | * @return {number} 12 | */ 13 | var leastInterval = function(tasks, n) { 14 | let arr = new Array(26).fill(0) 15 | for(let t of tasks){ 16 | arr[t.charCodeAt()-'A'.charCodeAt()]++ 17 | } 18 | let max = Math.max(...arr) 19 | let ret = (max-1)*(n+1) 20 | for(let i=0;i<26;i++){ 21 | if(arr[i]===max){ 22 | ret++ 23 | } 24 | } 25 | return Math.max(ret,tasks.length) 26 | }; 27 | // @lc code=end 28 | 29 | -------------------------------------------------------------------------------- /greedy/649.dota-2-参议院.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=649 lang=javascript 3 | * 4 | * [649] Dota2 参议院 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} senate 10 | * @return {string} 11 | */ 12 | var predictPartyVictory = function(senate) { 13 | // 比较栈 14 | 15 | // 胜利队列 16 | let queue = senate.split('') 17 | let stack = [] 18 | while(queue[0]){ 19 | let s = queue.shift() 20 | 21 | if(stack.length===0 || stack[stack.length-1]===s){ 22 | stack.push(s) 23 | }else{ 24 | queue.push(stack.pop()) 25 | } 26 | } 27 | return stack.pop() ==='R' ?"Radiant":"Dire" 28 | }; 29 | // @lc code=end 30 | 31 | -------------------------------------------------------------------------------- /greedy/860.柠檬水找零.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=860 lang=javascript 3 | * 4 | * [860] 柠檬水找零 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} bills 10 | * @return {boolean} 11 | // */ 12 | // 1. 给5 直接揣兜里 13 | // 2. 给10 兜里有5 就给他 14 | 15 | // 3. 给20 给一个10+5 也可以给5+5+5 16 | // 优先给10块 17 | 18 | var lemonadeChange = function(bills) { 19 | let fiveNum = 0 20 | let tenNum = 0 21 | for(let i=0;i0){ 27 | fiveNum -= 1 28 | tenNum += 1 29 | }else{ 30 | return false 31 | } 32 | }else{ 33 | // 20的情况 34 | if(tenNum>0 && fiveNum>0){ 35 | fiveNum -= 1 36 | tenNum -= 1 37 | }else if(fiveNum>2){ 38 | fiveNum -= 3 39 | }else{ 40 | return false 41 | } 42 | } 43 | } 44 | return true 45 | }; 46 | // @lc code=end 47 | 48 | -------------------------------------------------------------------------------- /interview/1472.设计浏览器历史记录.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=1472 lang=javascript 3 | * 4 | * [1472] 设计浏览器历史记录 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} homepage 10 | */ 11 | var BrowserHistory = function(homepage) { 12 | this.stack = [homepage] 13 | this.cur = 0 14 | }; 15 | // a,b,c,d 16 | // b 17 | /** 18 | * @param {string} url 19 | * @return {void} 20 | */ 21 | BrowserHistory.prototype.visit = function(url) { 22 | this.stack.length = this.cur+1 23 | this.stack.push(url) 24 | this.cur++ 25 | }; 26 | 27 | /** 28 | * @param {number} steps 29 | * @return {string} 30 | */ 31 | BrowserHistory.prototype.back = function(steps) { 32 | this.cur = Math.max(0,this.cur-steps) 33 | return this.stack[this.cur] 34 | // 当前是第3个,你要后退1步,到第二个 35 | // 后退5步,到第0个 36 | }; 37 | 38 | /** 39 | * @param {number} steps 40 | * @return {string} 41 | */ 42 | BrowserHistory.prototype.forward = function(steps) { 43 | this.cur = Math.min(this.stack.length-1,this.cur+steps) 44 | return this.stack[this.cur] 45 | // 总共有5个,你在第二个,前进10步 46 | }; 47 | 48 | /** 49 | * Your BrowserHistory object will be instantiated and called as such: 50 | * var obj = new BrowserHistory(homepage) 51 | * obj.visit(url) 52 | * var param_2 = obj.back(steps) 53 | * var param_3 = obj.forward(steps) 54 | */ 55 | // @lc code=end 56 | 57 | -------------------------------------------------------------------------------- /interview/148.排序链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=148 lang=javascript 3 | * 4 | * [148] 排序链表 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val, next) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.next = (next===undefined ? null : next) 13 | * } 14 | */ 15 | /** 16 | * @param {ListNode} head 17 | * @return {ListNode} 18 | */ 19 | var sortList = function(head) { 20 | if(!head){ 21 | return null 22 | } 23 | let arr = [] 24 | while(head){ 25 | let tmp = head.next 26 | head.next = null 27 | arr.push(head) 28 | head = tmp 29 | } 30 | arr.sort((a,b)=>a.val-b.val) 31 | for(let i=0;iv2){ 17 | return 1 18 | } 19 | } 20 | return 0 21 | }; -------------------------------------------------------------------------------- /interview/1797.设计一个验证系统.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=1797 lang=javascript 3 | * 4 | * [1797] 设计一个验证系统 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} timeToLive 10 | */ 11 | var AuthenticationManager = function(timeToLive) { 12 | this.timeToLive = timeToLive 13 | this.manager = {} 14 | // this.manager = new Map() //管理所有token {} 15 | }; 16 | 17 | /** 18 | * @param {string} tokenId 19 | * @param {number} currentTime 20 | * @return {void} 21 | */ 22 | AuthenticationManager.prototype.generate = function(tokenId, currentTime) { 23 | this.manager[tokenId] = currentTime 24 | // this.manager.set(tokenId,currentTime) 25 | }; 26 | 27 | /** 28 | * @param {string} tokenId 29 | * @param {number} currentTime 30 | * @return {void} 31 | */ 32 | AuthenticationManager.prototype.renew = function(tokenId, currentTime) { 33 | if(tokenId in this.manager){ 34 | let time = this.manager[tokenId] 35 | if(time+this.timeToLive >currentTime){ 36 | this.manager[tokenId] = currentTime 37 | } 38 | } 39 | }; 40 | 41 | /** 42 | * @param {number} currentTime 43 | * @return {number} 44 | */ 45 | AuthenticationManager.prototype.countUnexpiredTokens = function(currentTime) { 46 | let result = 0 47 | 48 | for(const time of Object.values(this.manager)){ 49 | if(time + this.timeToLive>currentTime){ 50 | result+=1 51 | } 52 | } 53 | return result 54 | }; 55 | 56 | /** 57 | * Your AuthenticationManager object will be instantiated and called as such: 58 | * var obj = new AuthenticationManager(timeToLive) 59 | * obj.generate(tokenId,currentTime) 60 | * obj.renew(tokenId,currentTime) 61 | * var param_3 = obj.countUnexpiredTokens(currentTime) 62 | */ 63 | // @lc code=end 64 | 65 | -------------------------------------------------------------------------------- /interview/18.四数之和.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=18 lang=javascript 3 | * 4 | * [18] 四数之和 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @param {number} target 11 | * @return {number[][]} 12 | */ 13 | var fourSum = function(nums, target) { 14 | // [1,0,-1,0,-2,2] 15 | let list = [] 16 | let len = nums.length 17 | let tmp = [] 18 | nums.sort((a,b)=>a-b) 19 | dfs(0,4,target) 20 | return list 21 | function dfs(index,count,target){ 22 | if(count===0 && target===0){ 23 | // @todo 24 | list.push([...tmp]) 25 | return 26 | } 27 | // 剪枝 28 | if(len-indexcount*nums[len-1]){ 36 | return 37 | } 38 | for(let i =index;iindex && nums[i]===nums[i-1]){ 40 | continue 41 | } 42 | tmp.push(nums[i]) 43 | dfs(i+1, count-1, target-nums[i]) 44 | tmp.pop() 45 | } 46 | } 47 | 48 | // nSum 49 | }; 50 | // @lc code=end 51 | 52 | -------------------------------------------------------------------------------- /interview/2.两数相加.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=2 lang=javascript 3 | * 4 | * [2] 两数相加 5 | */ 6 | 7 | 8 | // @lc code=start 9 | /** 10 | * Definition for singly-linked list. 11 | * function ListNode(val, next) { 12 | * this.val = (val===undefined ? 0 : val) 13 | * this.next = (next===undefined ? null : next) 14 | * } 15 | */ 16 | /** 17 | * @param {ListNode} l1 18 | * @param {ListNode} l2 19 | * @return {ListNode} 20 | */ 21 | var addTwoNumbers = function(l1, l2) { 22 | // [99] 23 | // [99] 24 | // 进位 25 | // 89 26 | let addOne = 0 27 | let flag = cur = new ListNode(0) 28 | while(addOne || l1||l2){ 29 | let val1 = l1!==null ? l1.val :0 30 | let val2 = l2!==null ? l2.val :0 31 | let sum = val1+val2 + addOne 32 | addOne = sum>=10 ? 1 : 0 33 | 34 | cur.next = new ListNode(sum%10) 35 | cur = cur.next 36 | if(l1){ 37 | l1 = l1.next 38 | } 39 | if(l2){ 40 | l2 = l2.next 41 | } 42 | } 43 | return flag.next 44 | 45 | }; 46 | // @lc code=end 47 | 48 | -------------------------------------------------------------------------------- /interview/208.实现-trie-前缀树.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=208 lang=javascript 3 | * 4 | * [208] 实现 Trie (前缀树) 5 | */ 6 | 7 | // @lc code=start 8 | 9 | var Trie = function() { 10 | // word 11 | // world 12 | // wowowow 13 | // wo 14 | // w 15 | this.children = {} 16 | }; 17 | 18 | /** 19 | * @param {string} word 20 | * @return {void} 21 | */ 22 | Trie.prototype.insert = function(word) { 23 | let children = this.children 24 | for(let ch of word){ 25 | if(!children[ch]){ 26 | children[ch] = {} 27 | } 28 | children = children[ch] 29 | } 30 | children.end = true // 最后一个节点标记一下结束 31 | }; 32 | 33 | /** 34 | * @param {string} word 35 | * @return {boolean} 36 | */ 37 | Trie.prototype.search = function(word) { 38 | let ret = this.startsWith(word) 39 | return ret && ret.end!==undefined 40 | }; 41 | 42 | /** 43 | * @param {string} prefix 44 | * @return {boolean} 45 | */ 46 | Trie.prototype.startsWith = function(prefix) { 47 | let {children} = this 48 | for(let ch of prefix ){ 49 | if(!children[ch]) return false 50 | children = children[ch] 51 | } 52 | return children 53 | }; 54 | 55 | /** 56 | * Your Trie object will be instantiated and called as such: 57 | * var obj = new Trie() 58 | * obj.insert(word) 59 | * var param_2 = obj.search(word) 60 | * var param_3 = obj.startsWith(prefix) 61 | */ 62 | 63 | // let trie = new Trie(); 64 | // trie.insert("apple"); 65 | // trie.search("apple"); // 返回 True 66 | // trie.search("app"); // 返回 False 67 | // trie.startsWith("app"); // 返回 True 68 | // trie.insert("app"); 69 | // trie.search("app"); // 返回 True 70 | 71 | // console.log(JSON.stringify(trie.children,null,2)) 72 | 73 | 74 | // @lc code=end 75 | 76 | -------------------------------------------------------------------------------- /interview/215.数组中的第k个最大元素.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=215 lang=javascript 3 | * 4 | * [215] 数组中的第K个最大元素 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @param {number} k 11 | * @return {number} 12 | */ 13 | class Heap{ 14 | constructor(compare){ 15 | this.arr = [0] //忽略0这个索引 16 | this.compare = compare?compare:(a,b)=>a>b 17 | } 18 | get size(){ 19 | return this.arr.length-1 20 | } 21 | push(item){ 22 | // 新增元素 23 | this.arr.push(item) 24 | this.shiftUp(this.arr.length-1) 25 | } 26 | shiftUp(k){ 27 | let {arr,compare,parent} = this 28 | while(k>1 && compare(arr[k],arr[parent(k)])){ 29 | this.swap(parent(k),k) 30 | k = parent(k) 31 | } 32 | } 33 | pop(){ 34 | // 弹出堆顶 35 | if(this.arr.length==1) return null 36 | this.swap(1, this.arr.length-1) 37 | let head = this.arr.pop() //删除堆顶 38 | this.sinkDown(1) 39 | return head 40 | } 41 | sinkDown(k){ 42 | let {arr,compare,left,right,size} = this 43 | while(left(k)<=size){ 44 | let child = left(k) 45 | if(right(k)<=size && compare(arr[right(k)],arr[child])){ 46 | child = right(k) 47 | } 48 | if(compare(arr[k],arr[child])) { 49 | return 50 | } 51 | this.swap(k,child) 52 | k = child //继续向下 53 | } 54 | } 55 | 56 | peek(){ 57 | // 获取堆顶元素 58 | return this.arr[1] 59 | } 60 | left(k){ 61 | return k*2 62 | } 63 | right(k){ 64 | return k*2+1 65 | } 66 | parent(k){ 67 | return Math.floor(k/2) 68 | } 69 | swap(i,j){ 70 | [this.arr[i],this.arr[j]] = [this.arr[j],this.arr[i]] 71 | } 72 | } 73 | 74 | var findKthLargest = function(nums, k) { 75 | // 维护一个大小是K的小顶堆 76 | let minHeap = new Heap((a,b)=>ak){ 80 | minHeap.pop() 81 | } 82 | } 83 | return minHeap.peek() 84 | // return nums.sort((a,b)=>b-a)[k-1] 85 | // n*lgK 86 | }; 87 | // @lc code=end 88 | 89 | -------------------------------------------------------------------------------- /interview/217.存在重复元素.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=217 lang=javascript 3 | * 4 | * [217] 存在重复元素 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @return {boolean} 11 | */ 12 | var containsDuplicate = function(nums) { 13 | 14 | nums.sort((a,b)=>a-b) 15 | for(let i=0;ia.val-b.val) 35 | // let head = cur = arr[0] || null 36 | // for(let i=1;i>1) 56 | const leftList = mergeLists(lists,start,mid) 57 | const rightList = mergeLists(lists,mid+1,end) 58 | return merge(leftList,rightList) 59 | } 60 | 61 | function merge(head1,head2){ 62 | let flag = new ListNode(0) 63 | let p =flag 64 | while(head1 && head2){ 65 | if(head1.val<=head2.val){ 66 | p.next = head1 67 | head1 = head1.next 68 | }else{ 69 | p.next = head2 70 | head2 = head2.next 71 | } 72 | p = p.next 73 | } 74 | p.next = head1 ? head1:head2 75 | return flag.next 76 | } 77 | 78 | // @lc code=end 79 | 80 | -------------------------------------------------------------------------------- /interview/295.数据流的中位数.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=295 lang=javascript 3 | * 4 | * [295] 数据流的中位数 5 | */ 6 | 7 | // @lc code=start 8 | 9 | class Heap{ 10 | constructor(compare){ 11 | this.arr = [0] //忽略0这个索引 12 | this.compare = compare?compare:(a,b)=>a>b 13 | } 14 | get size(){ 15 | return this.arr.length-1 16 | } 17 | push(item){ 18 | // 新增元素 19 | this.arr.push(item) 20 | this.shiftUp(this.arr.length-1) 21 | } 22 | shiftUp(k){ 23 | let {arr,compare,parent} = this 24 | while(k>1 && compare(arr[k],arr[parent(k)])){ 25 | this.swap(parent(k),k) 26 | k = parent(k) 27 | } 28 | } 29 | pop(){ 30 | // 弹出堆顶 31 | if(this.arr.length==1) return null 32 | this.swap(1, this.arr.length-1) 33 | let head = this.arr.pop() //删除堆顶 34 | this.sinkDown(1) 35 | return head 36 | } 37 | sinkDown(k){ 38 | let {arr,compare,left,right,size} = this 39 | while(left(k)<=size){ 40 | let child = left(k) 41 | if(right(k)<=size && compare(arr[right(k)],arr[child])){ 42 | child = right(k) 43 | } 44 | if(compare(arr[k],arr[child])) { 45 | return 46 | } 47 | this.swap(k,child) 48 | k = child //继续向下 49 | } 50 | } 51 | 52 | peek(){ 53 | // 获取堆顶元素 54 | return this.arr[1] 55 | } 56 | left(k){ 57 | return k*2 58 | } 59 | right(k){ 60 | return k*2+1 61 | } 62 | parent(k){ 63 | return Math.floor(k/2) 64 | } 65 | swap(i,j){ 66 | [this.arr[i],this.arr[j]] = [this.arr[j],this.arr[i]] 67 | } 68 | } 69 | 70 | 71 | var MedianFinder = function() { 72 | // 设计一个大顶堆 小的那一半数字 73 | this.maxHeap = new Heap((a,b)=>a>b) 74 | // 一个小顶堆 放大的那一半数字 75 | this.minHeap = new Heap((a,b)=>a1){ 91 | this.minHeap.push(this.maxHeap.pop()) 92 | } 93 | if(this.minHeap.size>this.maxHeap.size){ 94 | this.maxHeap.push(this.minHeap.pop()) 95 | } 96 | }; 97 | 98 | /** 99 | * @return {number} 100 | */ 101 | MedianFinder.prototype.findMedian = function() { 102 | // if() 103 | if((this.maxHeap.size+this.minHeap.size)%2===0){ 104 | return (this.maxHeap.peek()+this.minHeap.peek())/2 105 | } 106 | return this.maxHeap.peek() 107 | }; 108 | 109 | /** 110 | * Your MedianFinder object will be instantiated and called as such: 111 | * var obj = new MedianFinder() 112 | * obj.addNum(num) 113 | * var param_2 = obj.findMedian() 114 | */ 115 | // @lc code=end 116 | 117 | -------------------------------------------------------------------------------- /interview/341.扁平化嵌套列表迭代器.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=341 lang=javascript 3 | * 4 | * [341] 扁平化嵌套列表迭代器 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * // This is the interface that allows for creating nested lists. 10 | * // You should not implement it, or speculate about its implementation 11 | * function NestedInteger() { 12 | * 13 | * Return true if this NestedInteger holds a single integer, rather than a nested list. 14 | * @return {boolean} 15 | * this.isInteger = function() { 16 | * ... 17 | * }; 18 | * 19 | * Return the single integer that this NestedInteger holds, if it holds a single integer 20 | * Return null if this NestedInteger holds a nested list 21 | * @return {integer} 22 | * this.getInteger = function() { 23 | * ... 24 | * }; 25 | * 26 | * Return the nested list that this NestedInteger holds, if it holds a nested list 27 | * Return null if this NestedInteger holds a single integer 28 | * @return {NestedInteger[]} 29 | * this.getList = function() { 30 | * ... 31 | * }; 32 | * }; 33 | */ 34 | /** 35 | * @constructor 36 | * @param {NestedInteger[]} nestedList 37 | */ 38 | var NestedIterator = function(nestedList) { 39 | this.list = [] 40 | this.flatArray(nestedList) 41 | }; 42 | 43 | 44 | NestedIterator.prototype.flatArray = function(arr){ 45 | for(let i=0;i0 59 | 60 | }; 61 | 62 | /** 63 | * @this NestedIterator 64 | * @returns {integer} 65 | */ 66 | NestedIterator.prototype.next = function() { 67 | return this.list.shift() 68 | }; 69 | 70 | 71 | function flatArray(arr){ 72 | const stack = [...arr] 73 | const ret = [] 74 | while(stack.length){ 75 | let next = stack.pop() 76 | if(Array.isArray(next)){ 77 | stack.push(...next) 78 | }else{ 79 | ret.push(next) 80 | } 81 | } 82 | return ret 83 | } 84 | // console.log(flatArray([[9,8],1,2,3,[4,5,[6,7]]])) 85 | /** 86 | * Your NestedIterator will be called like this: 87 | * var i = new NestedIterator(nestedList), a = []; 88 | * while (i.hasNext()) a.push(i.next()); 89 | */ 90 | // @lc code=end 91 | 92 | -------------------------------------------------------------------------------- /interview/347.前-k-个高频元素.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=347 lang=javascript 3 | * 4 | * [347] 前 K 个高频元素 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @param {number} k 11 | * @return {number[]} 12 | */ 13 | 14 | class Heap{ 15 | constructor(compare){ 16 | this.arr = [0] //忽略0这个索引 17 | this.compare = compare?compare:(a,b)=>a>b 18 | } 19 | get size(){ 20 | return this.arr.length-1 21 | } 22 | push(item){ 23 | // 新增元素 24 | this.arr.push(item) 25 | this.shiftUp(this.arr.length-1) 26 | } 27 | shiftUp(k){ 28 | let {arr,compare,parent} = this 29 | while(k>1 && compare(arr[k],arr[parent(k)])){ 30 | this.swap(parent(k),k) 31 | k = parent(k) 32 | } 33 | } 34 | pop(){ 35 | // 弹出堆顶 36 | if(this.arr.length==1) return null 37 | this.swap(1, this.arr.length-1) 38 | let head = this.arr.pop() //删除堆顶 39 | this.sinkDown(1) 40 | return head 41 | } 42 | sinkDown(k){ 43 | let {arr,compare,left,right,size} = this 44 | while(left(k)<=size){ 45 | let child = left(k) 46 | if(right(k)<=size && compare(arr[right(k)],arr[child])){ 47 | child = right(k) 48 | } 49 | if(compare(arr[k],arr[child])) { 50 | return 51 | } 52 | this.swap(k,child) 53 | k = child //继续向下 54 | } 55 | } 56 | 57 | peek(){ 58 | // 获取堆顶元素 59 | return this.arr[1] 60 | } 61 | left(k){ 62 | return k*2 63 | } 64 | right(k){ 65 | return k*2+1 66 | } 67 | parent(k){ 68 | return Math.floor(k/2) 69 | } 70 | swap(i,j){ 71 | [this.arr[i],this.arr[j]] = [this.arr[j],this.arr[i]] 72 | } 73 | } 74 | 75 | var topKFrequent = function(nums, k) { 76 | let map = {} 77 | nums.map(num=>{ 78 | // map[num] = (num in map?map[num]+1||1 79 | if(num in map){ 80 | map[num]+=1 81 | }else{ 82 | map[num] = 1 83 | } 84 | }) 85 | // // let arr = [...new Set(nums)] 86 | // return Object.keys(map).sort((a,b)=>map[b]-map[a]).slice(0,k) 87 | 88 | // 维护一个大小是K的小顶堆, 89 | let heap = new Heap((a,b)=>map[a]{ 91 | if(i=0;i--){ 29 | // 10 30 | // 0~9 31 | const ri = Math.floor(Math.random()*(i+1)) 32 | ;[arr[i],arr[ri]] = [arr[ri],arr[i]] 33 | } 34 | return arr 35 | }; 36 | 37 | /** 38 | * Your Solution object will be instantiated and called as such: 39 | * var obj = new Solution(nums) 40 | * var param_1 = obj.reset() 41 | * var param_2 = obj.shuffle() 42 | */ 43 | // @lc code=end 44 | 45 | -------------------------------------------------------------------------------- /interview/460.lfu-缓存.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=460 lang=javascript 3 | * 4 | * [460] LFU 缓存 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} capacity 10 | */ 11 | var LFUCache = function(capacity) { 12 | this.size = capacity 13 | this.values = new Map() // key:value 14 | this.times = new Map() // key:次数 15 | // 找到当前次数最小的key 16 | // useMap更新的逻辑,其实vue的响应式依赖管理很像 17 | this.useMap = new Map() //次数:key: set(key) 18 | this.min =0 //最小次数是多少 19 | }; 20 | LFUCache.prototype.updateCount = function(key){ 21 | let time = this.times.get(key) 22 | let useSet = this.useMap.get(time) 23 | if(this.min===time && useSet.size===1){ 24 | //当前次数是最小值 并且这个次数只有一个key 25 | this.min +=1 26 | } 27 | // time 10=>11 28 | time+=1 29 | useSet.delete(key) 30 | useSet = this.useMap.get(time) || new Set() 31 | useSet.add(key) 32 | this.useMap.set(time,useSet) 33 | this.times.set(key,time) 34 | } 35 | /** 36 | * @param {number} key 37 | * @return {number} 38 | */ 39 | LFUCache.prototype.get = function(key) { 40 | if(this.values.has(key)){ 41 | this.updateCount(key) 42 | return this.values.get(key) 43 | } 44 | return -1 45 | }; 46 | 47 | /** 48 | * @param {number} key 49 | * @param {number} value 50 | * @return {void} 51 | */ 52 | LFUCache.prototype.put = function(key, value) { 53 | if(this.size===0){ 54 | return 55 | } 56 | if(this.values.has(key)){ 57 | //值存在,不需要淘汰 58 | this.values.set(key,value) 59 | this.updateCount(key) 60 | }else{ 61 | //值不存在,需要看size 62 | if(this.size === this.values.size){ 63 | // 满了需要淘汰 64 | let minSet = this.useMap.get(this.min) 65 | let minKey = minSet.keys().next().value 66 | minSet.delete(minKey) 67 | 68 | this.values.delete(minKey) 69 | this.times.delete(minKey) 70 | } 71 | // 更新 72 | this.values.set(key,value) 73 | // 这个数据出现了1次 74 | useSet = this.useMap.get(1) || new Set() 75 | useSet.add(key) 76 | this.useMap.set(1,useSet) 77 | this.times.set(key,1) 78 | this.min =1 79 | } 80 | }; 81 | 82 | /** 83 | * Your LFUCache object will be instantiated and called as such: 84 | * var obj = new LFUCache(capacity) 85 | * var param_1 = obj.get(key) 86 | * obj.put(key,value) 87 | */ 88 | // @lc code=end 89 | 90 | -------------------------------------------------------------------------------- /interview/496.下一个更大元素-i.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=496 lang=javascript 3 | * 4 | * [496] 下一个更大元素 I 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums1 10 | * @param {number[]} nums2 11 | * @return {number[]} 12 | */ 13 | var nextGreaterElement = function(nums1, nums2) { 14 | const map = {} 15 | const stack = [] 16 | for(let i=nums2.length-1;i>=0;i--){ 17 | const num = nums2[i] 18 | while(stack.length && num>=stack[stack.length-1]){ 19 | stack.pop() 20 | } 21 | map[num] = stack.length? stack[stack.length-1]:-1 22 | stack.push(num) 23 | } 24 | const res = nums1.map(n=>map[n]) 25 | return res 26 | }; 27 | // @lc code=end 28 | 29 | -------------------------------------------------------------------------------- /interview/502.ipo.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=502 lang=javascript 3 | * 4 | * [502] IPO 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} k 10 | * @param {number} w 11 | * @param {number[]} profits 12 | * @param {number[]} capital 13 | * @return {number} 14 | */ 15 | 16 | class Heap{ 17 | constructor(compare){ 18 | this.arr = [0] //忽略0这个索引 19 | this.compare = compare?compare:(a,b)=>a>b 20 | } 21 | get size(){ 22 | return this.arr.length-1 23 | } 24 | push(item){ 25 | // 新增元素 26 | this.arr.push(item) 27 | this.shiftUp(this.arr.length-1) 28 | } 29 | shiftUp(k){ 30 | let {arr,compare,parent} = this 31 | while(k>1 && compare(arr[k],arr[parent(k)])){ 32 | this.swap(parent(k),k) 33 | k = parent(k) 34 | } 35 | } 36 | pop(){ 37 | // 弹出堆顶 38 | if(this.arr.length==1) return null 39 | this.swap(1, this.arr.length-1) 40 | let head = this.arr.pop() //删除堆顶 41 | this.sinkDown(1) 42 | return head 43 | } 44 | sinkDown(k){ 45 | let {arr,compare,left,right,size} = this 46 | while(left(k)<=size){ 47 | let child = left(k) 48 | if(right(k)<=size && compare(arr[right(k)],arr[child])){ 49 | child = right(k) 50 | } 51 | if(compare(arr[k],arr[child])) { 52 | return 53 | } 54 | this.swap(k,child) 55 | k = child //继续向下 56 | } 57 | } 58 | 59 | peek(){ 60 | // 获取堆顶元素 61 | return this.arr[1] 62 | } 63 | left(k){ 64 | return k*2 65 | } 66 | right(k){ 67 | return k*2+1 68 | } 69 | parent(k){ 70 | return Math.floor(k/2) 71 | } 72 | swap(i,j){ 73 | [this.arr[i],this.arr[j]] = [this.arr[j],this.arr[i]] 74 | } 75 | } 76 | 77 | 78 | var findMaximizedCapital = function(k, w, profits, capital) { 79 | // topK的题 80 | let arr = capital.map((c,i)=> [c,profits[i]]) 81 | arr.sort((a,b)=>a[0]-b[0]) 82 | let heap = new Heap((a,b)=>a>b) 83 | let cur = 0 84 | while(k>0){ 85 | 86 | while(cur0){ 91 | w+= heap.pop() 92 | }else{ 93 | break 94 | } 95 | k-- 96 | } 97 | return w 98 | }; 99 | 100 | // @lc code=end 101 | 102 | -------------------------------------------------------------------------------- /interview/503.下一个更大元素-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=503 lang=javascript 3 | * 4 | * [503] 下一个更大元素 II 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @return {number[]} 11 | */ 12 | var nextGreaterElements = function(nums) { 13 | // [...nums,...nums] 14 | let len = nums.length 15 | const stack = [] 16 | let res = new Array(len).fill(-1) 17 | for(let i=0;inums[stack[stack.length-1]]){ 20 | const index = stack.pop() 21 | res[index] = num 22 | } 23 | stack.push(i%len) 24 | } 25 | return res 26 | }; 27 | // @lc code=end 28 | 29 | -------------------------------------------------------------------------------- /interview/707.设计链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=707 lang=javascript 3 | * 4 | * [707] 设计链表 5 | */ 6 | 7 | // @lc code=start 8 | 9 | // { 10 | // val, 11 | // next, 12 | // } 13 | 14 | var LinkNode = function(val,next){ 15 | this.val = val 16 | this.next = next 17 | } 18 | var MyLinkedList = function() { 19 | this.head = null //head节点 20 | this.tail = null //尾节点 21 | this.size = 0 //长度 22 | }; 23 | 24 | /** 25 | * @param {number} index 26 | * @return {number} 27 | */ 28 | MyLinkedList.prototype.getNode = function(index){ 29 | if(index<0 || index>=this.size){ 30 | return -1 31 | } 32 | let cur = new LinkNode(0,this.head) //虚拟节点 33 | while(index-- >=0){ 34 | cur = cur.next 35 | } 36 | return cur 37 | 38 | } 39 | MyLinkedList.prototype.get = function(index) { 40 | if(index<0||index>=this.size) { 41 | return -1 42 | } 43 | return this.getNode(index).val 44 | }; 45 | 46 | /** 47 | * @param {number} val 48 | * @return {void} 49 | */ 50 | MyLinkedList.prototype.addAtHead = function(val) { 51 | let node = new LinkNode(val,this.head) 52 | this.head = node 53 | this.size++ 54 | if(!this.tail){ 55 | this.tail = node 56 | } 57 | }; 58 | 59 | /** 60 | * @param {number} val 61 | * @return {void} 62 | */ 63 | MyLinkedList.prototype.addAtTail = function(val) { 64 | let node = new LinkNode(val,null) 65 | this.size++ 66 | if(this.tail){ 67 | this.tail.next = node 68 | this.tail = node 69 | return 70 | } 71 | this.tail = node 72 | this.head = node 73 | }; 74 | 75 | /** 76 | * @param {number} index 77 | * @param {number} val 78 | * @return {void} 79 | */ 80 | MyLinkedList.prototype.addAtIndex = function(index, val) { 81 | if(index>this.size) { 82 | return 83 | } 84 | if(index<=0){ 85 | this.addAtHead(val) 86 | return 87 | } 88 | if(index===this.size){ 89 | this.addAtTail(val) 90 | return 91 | } 92 | let node = this.getNode(index-1) 93 | node.next = new LinkNode(val,node.next) 94 | this.size++ 95 | // 其他情况 96 | }; 97 | 98 | /** 99 | * @param {number} index 100 | * @return {void} 101 | */ 102 | MyLinkedList.prototype.deleteAtIndex = function(index) { 103 | if(index<0 || index>=this.size){ 104 | return 105 | } 106 | if(index===0){ 107 | this.head = this.head.next 108 | this.size-- 109 | return 110 | } 111 | let node = this.getNode(index-1) 112 | node.next = node.next.next 113 | if(index===this.size-1){ 114 | this.tail = node 115 | } 116 | this.size-- 117 | }; 118 | 119 | /** 120 | * Your MyLinkedList object will be instantiated and called as such: 121 | * var obj = new MyLinkedList() 122 | * var param_1 = obj.get(index) 123 | * obj.addAtHead(val) 124 | * obj.addAtTail(val) 125 | * obj.addAtIndex(index,val) 126 | * obj.deleteAtIndex(index) 127 | */ 128 | // @lc code=end 129 | 130 | -------------------------------------------------------------------------------- /interview/739.每日温度.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=739 lang=javascript 3 | * 4 | * [739] 每日温度 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} temperatures 10 | * @return {number[]} 11 | */ 12 | var dailyTemperatures = function(temperatures) { 13 | 14 | let n = temperatures.length 15 | let res = new Array(n).fill(0) 16 | let stack = [] 17 | stack.push(0) 18 | for(let i=1;itemperatures[stack[stack.length-1]]){ 20 | const top = stack.pop() 21 | res[top] = i-top 22 | } 23 | stack.push(i) 24 | } 25 | return res 26 | // [,,,]12 27 | // // [4,2,4,-1,-1] 28 | // [4,2,4,-1,-1] 29 | // s [4] 30 | }; 31 | // @lc code=end 32 | 33 | -------------------------------------------------------------------------------- /interview/933.最近的请求次数.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=933 lang=javascript 3 | * 4 | * [933] 最近的请求次数 5 | */ 6 | 7 | // @lc code=start 8 | 9 | var RecentCounter = function() { 10 | this.arr = [] 11 | }; 12 | 13 | /** 14 | * @param {number} t 15 | * @return {number} 16 | */ 17 | RecentCounter.prototype.ping = function(t) { 18 | this.arr.push(t) 19 | while(this.arr[0]{ 11 | if(i+1>k){return} 12 | // id:任务id 13 | // next:下一步的任务 14 | // cost:任务的执行时间 15 | // in: 有几个任务依赖它 16 | // time:任务开始时间 17 | obj[i] = {id:i,next:new Set(),cost:row[i],in:0,time:0} 18 | row.forEach((col,j)=>{ 19 | if(i!==j && col===1){ 20 | obj[j].next.add(i) 21 | obj[i].in++ 22 | } 23 | }) 24 | }) 25 | // 就像webpack里的文件关系,入口文件->next的关系 26 | // 完成的任务 用来统计时间 27 | let compltes = [] 28 | // in是0的 说明没有前置任务,可以并行启动 29 | while(true){ 30 | let ready = [] 31 | for(let i in obj){ 32 | // 入口节点可能不止一个,找到他 in是0的意思,就是没有任务的.next是他 33 | // 没有前置任务,直接启动 34 | if(obj[i].in===0){ 35 | ready.push(obj[i]) 36 | } 37 | } 38 | if(ready.length===0){ 39 | break // 没有可以启动的任务 40 | } 41 | // 打印一下并行的任务 42 | // console.log(ready.map(v=>v.id)) 43 | ready.forEach(task=>{ 44 | task.next.forEach(nextTask=>{ 45 | // 任务挨个执行 46 | let next = obj[nextTask] 47 | // next的依赖项-1 等于0的话,就可以启动了 48 | next.in-- 49 | // 任务的开始时间 = max(前置任务的结束时间,当前任务的开始时间) 50 | next.time = Math.max(task.time+task.cost,next.time) 51 | }) 52 | }) 53 | ready.forEach(task=>{ 54 | delete obj[task.id] 55 | compltes.push(task) 56 | }) 57 | } 58 | const ret = Math.max(...compltes.map(task=>task.time+task.cost)) 59 | return ret 60 | } 61 | 62 | let arr1 = [ 63 | [1, 0, 0], 64 | [1, 2, 0], 65 | [0, 1, 3] 66 | ] 67 | //6 68 | console.log(calcLaunchTime(arr1,3)) 69 | let arr2 = [ 70 | [1, 0, 0, 0], 71 | [1, 2, 0, 0], 72 | [1, 1, 3, 0], 73 | [0, 0, 1, 4] 74 | ] 75 | //10 76 | console.log(calcLaunchTime(arr2,4)) 77 | let arr3 = [ 78 | [1, 0, 0, 0], 79 | [1, 2, 0, 0], 80 | [1, 0, 3, 0], 81 | [0, 1, 1, 4] 82 | ] 83 | //8 84 | console.log(calcLaunchTime(arr3,4)) 85 | 86 | let arr4 = [ 87 | [1, 0, 0, 0, 0, 0, 0, 0], 88 | [0, 2, 0, 0, 0, 0, 0, 0], 89 | [1, 1, 3, 0, 0, 0, 0, 0], 90 | [0, 0, 1, 4, 0, 0, 0, 0], 91 | [0, 0, 0, 1, 5, 0, 0, 0], 92 | [0, 0, 0, 1, 0, 6, 0, 0], 93 | [0, 0, 0, 0, 1, 1, 7, 0], 94 | [0, 0, 0, 0, 0, 0, 1, 8], 95 | ] 96 | console.log(calcLaunchTime(arr4,8)) 97 | -------------------------------------------------------------------------------- /interview/coins.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | //允许的钱是50,100,500,1000,5000 4 | var getMoney = function( number) { 5 | if(!number) return 0 6 | const coins = [5000,1000,500,100,50] 7 | const obj = { '50': 0, '100': 0, '500': 0, '1000': 0, '5000': 0 } 8 | // obj通过计算得来通用 9 | // const obj = coins.reduce((ret,a)=>{ 10 | // ret[a] = 0 11 | // return ret 12 | // },{}) 13 | let dp = Array(number+1).fill(Infinity) 14 | dp[0] = 0 15 | let selected = Array(number+1) 16 | selected[0] = {...obj} 17 | for(const coin of coins){ 18 | for(let j=coin;j<=number;j++){ 19 | // dp[j] 都是Infinity 20 | if(dp[j-coin]+ 1 < dp[j]){ 21 | dp[j] = dp[j-coin]+ 1 22 | selected[j] = {...selected[j-coin]} 23 | selected[j][coin]++ 24 | } 25 | } 26 | } 27 | 28 | return dp[number]===Infinity?-1:selected[number] 29 | } 30 | 31 | 32 | // limit可以限制硬币的数量,比如{5000:0,1000:4,}就是没有5000的,1000的有四个 33 | var getMoney1 = function( number,option={}) { 34 | if(!number){ 35 | return 0; 36 | } 37 | const coins = [5000,1000,500,100,50] 38 | const obj = coins.reduce((ret,a)=>{ 39 | ret[a] = 0 40 | return ret 41 | },{}) 42 | 43 | let dp = Array(number+1).fill(Infinity) 44 | dp[0] = 0 45 | let selected = Array(number+1) 46 | selected[0] = {...obj} 47 | const limit = {...obj,...option} 48 | for(const coin of coins){ 49 | let count = limit[coin] 50 | for(let i=number;i>=0;i--){ 51 | if(dp[i]!==Infinity){ 52 | // 编译count, 钱数没超过number 53 | for(let j=1;j<=count &&i+j*coin<=number;j++){ 54 | // 比如dp[100],2块的硬币有3个 55 | // 遍历这三个硬币,可以从dp[98]+1, dp[96]+2,dp[94]+3 三个最小值决定 56 | if(dp[i]+j { 74 | // expect(getMoney(6200)).toEqual({5000:1,1000:1,500:0,100:2,50:0}) 75 | // const option = { 5000:0,1000:7,100:5} 76 | // expect(getMoney1(6200),option).toEqual({5000:0,1000:6,100:2}) 77 | 78 | // }) 79 | // } 80 | -------------------------------------------------------------------------------- /interview/frog-jump.js: -------------------------------------------------------------------------------- 1 | // 特斯拉面试题 2 | 3 | // 有N块积木,从0到N-1,排成一排。 【特斯拉】 4 | // 一对青蛙坐在一块积木上,他们大吵了一架。 5 | // 现在它们想要跳离彼此,这样它们之间的距离就会尽可能大。 6 | // 块号J和K之间的距离,当J <=K时,计算为K - J + 1。 7 | // 青蛙只能跳起来, 8 | // 这意味着它们只能在 9 | // 两个木块相邻且第二个木块与第一个木块高度相同或更高的情况下才能从一个木块移动到另一个木块。 10 | // 如果它们一开始也选择坐在最理想的起始木块上,那么它们之间可能形成的最长距离是多少? 11 | 12 | // 写一个函数: 13 | 14 | // 函数的解决方案 15 | 16 | // 给定一个由表示方块高度的n整数组成的数组方块,返回两只青蛙从其中一个方块开始彼此之间可能的最长距离 17 | // ![](./assets/frog.png) 18 | // https://github.com/himanshuarora05/Codility-FrogJump 19 | 20 | // 动态规划 21 | function solution(blocks) { 22 | let ret = [] // 每一个block[i]作为起点的时候,最大的距离 23 | 24 | for(let i=0;i=0;j--){ 28 | // 第一只青蛙从右向左跳 29 | if(j===0 || blocks[j] > blocks[j-1]) { 30 | break 31 | } 32 | } 33 | 34 | for(k=i;k blocks[k+1]) { 37 | break 38 | } 39 | } 40 | 41 | // console.log(j,k) 42 | ret.push(k-j+1) 43 | } 44 | return Math.max(...ret) 45 | } 46 | console.log(solution([2,6,8,5])) 47 | console.log(solution([1,5,5,2,6])) 48 | console.log(solution([0,1])) -------------------------------------------------------------------------------- /interview/heap.js: -------------------------------------------------------------------------------- 1 | // top K 2 | // 长度是K的堆 3 | class Heap{ 4 | constructor(compare){ 5 | this.arr = [0] //忽略0这个索引 6 | this.compare = compare?compare:(a,b)=>a>b 7 | } 8 | get size(){ 9 | return this.arr.length-1 10 | } 11 | push(item){ 12 | // 新增元素 13 | this.arr.push(item) 14 | this.shiftUp(this.arr.length-1) 15 | } 16 | shiftUp(k){ 17 | let {arr,compare,parent} = this 18 | while(k>1 && compare(arr[k],arr[parent(k)])){ 19 | this.swap(parent(k),k) 20 | k = parent(k) 21 | } 22 | } 23 | pop(){ 24 | // 弹出堆顶 25 | if(this.arr.length==1) return null 26 | this.swap(1, this.arr.length-1) 27 | let head = this.arr.pop() //删除堆顶 28 | this.sinkDown(1) 29 | return head 30 | } 31 | sinkDown(k){ 32 | let {arr,compare,left,right,size} = this 33 | while(left(k)<=size){ 34 | let child = left(k) 35 | if(right(k)<=size && compare(arr[right(k)],arr[child])){ 36 | child = right(k) 37 | } 38 | if(compare(arr[k],arr[child])) { 39 | return 40 | } 41 | this.swap(k,child) 42 | k = child //继续向下 43 | } 44 | } 45 | 46 | peek(){ 47 | // 获取堆顶元素 48 | return this.arr[1] 49 | } 50 | left(k){ 51 | return k*2 52 | } 53 | right(k){ 54 | return k*2+1 55 | } 56 | parent(k){ 57 | return Math.floor(k/2) 58 | } 59 | swap(i,j){ 60 | [this.arr[i],this.arr[j]] = [this.arr[j],this.arr[i]] 61 | } 62 | } 63 | 64 | let heap = new Heap((a,b)=>a>b) //大顶堆 65 | // heap.push(1.5) 66 | heap.push(3) 67 | heap.push(1) 68 | heap.push(2) 69 | heap.push(4) 70 | // console.log(heap.arr) 71 | console.log(heap.pop()) 72 | console.log(heap.size) 73 | console.log(heap.pop()) 74 | console.log(heap.pop()) 75 | console.log('='.repeat(20)) 76 | let heap1 = new Heap((a,b)=>a> 1 37 | // len = parseInt(len/2) 38 | } 39 | 40 | } 41 | console.log(leftpad2('hello',10,'0')) 42 | 43 | 44 | 45 | console.time('leftpad') 46 | for(let i=0;i<10000;i++){ 47 | leftpad('hello',1000,'0') 48 | } 49 | console.timeEnd('leftpad') 50 | 51 | console.time('leftpad2') 52 | for(let i=0;i<10000;i++){ 53 | leftpad2('hello',1000,'0') 54 | } 55 | console.timeEnd('leftpad2') 56 | 57 | -------------------------------------------------------------------------------- /interview/limit-promise.js: -------------------------------------------------------------------------------- 1 | async function asyncPool({ 2 | limit, 3 | items, 4 | fn 5 | }) { 6 | const promises= [] 7 | const pool = new Set() 8 | for (const item of items) { 9 | const promise = fn(item) 10 | promises.push(promise) 11 | pool.add(promise) 12 | const clean = () => pool.delete(promise) 13 | promise.then(clean, clean) 14 | if (pool.size >= limit) await Promise.race(pool) 15 | } 16 | return Promise.all(promises) 17 | } 18 | 19 | async function sleep(n,name='test'){ 20 | return new Promise(resolve=>{ 21 | console.log(n,name,'start') 22 | setTimeout(()=>{ 23 | console.log(n,name,'end','-------------') 24 | resolve({n,name}) 25 | },n*1000) 26 | }) 27 | } 28 | 29 | 30 | async function start(){ 31 | asyncPool({ 32 | limit: 2, 33 | items: [ 34 | ()=> sleep(1,'吃饭'), 35 | ()=> sleep(3,'睡觉'), 36 | ()=> sleep(5,'打游戏'), 37 | ()=> sleep(3.5,'学习算法'), 38 | ()=> sleep(4,'学习Vue和React'), 39 | ], 40 | async fn(item){ 41 | return await item() 42 | } 43 | }) 44 | 45 | } 46 | // @think 如果任务有优先级呢 47 | start() 48 | 49 | -------------------------------------------------------------------------------- /interview/limit.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // function runTask(list){ 4 | // // 挨个执行传递的异步任务 5 | // } 6 | 7 | function limit(maxCount){ 8 | // [,5] 9 | // [2,34,] 10 | let queue = [] 11 | let activeCount = 0 12 | 13 | const next = ()=>{ 14 | //下一个任务 15 | activeCount-- 16 | if(queue.length>0){ 17 | queue.shift()() 18 | } 19 | } 20 | const run = async (fn,resolve,args)=>{ 21 | //执行一个函数 22 | activeCount++ 23 | const result = (async()=>fn(...args))() 24 | resolve(result) 25 | await result 26 | next() //下一个 27 | } 28 | const push = async (fn,resolve,args)=>{ 29 | queue.push(run.bind(null,fn,resolve,args)) 30 | if(activeCount0){ 31 | // 队列没满 并且还有任务 启动任务 32 | queue.shift()() 33 | } 34 | } 35 | 36 | let runner = (fn,...args)=>{ 37 | return new Promise((resolve)=>{ 38 | push(fn,resolve,args) 39 | }) 40 | } 41 | return runner 42 | 43 | 44 | } 45 | async function sleep(n,name='test'){ 46 | return new Promise(resolve=>{ 47 | console.log(n,name,'start') 48 | setTimeout(()=>{ 49 | console.log(n,name,'end','-------------') 50 | resolve({n,name}) 51 | },n*1000) 52 | }) 53 | } 54 | 55 | async function start(){ 56 | let runner = limit(2) //并发量是3 57 | let tasks = [ 58 | ()=> sleep(1,'吃饭'), 59 | ()=> sleep(3,'睡觉'), 60 | ()=> sleep(5,'打游戏'), 61 | ()=> sleep(3.5,'学习算法'), 62 | ()=> sleep(4,'学习Vue和React'), 63 | ].map(runner) 64 | let result = await Promise.all(tasks) 65 | console.log(result,'end') 66 | } 67 | // @think 如果任务有优先级呢 68 | start() -------------------------------------------------------------------------------- /interview/matrix.js: -------------------------------------------------------------------------------- 1 | // S型打印二维数组 2 | function printMatrix(n, m) { 3 | let ret = [] 4 | // let obj = Array(String(n*m).length-1).fill(0) 5 | // .reduce((val,v,i)=>{ 6 | // const num = Math.pow(10,i+1) 7 | // const index = Math.floor(num/n) -1 8 | // val[index] = i+2 9 | // return val 10 | // },{}) 11 | // console.log(obj) 12 | for (let i = 0; i < m; i++) { 13 | let arr = Array(n).fill(0).map((v, k) => k + i * n + 1) 14 | // const len = String(Math.max(...arr)).length 15 | // arr = arr.map(v=>String(v).padEnd(len," ")) 16 | ret.push(i & 1 ? arr.reverse() : arr) 17 | } 18 | let str = "" 19 | for (let y = 0; y < n; y++) { 20 | for (let x = 0; x < m; x++) { 21 | str += ret[x][y] + ' ' 22 | } 23 | str += '\n' 24 | } 25 | console.log(str) 26 | } 27 | printMatrix(6, 7) 28 | printMatrix(10, 10) 29 | // printMatrix(34, 34) 30 | -------------------------------------------------------------------------------- /interview/offer.33.二叉搜索树的后序遍历序列.js: -------------------------------------------------------------------------------- 1 | // https://leetcode.cn/problems/er-cha-sou-suo-shu-de-hou 2 | 3 | // 二叉搜索树:右》根》左 4 | // 后序遍历 左->右->根 5 | 6 | // 主要的思路就是找到左右树的分解,递归判断大小 7 | 8 | var verifyPostorder = function (postorder) { 9 | if (postorder.length <= 2) return true 10 | // 最后一个是root节点 11 | const root = postorder.pop() 12 | let i = 0 13 | // 找到左右的分界点 14 | while (postorder[i] < root) { 15 | i++ 16 | } 17 | let right = postorder.slice(i) 18 | let left = postorder.slice(0, i) 19 | // 右边当中所有节点都大于root 20 | const rightResult = right.every((item) => item > root) 21 | //递归 22 | return rightResult && verifyPostorder(left) && verifyPostorder(right) 23 | } 24 | -------------------------------------------------------------------------------- /interview/剑指offer045.剑指 Offer II 045. 二叉树最底层最左边的值.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val, left, right) { 4 | * this.val = (val===undefined ? 0 : val) 5 | * this.left = (left===undefined ? null : left) 6 | * this.right = (right===undefined ? null : right) 7 | * } 8 | */ 9 | /** 10 | * @param {TreeNode} root 11 | * @return {number} 12 | */ 13 | // dfs 14 | var findBottomLeftValue1 = function (root) { 15 | if (root === null) { 16 | return 17 | } 18 | let res, maxLevel = 0 19 | dfs(root, 1) 20 | return res && res.val 21 | function dfs(node, level) { 22 | if (!node) return 23 | if (level > maxLevel) res = node, maxLevel = level 24 | dfs(node.left, level + 1) 25 | dfs(node.right, level + 1) 26 | } 27 | } 28 | // dfs 二叉树的层序遍历 29 | var findBottomLeftValue = function (root) { 30 | let res 31 | const queue = [root] 32 | while (queue.length) { 33 | const len = queue.length 34 | for (let i = 0; i < len ; i++) { 35 | const node = queue.shift() 36 | if (i === 0) res = node.val 37 | node.left && queue.push(node.left) 38 | node.right && queue.push(node.right) 39 | } 40 | } 41 | return res 42 | } 43 | 44 | -------------------------------------------------------------------------------- /interview/字符串排序.js: -------------------------------------------------------------------------------- 1 | // ["B3","D2","F1","A9","D12","A2","C1","Z0","B1"] 2 | // => 3 | // // ["Z0","B1","C1","F1","A2","D2","B3","A9","D12"] 4 | // 假设有如下字符串“A12”,其中“A”表示数据类型(A-Z),“12”表示数据序号(0-9)。 5 | // 现在需要对一组数据先按照数据序号再按照数据类型进行排序。 6 | // 例如:["B3","D2","F1","A9","D12","A2","C1","Z0","B1"]=>["Z0","B1","C1","F1","A2","D2","B3","A9","D12"] 7 | function sortArr(arr){ 8 | return arr.sort((a,b)=>{ 9 | const [a1,b1] = [a,b].map(v=>Number(v.slice(1))) 10 | if(a1==b1){ 11 | return a[0].charCodeAt()-b[0].charCodeAt() 12 | }else{ 13 | return a1 -b1 14 | } 15 | }) 16 | } 17 | console.log(sortArr(["B3","D2","F1","A9","D12","A2","C1","Z0","B1"])) -------------------------------------------------------------------------------- /interview/服务器启动时间.md: -------------------------------------------------------------------------------- 1 | # 2. 用javascript求服务启动时间 2 | 已知每个服务启动都需要一定时间,且每个服务可能依赖其他的服务启动。现给定一个n*n的二维数组arr,arr[i][i]表示i服务启动需要的时间,arr[i][j]表示i服务是否依赖j服务,如果为1表示依赖,0表示不依赖。当服务依赖的服务彼此之间没有依赖关系时,这些服务可以并行启动。题目保证服务之间不存在循环依赖关系,求服务k(1<=k<=n)启动需要的时间。 3 | 示例1输入: 4 | ```javascript 5 | arr = [ 6 | [1, 0, 0], 7 | [1, 2, 0], 8 | [0, 1, 3] 9 | ] 10 | k = 3 11 | ``` 12 | 输出:6 13 | 14 | 说明:服务3启动需要依赖服务2,服务2启动需要依赖服务1,所以需要的时间为3 + 2 + 1 = 6 15 | 16 | 示例2输入: 17 | ```javascript 18 | arr = [ 19 | [1, 0, 0, 0], 20 | [1, 2, 0, 0], 21 | [1, 1, 3, 0], 22 | [0, 0, 1, 4] 23 | ] 24 | k = 4 25 | ``` 26 | 输出:10 27 | 说明:服务4启动需要依赖服务3,服务3启动需要依赖服务1和服务2,服务2启动需要依赖服务1,因此服务4启动需要的时间是服务1、服务2、服务3、和服务4启动的时间和:1 + 2 + 3 + 4 = 10 28 | 29 | 示例3输入: 30 | ```javascript 31 | arr = [ 32 | [1, 0, 0, 0], 33 | [1, 2, 0, 0], 34 | [1, 0, 3, 0], 35 | [0, 1, 1, 4] 36 | ] 37 | k = 4 38 | ``` 39 | 输出:8 40 | 说明:服务4启动需要依赖服务3和服务2,服务3和服务2启动都需要依赖服务1,服务3启动需要时间为3 + 1 = 4,服务2启动需要时间为2 + 1 = 3,由于服务2和服务3没有依赖关系,因此可以并行加载,因此服务4启动需要的时间为4 + 4 = 8 41 | 42 | 43 | 44 | ```javascript 45 | 46 | 47 | // 已知每个服务启动都需要一定时间,且每个服务可能依赖其他的服务启动。现给定一个n*n的二维数组arr, 48 | // arr[i][i]表示i服务启动需要的时间,arr[i][j]表示i服务是否依赖j服务,如果为1表示依赖, 49 | // 0表示不依赖。当服务依赖的服务彼此之间没有依赖关系时,这些服务可以并行启动。 50 | // 题目保证服务之间不存在循环依赖关系,求服务k(1<=k<=n)启动需要的时间。 51 | 52 | function calcLaunchTime(arr,k) { 53 | // 1. 生成依赖关系图 54 | let obj = {} 55 | arr.forEach((row,i)=>{ 56 | if(i+1>k){return} 57 | // id:任务id 58 | // next:下一步的任务 59 | // cost:任务的执行时间 60 | // in: 有几个任务依赖它 61 | // time:任务开始时间 62 | obj[i] = {id:i,next:new Set(),cost:row[i],in:0,time:0} 63 | row.forEach((col,j)=>{ 64 | if(i!==j && col===1){ 65 | obj[j].next.add(i) 66 | obj[i].in++ 67 | } 68 | }) 69 | }) 70 | // 就像webpack里的文件关系,入口文件->next的关系 71 | // 完成的任务 用来统计时间 72 | let compltes = [] 73 | // in是0的 说明没有前置任务,可以并行启动 74 | while(true){ 75 | let ready = [] 76 | for(let i in obj){ 77 | // 入口节点可能不止一个,找到他 in是0的意思,就是没有任务的.next是他 78 | // 没有前置任务,直接启动 79 | if(obj[i].in===0){ 80 | ready.push(obj[i]) 81 | } 82 | } 83 | if(ready.length===0){ 84 | break // 没有可以启动的任务 85 | } 86 | // 打印一下并行的任务 87 | // console.log(ready.map(v=>v.id)) 88 | ready.forEach(task=>{ 89 | task.next.forEach(nextTask=>{ 90 | // 任务挨个执行 91 | let next = obj[nextTask] 92 | // next的依赖项-1 等于0的话,就可以启动了 93 | next.in-- 94 | // 任务的开始时间 = max(前置任务的结束时间,当前任务的开始时间) 95 | next.time = Math.max(task.time+task.cost,next.time) 96 | }) 97 | }) 98 | ready.forEach(task=>{ 99 | delete obj[task.id] 100 | compltes.push(task) 101 | }) 102 | } 103 | const ret = Math.max(...compltes.map(task=>task.time+task.cost)) 104 | return ret 105 | } 106 | 107 | let arr1 = [ 108 | [1, 0, 0], 109 | [1, 2, 0], 110 | [0, 1, 3] 111 | ] 112 | //6 113 | console.log(calcLaunchTime(arr1,3)) 114 | let arr2 = [ 115 | [1, 0, 0, 0], 116 | [1, 2, 0, 0], 117 | [1, 1, 3, 0], 118 | [0, 0, 1, 4] 119 | ] 120 | //10 121 | console.log(calcLaunchTime(arr2,4)) 122 | let arr3 = [ 123 | [1, 0, 0, 0], 124 | [1, 2, 0, 0], 125 | [1, 0, 3, 0], 126 | [0, 1, 1, 4] 127 | ] 128 | //8 129 | console.log(calcLaunchTime(arr3,4)) 130 | 131 | let arr4 = [ 132 | [1, 0, 0, 0, 0, 0, 0, 0], 133 | [0, 2, 0, 0, 0, 0, 0, 0], 134 | [1, 1, 3, 0, 0, 0, 0, 0], 135 | [0, 0, 1, 4, 0, 0, 0, 0], 136 | [0, 0, 0, 1, 5, 0, 0, 0], 137 | [0, 0, 0, 1, 0, 6, 0, 0], 138 | [0, 0, 0, 0, 1, 1, 7, 0], 139 | [0, 0, 0, 0, 0, 0, 1, 8], 140 | ] 141 | console.log(calcLaunchTime(arr4,8)) //30 142 | ``` 143 | 144 | 145 | ## dp 146 | 从上到下推到 147 | 148 | 149 | ```js 150 | 151 | 152 | function calcLaunchTime1(arr,k){ 153 | k = k-1 154 | const target = [] 155 | const n = arr.length 156 | for(let i =0;i v) 52 | .map((v) => v.split(' ').map((v) => parseInt(v))) 53 | let area = 0 54 | let y = 0 55 | let x = 0 56 | for (let i = 0; i < total; i++) { 57 | const [x1, y1] = reset[i] 58 | // 竖着的每一块长方形,注意y有可能是负数 59 | area += (x1 - x) * Math.abs(y) 60 | // 记录x和y,以便下一次遍历用 61 | x = x1 62 | y += y1 63 | } 64 | // 最后一块 65 | return area + (len - x) * Math.abs(y) 66 | } 67 | 68 | console.log( 69 | clac(`4 10 70 | 1 1 71 | 2 1 72 | 3 1 73 | 4 -2`) 74 | ) 75 | 76 | console.log( 77 | clac(`2 4 78 | 0 1 79 | 2 -2`) 80 | ) 81 | 82 | ``` -------------------------------------------------------------------------------- /interview/简历格式生成.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /interview/简历格式生成.js: -------------------------------------------------------------------------------- 1 | 2 | const fs = require('fs') 3 | const path = require('path') 4 | 5 | function generateResume(str){ 6 | // '---[1:2][1:1:1]---' 7 | let ret = [] 8 | // console.l 9 | let i = 0 10 | console.log(str.length) 11 | while(i{ 29 | if(item==='-'){ 30 | return `
` 31 | }else{ 32 | console.log(item) 33 | return `
34 | ${item.map(v=>`
`).join('')} 35 |
` 36 | } 37 | }) 38 | const tmpl = ` 39 | 40 | 41 | 42 | 43 | 44 | Document 45 | 57 | 58 | 59 |
60 | ${ret.join('\n')} 61 |
62 | 63 | 64 | ` 65 | let p = path.resolve(__dirname,filename) 66 | fs.writeFileSync(p,tmpl,'utf-8' ) 67 | } 68 | generateResume('---[1:2][1:1:1]---') -------------------------------------------------------------------------------- /linklist/141.环形链表.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | 9 | /** 10 | * @param {ListNode} head 11 | * @return {boolean} 12 | */ 13 | var hasCycle = function(head) { 14 | 15 | // let cache = new Set() 16 | // while(head){ 17 | // if(cache.has(head)){ 18 | // return true 19 | // }else{ 20 | // cache.add(head) 21 | // } 22 | // head = head.next 23 | // } 24 | // return false 25 | 26 | let slow = head 27 | let fast = head 28 | while(fast && fast.next){ 29 | fast = fast.next.next 30 | slow = slow.next 31 | if(slow===fast) return true 32 | } 33 | return false 34 | 35 | }; 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /linklist/142.环形链表-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=142 lang=javascript 3 | * 4 | * [142] 环形链表 II 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val) { 11 | * this.val = val; 12 | * this.next = null; 13 | * } 14 | */ 15 | 16 | /** 17 | * @param {ListNode} head 18 | * @return {ListNode} 19 | */ 20 | var detectCycle = function(head) { 21 | 22 | // a --b--*-- 23 | // ---------| | 24 | // ---c---- 25 | // // 2(a+b) = a+b+圈*n 26 | // fst走过的路: a+b+n(b+c) 27 | // slow 2(a+b) 28 | // a+b = n(b+c) 29 | // 想找a 30 | // a = n(b+c)-b 31 | // a = (n-1)(b+c)+c 32 | 33 | if(head==null){ 34 | return null 35 | } 36 | let slow = head 37 | let fast = head 38 | while(fast!==null){ 39 | slow = slow.next 40 | if(fast.next!=null){ 41 | fast = fast.next.next 42 | }else{ 43 | return null 44 | } 45 | if(fast===slow){ 46 | let cur = head 47 | while(cur!==slow){ 48 | cur = cur.next 49 | slow = slow.next 50 | } 51 | return cur 52 | } 53 | } 54 | return null 55 | }; 56 | // @lc code=end 57 | 58 | -------------------------------------------------------------------------------- /linklist/146.lru-缓存.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=146 lang=javascript 3 | * 4 | * [146] LRU 缓存 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} capacity 10 | */ 11 | // Vue3的keepalive组件就用了这个LRU管理组件的缓存 12 | var LRUCache = function (capacity) { 13 | this.map = new Map() 14 | this.capacity = capacity 15 | } 16 | 17 | /** 18 | * @param {number} key 19 | * @return {number} 20 | */ 21 | LRUCache.prototype.get = function (key) { 22 | if (this.map.has(key)) { 23 | let value = this.map.get(key) 24 | // 重新set,相当于更新到 map最后 25 | this.map.delete(key) 26 | this.map.set(key, value) 27 | return value 28 | } else { 29 | return -1 30 | } 31 | 32 | } 33 | /** 34 | * @param {number} key 35 | * @param {number} value 36 | * @return {void} 37 | */ 38 | LRUCache.prototype.put = function (key, value) { 39 | // 如果有,就删了再赋值 40 | if (this.map.has(key)) { 41 | this.map.delete(key) 42 | } 43 | this.map.set(key, value) 44 | // 判断是不是容量超了,淘汰机制 45 | if (this.map.size > this.capacity) { 46 | this.map.delete(this.map.keys().next().value) 47 | } 48 | } 49 | 50 | /** 51 | * Your LRUCache object will be instantiated and called as such: 52 | * var obj = new LRUCache(capacity) 53 | * var param_1 = obj.get(key) 54 | * obj.put(key,value) 55 | */ 56 | // @lc code=end 57 | 58 | -------------------------------------------------------------------------------- /linklist/160.相交链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=160 lang=javascript 3 | * 4 | * [160] 相交链表 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val) { 11 | * this.val = val; 12 | * this.next = null; 13 | * } 14 | */ 15 | 16 | /** 17 | * @param {ListNode} headA 18 | * @param {ListNode} headB 19 | * @return {ListNode} 20 | */ 21 | var getIntersectionNode = function(headA, headB) { 22 | // if(headA===null || headB===null){ 23 | // return null 24 | // } 25 | let curA = headA 26 | let curB = headB 27 | while(curA!==curB){ 28 | curA = curA===null ? headB:curA.next 29 | curB = curB===null ? headA:curB.next 30 | } 31 | return curA 32 | 33 | // while(headA) 34 | // while(headB) 35 | 36 | // 1=>2=>3=>4 37 | // 5=>3=>4 38 | 39 | // 1=>2=>3=>4=>5=>3=>4 40 | // 5=>3=>4=>1=>2=>3=>4 41 | 42 | }; 43 | // @lc code=end 44 | 45 | -------------------------------------------------------------------------------- /linklist/19.删除链表的倒数第-n-个结点.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=19 lang=javascript 3 | * 4 | * [19] 删除链表的倒数第 N 个结点 5 | */ 6 | 7 | 8 | // @lc code=start 9 | /** 10 | * Definition for singly-linked list. 11 | * function ListNode(val, next) { 12 | * this.val = (val===undefined ? 0 : val) 13 | * this.next = (next===undefined ? null : next) 14 | * } 15 | */ 16 | /** 17 | * @param {ListNode} head 18 | * @param {number} n 19 | * @return {ListNode} 20 | */ 21 | var removeNthFromEnd = function(head, n) { 22 | // 100 10 23 | // // 先走10个节点 24 | // 然后fast slow一起走 25 | 26 | // let dummy = new ListNode(null,head) 27 | let dummy = { 28 | next:head 29 | } 30 | let slow = fast = dummy 31 | while(n--){ 32 | fast = fast.next 33 | } 34 | while(fast.next!==null){ 35 | fast = fast.next 36 | slow = slow.next 37 | } 38 | slow.next = slow.next.next 39 | return dummy.next 40 | }; 41 | // @lc code=end 42 | 43 | -------------------------------------------------------------------------------- /linklist/203.移除链表元素.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val, next) { 4 | * this.val = (val===undefined ? 0 : val) 5 | * this.next = (next===undefined ? null : next) 6 | * } 7 | */ 8 | /** 9 | * @param {ListNode} head 10 | * @param {number} val 11 | * @return {ListNode} 12 | */ 13 | // head.next 14 | var removeElements = function(head, val) { 15 | // if(head ==null){ 16 | // return head 17 | // } 18 | // head.next = removeElements(head.next,val) 19 | // // return head.val ===val?head.next : head 20 | // 哨兵=>1=>2=>3=>4 val2 21 | 22 | // return 哨兵.next 23 | 24 | let ele = { 25 | next:head 26 | } 27 | let p =ele 28 | while(p.next){ 29 | if(p.next.val ===val){ 30 | p.next = p.next.next 31 | }else{ 32 | p = p.next 33 | } 34 | } 35 | return ele.next 36 | }; 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /linklist/206.反转链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=206 lang=javascript 3 | * 4 | * [206] 反转链表 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val, next) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.next = (next===undefined ? null : next) 13 | * } 14 | */ 15 | /** 16 | * @param {ListNode} head 17 | * @return {ListNode} 18 | */ 19 | // cur 20 | // head-->b-->c 21 | 22 | // b.next = c 取消 23 | // b.next = head (prev获取遍历的上一个节点) 24 | 25 | // c-->b-->head 26 | 27 | // prev->cur->next 28 | 29 | var reverseList = function(head) { 30 | if(!head || !head.next){ 31 | return head 32 | } 33 | let prev = null 34 | let cur = head 35 | while(cur){ 36 | // prev 上一个遍历的cur 也就是上一个节点 37 | [cur.next,prev,cur] = [prev,cur,cur.next] 38 | 39 | // let next = cur.next 40 | // cur.next = prev 41 | // prev = cur //缓存上一次遍历的current 42 | // cur = next //游标向下走 43 | } 44 | return prev 45 | }; 46 | // @lc code=end 47 | 48 | -------------------------------------------------------------------------------- /linklist/21.合并两个有序链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=21 lang=javascript 3 | * 4 | * [21] 合并两个有序链表 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val, next) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.next = (next===undefined ? null : next) 13 | * } 14 | */ 15 | /** 16 | * @param {ListNode} list1 17 | * @param {ListNode} list2 18 | * @return {ListNode} 19 | */ 20 | var mergeTwoLists = function(list1, list2) { 21 | // 遍历两个了链表,每次判断节点头部的大小 22 | // 优先把小的追加到新的链表 23 | let dummy = { 24 | next:null 25 | } 26 | let tmp = dummy 27 | while(list1!=null && list2!=null){ 28 | if(list1.val<=list2.val){ 29 | tmp.next = list1 30 | list1 = list1.next 31 | }else{ 32 | tmp.next = list2 33 | list2 = list2.next 34 | } 35 | tmp = tmp.next 36 | } 37 | tmp.next = list1===null ?list2:list1 38 | return dummy.next 39 | }; 40 | // @lc code=end 41 | 42 | -------------------------------------------------------------------------------- /linklist/234.回文链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=234 lang=javascript 3 | * 4 | * [234] 回文链表 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val, next) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.next = (next===undefined ? null : next) 13 | * } 14 | */ 15 | /** 16 | * @param {ListNode} head 17 | * @return {boolean} 18 | */ 19 | var isPalindrome = function(head) { 20 | // 通过双指针,把前半截翻转了 21 | // | 22 | // 2 1 2 1 23 | let slow = fast = head 24 | let prev 25 | 26 | while(fast && fast.next){ 27 | fast = fast.next.next 28 | 29 | let next = slow.next 30 | slow.next = prev 31 | prev = slow 32 | slow = next // slow = slow.next 33 | } 34 | 35 | // 21321 36 | // slow在中间 37 | if(fast){ 38 | slow = slow.next //奇数个节点 39 | } 40 | while(prev && slow){ 41 | if(prev.val!==slow.val){ 42 | return false 43 | } 44 | prev = prev.next 45 | slow = slow.next 46 | } 47 | return true 48 | }; 49 | // @lc code=end 50 | 51 | -------------------------------------------------------------------------------- /linklist/876.链表的中间结点.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=876 lang=javascript 3 | * 4 | * [876] 链表的中间结点 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val, next) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.next = (next===undefined ? null : next) 13 | * } 14 | */ 15 | /** 16 | * @param {ListNode} head 17 | * @return {ListNode} 18 | */ 19 | var middleNode = function(head) { 20 | let slow = fast = head 21 | while(fast && fast.next){ 22 | slow = slow.next 23 | fast = fast.next.next 24 | } 25 | return slow 26 | }; 27 | // @lc code=end 28 | 29 | -------------------------------------------------------------------------------- /linklist/92.反转链表-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=92 lang=javascript 3 | * 4 | * [92] 反转链表 II 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val, next) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.next = (next===undefined ? null : next) 13 | * } 14 | */ 15 | /** 16 | * @param {ListNode} head 17 | * @param {number} left 18 | * @param {number} right 19 | * @return {ListNode} 20 | */ 21 | var reverseBetween = function(head, left, right) { 22 | 23 | // if(left>=right){ 24 | // return head 25 | // } 26 | let dummy ={ 27 | next:head 28 | } 29 | let tmp = dummy 30 | for(let i=0;igetNum(n) =>getNum(getNum(n)) 21 | // 环形链表 22 | var isHappy = function(n){ 23 | let slow = n 24 | let fast = n 25 | if(n===1){ 26 | return true 27 | } 28 | while(fast!==1 && getNum(fast)!==1){ 29 | slow = getNum(slow) 30 | fast = getNum(getNum(fast)) 31 | if(slow===fast){ 32 | return false 33 | } 34 | } 35 | return true 36 | } 37 | var isHappy1 = function(n) { 38 | let obj = {} 39 | // let map = new Map() 40 | while(true){ 41 | if(n in obj){ 42 | return false 43 | } 44 | if(n==1) { 45 | return true 46 | } 47 | obj[n] = true 48 | n = getNum(n) 49 | } 50 | }; 51 | // @lc code=end 52 | 53 | -------------------------------------------------------------------------------- /other/242.有效的字母异位词.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=242 lang=javascript 3 | * 4 | * [242] 有效的字母异位词 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} s 10 | * @param {string} t 11 | * @return {boolean} 12 | */ 13 | var isAnagram = function(s, t) { 14 | // ratr 15 | // car 16 | // charCodeAt() 17 | // [1,0,,,,,,,2,,,] 18 | // b 19 | if(s.length!==t.length){ 20 | return false 21 | } 22 | let obj = {} 23 | 24 | // let arr = new Array(26).fill(0) 25 | // let base = 'a'.charCodeAt(0) 26 | for(let i=0;iobj[k]===0) 39 | }; 40 | // @lc code=end 41 | 42 | -------------------------------------------------------------------------------- /other/292.nim-游戏.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=292 lang=javascript 3 | * 4 | * [292] Nim 游戏 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} n 10 | * @return {boolean} 11 | */ 12 | var canWinNim = function(n) { 13 | // 4 14 | // 4 15 | // 5 16 | // 1 13 22 3 1 17 | return n%4!==0 18 | }; 19 | // @lc code=end 20 | 21 | -------------------------------------------------------------------------------- /other/326.3-的幂.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=326 lang=javascript 3 | * 4 | * [326] 3 的幂 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} n 10 | * @return {boolean} 11 | */ 12 | var isPowerOfThree = function(n) { 13 | return n>0 && 1162261467%n==0 14 | }; 15 | // @lc code=end 16 | 17 | -------------------------------------------------------------------------------- /other/383.赎金信.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=383 lang=javascript 3 | * 4 | * [383] 赎金信 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} ransomNote 10 | * @param {string} magazine 11 | * @return {boolean} 12 | */ 13 | var canConstruct = function(ransomNote, magazine) { 14 | let arr = new Array(26).fill(0) 15 | let base = 'a'.charCodeAt(0) 16 | for(const m of magazine){ 17 | arr[m.charCodeAt()-base]++ 18 | } 19 | for(const r of ransomNote){ 20 | arr[r.charCodeAt()-base]-- 21 | } 22 | return arr.every(v=>v>=0) 23 | }; 24 | // @lc code=end 25 | 26 | -------------------------------------------------------------------------------- /other/877.石子游戏.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=877 lang=javascript 3 | * 4 | * [877] 石子游戏 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} piles 10 | * @return {boolean} 11 | */ 12 | var stoneGame = function(piles) { 13 | return true 14 | // [1,4,3,] 15 | // 7 16 | // 13 17 | // 47 18 | }; 19 | // @lc code=end 20 | 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "algorithm", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "vitest" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "vitest": "^0.24.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /recursion/131.分割回文串.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=131 lang=javascript 3 | * 4 | * [131] 分割回文串 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} s 10 | * @return {string[][]} 11 | */ 12 | function isPalindrome(s,l,r){ 13 | for (let i = l,j=r; i < j; i++,j--) { 14 | if(s[i]!==s[j]){ 15 | return false 16 | } 17 | } 18 | return true 19 | } 20 | var partition = function(s) { 21 | // 判断回文 22 | // 分割问题 23 | 24 | // h e l lloworld //排列组合 25 | // aab 26 | // a aa aab 27 | // a b null 28 | // b 29 | let ret = [] 30 | let path = [] 31 | backtrack(0) 32 | return ret 33 | // 从哪切 34 | function backtrack(i){ 35 | if(i>=s.length){ 36 | ret.push([...path]) 37 | return 38 | } 39 | for(let j=i;jtarget){ 22 | return //比traget大了 23 | } 24 | if(sum===target){ 25 | ret.push([...path]) 26 | } 27 | for (let j = i; j < candidates.length; j++) { 28 | // const element = array[j] 29 | let num = candidates[j] 30 | if((num+sum)>target){ 31 | continue 32 | } 33 | path.push(num) 34 | sum+= num 35 | backtrack(j,sum) 36 | path.pop() 37 | sum-=num 38 | } 39 | } 40 | }; 41 | // @lc code=end 42 | 43 | -------------------------------------------------------------------------------- /recursion/46.全排列.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=46 lang=javascript 3 | * 4 | * [46] 全排列 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @return {number[][]} 11 | */ 12 | // 递归公式 13 | // 遍历到3的时候 14 | // temp = [1] 15 | // backtrack 16 | // temp = [1,2] 17 | // backtrack 18 | // [1,2,3] 终止 19 | // temp = [1] 20 | // temp = [1,3,] 21 | function backtrack(list,temp,nums){ 22 | // 1. 终止条件 23 | if(temp.length===nums.length){ 24 | return list.push([...temp]) 25 | } 26 | for(let i =0;ib-a) 15 | 16 | let ret = [] 17 | let path = [] 18 | backtrack([]) 19 | return ret 20 | function backtrack(used){ 21 | if(path.length===nums.length){ 22 | ret.push([...path]) 23 | return 24 | } 25 | for(let i=0;i{ 23 | let arr = new Array(n).fill('.') 24 | arr[c] = 'Q' 25 | return arr.join('') 26 | }) 27 | ) 28 | } 29 | // row 第几行 30 | for (let col = 0; col < n; col++) { 31 | let canNotSet = tmp.some((c,r)=>{ 32 | return c==col || ((r-c)===(row-col)) || ((r+c)===(row+col)) 33 | }) 34 | if(canNotSet){ 35 | continue 36 | } 37 | backtrack(row+1,[...tmp,col]) 38 | 39 | } 40 | } 41 | // r c row col 42 | // r==row c==col r-c==row-col r+c row+col 43 | }; 44 | 45 | // @lc code=end 46 | 47 | -------------------------------------------------------------------------------- /recursion/77.组合.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=77 lang=javascript 3 | * 4 | * [77] 组合 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number} n 10 | * @param {number} k 11 | * @return {number[][]} 12 | */ 13 | var combine = function(n, k) { 14 | let ret = [] 15 | let path = [] //递归的时候用的临时,用来统计[2] 16 | backtrack(n,k,1) 17 | 18 | return ret 19 | function backtrack(n,k,i){ 20 | let len = path.length 21 | if(len===k){ 22 | ret.push([...path]) 23 | return 24 | } 25 | // n=4,k=2 i = 1 len = 0 26 | // 1,2,3 选4,后面就没了 27 | for(let j=i;j<=n-k+len+1;j++ ){ 28 | path.push(j) 29 | backtrack(n,k,j+1) 30 | path.pop() 31 | } 32 | } 33 | // n=4 k=4 34 | // root 35 | // 1, 2, 3, 4 36 | 37 | // 2,3,4, 3,4 [4] 38 | 39 | // 34 40 | // N叉树的遍历 剪枝 41 | // n = 4, k = 2 42 | // root 43 | // [1,2,3,4] 44 | // 1. 取1 [2,3,4] 45 | // 取2 46 | // 3 47 | // 4 48 | // 2. 2 [3,4] 49 | // 3 3 [4] 50 | // 4 4 [] 51 | }; 52 | // @lc code=end 53 | 54 | -------------------------------------------------------------------------------- /recursion/78.子集.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=78 lang=javascript 3 | * 4 | * [78] 子集 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @return {number[][]} 11 | */ 12 | var subsets = function(nums) { 13 | let ret = [] 14 | let path = [] 15 | backtrack(0) 16 | return ret 17 | function backtrack(index){ 18 | ret.push([...path]) 19 | for (let i = index; i < nums.length; i++) { 20 | const num = nums[i] 21 | path.push(num) 22 | backtrack(i+1) //找下一个数组 23 | path.pop() 24 | } 25 | } 26 | }; 27 | // @lc code=end 28 | 29 | -------------------------------------------------------------------------------- /recursion/79.单词搜索.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=79 lang=javascript 3 | * 4 | * [79] 单词搜索 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {character[][]} board 10 | * @param {string} word 11 | * @return {boolean} 12 | */ 13 | 14 | // 输入:board = 15 | // [["A","B","C","E"], 16 | // ["S","F","C","S"], 17 | // ["A","D","E","E"] 18 | // ], word = "ABCCED" 19 | // 输出:true 20 | 21 | var exist = function(board, word) { 22 | // 输入的终止条件 23 | if(board.length===0) { 24 | return false 25 | } 26 | if(word.length===0){ 27 | return true 28 | } 29 | //开始循环找 30 | let row = board.length 31 | let col = board[0].length 32 | for(let i=0;i=row || i<0){ 45 | return false 46 | } 47 | if(j>=col || j<0){ 48 | return false 49 | } 50 | 51 | // if() 52 | let letter = board[i][j] 53 | // 查询结束判断 54 | if(letter!==word[cur]){ 55 | return false 56 | } 57 | if(cur==word.length-1){ 58 | // 最后一个 也是匹配的 59 | return true 60 | } 61 | 62 | board[i][j] = null //选择当前的字母 63 | // 进行下一步 有一个找到就算 64 | const ret = find(i+1,j,cur+1) || 65 | find(i-1,j,cur+1) || 66 | find(i,j+1,cur+1) || 67 | find(i,j-1,cur+1) 68 | board[i][j] = letter //回撤 69 | return ret 70 | } 71 | }; 72 | // @lc code=end 73 | 74 | -------------------------------------------------------------------------------- /recursion/93.复原-ip-地址.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=93 lang=javascript 3 | * 4 | * [93] 复原 IP 地址 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} s 10 | * @return {string[]} 11 | */ 12 | var restoreIpAddresses = function(s) { 13 | // 分割问题 14 | // 101023 15 | // 1| 12| 101| 后面直接终止 16 | // 0| 17 | let ret = [] 18 | let path = [] 19 | backtrack(0) 20 | return ret 21 | 22 | function backtrack(i){ 23 | if(path.length>4){ 24 | return 25 | } 26 | if(path.length===4 && i===s.length){ 27 | ret.push(path.join('.')) 28 | return 29 | } 30 | // 判断终止条件 31 | for(let j=i;j255){ 35 | break 36 | } 37 | if(str.length>1 && str[0]==='0'){ 38 | break 39 | } 40 | path.push(str) 41 | backtrack(j+1) //切下一个 42 | path.pop() 43 | } 44 | } 45 | 46 | }; 47 | // @lc code=end 48 | 49 | -------------------------------------------------------------------------------- /sort/15.三数之和.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=15 lang=javascript 3 | * 4 | * [15] 三数之和 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @return {number[][]} 11 | */ 12 | var threeSum = function(nums) { 13 | // 找到a b c 14 | // 无需的数组里,查找目标和大小相关 就可以看下是否可以利用排序降低复杂度 15 | // 排序 n*lgn 16 | if(nums.length<3){ 17 | return [] 18 | } 19 | let list = [] 20 | // 最小+最大之和,如何比目标值大,说明我们要缩小这个值,最大值左移动 否则,最小右移 21 | // [2,3,4,6,8,-5,7,8] 22 | // 1, 23 | nums.sort((a,b)=>a-b) // n*lgn 24 | for(let i=0;i0){ 48 | // 数字变大了 需要小一些判断 49 | right-- 50 | }else{ 51 | // 数字太小了 52 | left++ 53 | } 54 | } 55 | } 56 | return list 57 | }; 58 | // @lc code=end 59 | 60 | -------------------------------------------------------------------------------- /sort/912.排序数组.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=912 lang=javascript 3 | * 4 | * [912] 排序数组 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {number[]} nums 10 | * @return {number[]} 11 | */ 12 | var sortArray = function(nums) { 13 | 14 | }; 15 | // @lc code=end 16 | 17 | -------------------------------------------------------------------------------- /sort/arr.js: -------------------------------------------------------------------------------- 1 | let arr = [366, 240, 866, 115, 9, 760, 553, 354, 232, 374, 450, 426, 944, 2,393, 143] 2 | module.exports = arr -------------------------------------------------------------------------------- /sort/sort.js: -------------------------------------------------------------------------------- 1 | // 排序 2 | 3 | const arr = require('./arr') 4 | let arrary = require('./arr') 5 | // arr.sort((a,b)=>a-b) 6 | console.log(arrary) 7 | 8 | function bubbleSort(arr){ 9 | // 每个人和右边人比较,如果你比他高,就交换位置,否则就不动 10 | let len = arr.length-1 11 | // O(n^2) 12 | for(let j=0;jarr[i+1]){ 15 | // let tmp = arr[i] 16 | // arr[i] = arr[i+1] 17 | // arr[i+1] = tmp 18 | [arr[i],arr[i+1]] = [arr[i+1],arr[i]] 19 | } 20 | } 21 | } 22 | return arr 23 | } 24 | 25 | // console.log('冒泡排序',bubbleSort(arrary)) 26 | 27 | 28 | // 给数组找一个标志位,比如我,所有人都给我比个头,比我高的,站我右边 29 | // 比我矮的,占我左边 30 | // O(n * lgn) 31 | 32 | function quickSort(arr){ 33 | if(arr.length<2){ 34 | return arr 35 | } 36 | let flag = arr[0] 37 | let left = [] 38 | let right = [] 39 | for(let i=1;iflag){ 41 | right.push(arr[i]) 42 | }else{ 43 | left.push(arr[i]) 44 | } 45 | } 46 | return quickSort(left).concat(flag,quickSort(right)) 47 | } 48 | // console.log('快速排序',quickSort(arrary)) 49 | 50 | // 原地快排 51 | // i-> <-j 52 | // [d,a,b,c,e,f,g,h] 53 | // i找到一个比e打的 54 | // j找到一个比e晓得 55 | // i和j的值交换一下位置 56 | // 到最后i和j遇见 57 | 58 | 空间复杂度变成了O1 59 | function quick1(arr,start,end){ 60 | // 双指针 61 | let init = start 62 | let flag = arr[init] 63 | start++ 64 | while(start<=end){ 65 | while(arr[end]>flag){ 66 | end-- 67 | } 68 | while(arr[start]a+b, 16 | '-':(a,b)=>b-a, 17 | '*':(a,b)=>a*b, 18 | '/':(a,b)=>(b/a)|0, 19 | } 20 | let stack = [] 21 | 22 | for (let i = 0; i < tokens.length; i++) { 23 | const t = tokens[i] 24 | if(t in calc){ 25 | // 增删改查 26 | stack.push(calc[t](stack.pop(),stack.pop())) 27 | }else{ 28 | // 数组 29 | stack.push(Number(t)) 30 | } 31 | 32 | } 33 | return stack.pop() 34 | 35 | // let tmp 36 | // for (let i = 0; i < tokens.length; i++) { 37 | // const t = tokens[i] 38 | // // switch() 39 | // if(t==='+'){ 40 | // tmp = stack.pop()+stack.pop() 41 | // stack.push(tmp) 42 | // }else if(t==='-'){ 43 | // tmp = stack.pop() 44 | // tmp = stack.pop()-tmp 45 | // stack.push(tmp) 46 | // }else if(t==='*'){ 47 | // tmp = stack.pop()*stack.pop() 48 | // stack.push(tmp) 49 | 50 | // }else if(t==='/'){ 51 | // tmp = stack.pop() 52 | // tmp = getNum(stack.pop()/tmp) 53 | // stack.push(tmp) 54 | // }else{ 55 | // stack.push(Number(t)) 56 | // } 57 | // // + - * / 58 | // // else 数字 59 | 60 | // } 61 | // // (2+1)*3 62 | // return stack.pop() 63 | // 2,1 +,3 * 64 | }; 65 | // function getNum(num){ 66 | // return num | 0 //位运算 67 | // return Number(num.toString().split('.')[0]) 68 | // } 69 | // @lc code=end 70 | 71 | -------------------------------------------------------------------------------- /stack/151.颠倒字符串中的单词.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=151 lang=javascript 3 | * 4 | * [151] 颠倒字符串中的单词 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} s 10 | * @return {string} 11 | */ 12 | var reverseWords = function(s) { 13 | // return s.trim().split(' ').filter(v=>v).reverse().join(' ') 14 | let left = 0 15 | let right = s.length-1 16 | let queue = [] 17 | let word = '' 18 | while(s.charAt(left)===' '){ 19 | left++ 20 | } 21 | while(s.charAt(right)===' '){ 22 | right-- 23 | } 24 | while(left <=right){ 25 | let ch = s.charAt(left) 26 | if(ch==' ' && word){ 27 | queue.unshift(word) 28 | word = '' 29 | }else if(ch!==' '){ 30 | word += ch 31 | } 32 | left ++ 33 | } 34 | queue.unshift(word) 35 | return queue.join(' ') 36 | // return s.trim().split(' ').reverse().join(' ') 37 | }; 38 | // @lc code=end 39 | 40 | -------------------------------------------------------------------------------- /stack/20.有效的括号.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=20 lang=javascript 3 | * 4 | * [20] 有效的括号 5 | */ 6 | 7 | 8 | // @lc code=start 9 | /** 10 | * @param {string} s 11 | * @return {boolean} 12 | */ 13 | var isValid = function(s) { 14 | let stack = [] 15 | let obj = { 16 | '(':')', 17 | '[':']', 18 | '{':'}' 19 | } 20 | for(let i=0;i1){ 35 | this.queue2.push(this.queue1.shift()) 36 | } 37 | // 1. 队列1有数据,队列1清空,备份到队列2 38 | // 2、 队列1没有数据 两个队列交换后 弹出数据 39 | return this.queue1.shift() 40 | }; 41 | 42 | /** 43 | * @return {number} 44 | */ 45 | MyStack.prototype.top = function() { 46 | const x = this.pop() 47 | this.queue1.push(x) 48 | return x 49 | }; 50 | 51 | /** 52 | * @return {boolean} 53 | */ 54 | MyStack.prototype.empty = function() { 55 | return !this.queue1.length && !this.queue2.length 56 | }; 57 | 58 | /** 59 | * Your MyStack object will be instantiated and called as such: 60 | * var obj = new MyStack() 61 | * obj.push(x) 62 | * var param_2 = obj.pop() 63 | * var param_3 = obj.top() 64 | * var param_4 = obj.empty() 65 | */ 66 | // @lc code=end 67 | 68 | -------------------------------------------------------------------------------- /stack/232.用栈实现队列.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=232 lang=javascript 3 | * 4 | * [232] 用栈实现队列 5 | */ 6 | 7 | // @lc code=start 8 | // push pop() 9 | 10 | // push shift 11 | var MyQueue = function() { 12 | // [] 1 13 | // [3,2]2 3 14 | this.stackIn = [] 15 | this.stackOut = [] 16 | }; 17 | 18 | /** 19 | * @param {number} x 20 | * @return {void} 21 | */ 22 | MyQueue.prototype.push = function(x) { 23 | this.stackIn.push(x) 24 | }; 25 | 26 | /** 27 | * @return {number} 28 | */ 29 | MyQueue.prototype.pop = function() { 30 | if(this.stackOut.length){ 31 | return this.stackOut.pop() 32 | } 33 | while(this.stackIn.length){ 34 | this.stackOut.push(this.stackIn.pop()) 35 | } 36 | return this.stackOut.pop() 37 | }; 38 | 39 | /** 40 | * @return {number} 41 | */ 42 | MyQueue.prototype.peek = function() { 43 | let x = this.pop() 44 | this.stackOut.push(x) 45 | return x 46 | }; 47 | 48 | /** 49 | * @return {boolean} 50 | */ 51 | MyQueue.prototype.empty = function() { 52 | return !this.stackIn.length && !this.stackOut.length 53 | }; 54 | 55 | /** 56 | * Your MyQueue object will be instantiated and called as such: 57 | * var obj = new MyQueue() 58 | * obj.push(x) 59 | * var param_2 = obj.pop() 60 | * var param_3 = obj.peek() 61 | * var param_4 = obj.empty() 62 | */ 63 | // @lc code=end 64 | 65 | -------------------------------------------------------------------------------- /stack/71.简化路径.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=71 lang=javascript 3 | * 4 | * [71] 简化路径 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * @param {string} path 10 | * @return {string} 11 | */ 12 | var simplifyPath = function(path) { 13 | // "/a/./b/../../c/" 14 | let stack = [] 15 | let paths = path.split('/') 16 | for (let i = 0; i < paths.length; i++) { 17 | const p = paths[i] 18 | if(p=='..'){ 19 | stack.pop() 20 | }else if(p && p!=='.'){ 21 | stack.push(p) 22 | } 23 | } 24 | return '/'+stack.join('/') 25 | }; 26 | // @lc code=end 27 | 28 | -------------------------------------------------------------------------------- /tips.md: -------------------------------------------------------------------------------- 1 | # 刷题章节 2 | 3 | 150题左右 4 | 5 | ## 数据结构 6 | 1. 链表 7 | ```js 8 | 遍历 9 | while(head){ 10 | head = head.next 11 | } 12 | return head 13 | 14 | let dummny = { 15 | next:head 16 | } 17 | ... 18 | return dummny.next 19 | 20 | ``` 21 | 2. 数组 22 | ```js 23 | for(let i=0;i>1 75 | if(arr[mid]>1 82 | if(arr[mid] 130 | // 边界条件 131 | // 循环: 132 | // 递推公式 133 | // 循环硬币 134 | // dp[n] n的钱数下,返回零钱的最优解 135 | 136 | 1. 暴力解(画图) 137 | 2. 研究优化,加备忘录 138 | 3. 递推 139 | 140 | 1. 贪心 141 | 没有公式 142 | 6. bfs(宽度/广度优先) dfs(回溯,深度有限) 143 | 144 | 其他 145 | 1. bfs 146 | 2. 位运算 147 | 148 | ## 题型 149 | 1. 盛水 150 | 2. 炒股 151 | 3. 打劫 152 | .... 153 | 154 | 155 | 156 | 157 | # 扩展 158 | 159 | 1. 图 160 | 2. 哈希表 161 | 3. 。。。。 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /tree/100.相同的树.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=100 lang=javascript 3 | * 4 | * [100] 相同的树 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} p 18 | * @param {TreeNode} q 19 | * @return {boolean} 20 | */ 21 | // var isSameTree = function(p, q) { 22 | // if(p===null&&q===null){ 23 | // return true 24 | // } 25 | // if(p===null||q===null){ 26 | // return false 27 | // } 28 | // if(p.val!==q.val){ 29 | // return false 30 | // } 31 | // return isSameTree(p.left,q.left) && isSameTree(p.right,q.right) 32 | // }; 33 | // var isSameTree = function(p,q){ 34 | // function travese(p,q){ 35 | // if(p===null&&q===null){ 36 | // return true 37 | // } 38 | // if(p===null||q===null){ 39 | // return false 40 | // } 41 | // let left = travese(p.left,q.left) 42 | // let right = travese(p.right,q.right) 43 | // if(p.val===q.val &&left && right){ 44 | // return true 45 | // } 46 | // return false 47 | // } 48 | // return travese(p,q) 49 | // } 50 | 51 | // var isSameTree = function(p,q){ 52 | // return JSON.stringify(p)===JSON.stringify(q) 53 | // } 54 | var isSameTree1 = function(p,q){ 55 | // 迭代 56 | if(p===null&&q===null){ 57 | return true 58 | } 59 | if(p===null||q===null){ 60 | return false 61 | } 62 | let queueP = [p] 63 | let queueQ = [q] 64 | while(queueP.length && queueQ.length){ 65 | const nodeP = queueP.shift() 66 | const nodeQ = queueQ.shift() 67 | if(nodeP.val!==nodeQ.val){ 68 | return false 69 | } 70 | if(nodeP.left && nodeQ.left){ 71 | queueP.push(nodeP.left) 72 | queueQ.push(nodeQ.left) 73 | }else if(nodeP.left || nodeQ.left){ 74 | return false 75 | } 76 | 77 | if(nodeP.right && nodeQ.right){ 78 | queueP.push(nodeP.right) 79 | queueQ.push(nodeQ.right) 80 | }else if(nodeP.right || nodeQ.right){ 81 | return false 82 | } 83 | } 84 | return true 85 | } 86 | // @lc code=end 87 | 88 | -------------------------------------------------------------------------------- /tree/101.对称二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=101 lang=javascript 3 | * 4 | * [101] 对称二叉树 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {boolean} 19 | */ 20 | var isSymmetric = function(root) { 21 | const travese = (root1,root2)=>{ 22 | if(root1===null&&root2===null){ 23 | return true 24 | } 25 | if(root1===null||root2===null){ 26 | return false 27 | } 28 | if(root1.val===root2.val){ 29 | return travese(root1.left,root2.right) && travese(root1.right,root2.left) 30 | } 31 | return false 32 | } 33 | 34 | return travese(root.left,root.right) 35 | }; 36 | // @lc code=end 37 | 38 | -------------------------------------------------------------------------------- /tree/102.二叉树的层序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=102 lang=javascript 3 | * 4 | * [102] 二叉树的层序遍历 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number[][]} 19 | */ 20 | // [3] 1 21 | // [9,20] 2 22 | 23 | 24 | 25 | var levelOrder = function(root) { 26 | let ret = [] //结果 27 | if(root===null){ 28 | return ret 29 | } 30 | let queue = [root] //遍历中用的队列 31 | while(queue.length){ 32 | let len = queue.length //一层的数据量 33 | let curLevel = [] 34 | while(len>0){ 35 | let node = queue.shift() 36 | curLevel.push(node.val) 37 | node.left && queue.push(node.left) 38 | node.right && queue.push(node.right) 39 | len-- 40 | } 41 | ret.push(curLevel) 42 | } 43 | return ret 44 | }; 45 | // @lc code=end 46 | 47 | -------------------------------------------------------------------------------- /tree/104.二叉树的最大深度.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val, left, right) { 4 | * this.val = (val===undefined ? 0 : val) 5 | * this.left = (left===undefined ? null : left) 6 | * this.right = (right===undefined ? null : right) 7 | * } 8 | */ 9 | /** 10 | * @param {TreeNode} root 11 | * @return {number} 12 | */ 13 | var maxDepth = function(root) { 14 | //终止条件 15 | if(root==null){ 16 | return 0 17 | } 18 | // 树最大深度,等于 左子树的深度 和右子树的深度,最大的那一个+1 19 | return Math.max(maxDepth(root.left),maxDepth(root.right))+1 20 | }; 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /tree/107.二叉树的层序遍历-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=107 lang=javascript 3 | * 4 | * [107] 二叉树的层序遍历 II 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number[][]} 19 | */ 20 | var levelOrderBottom = function(root) { 21 | let ret = [] //结果 22 | if(root===null){ 23 | return ret 24 | } 25 | let queue = [root] //遍历中用的队列 26 | while(queue.length){ 27 | let len = queue.length //一层的数据量 28 | let curLevel = [] 29 | while(len>0){ 30 | let node = queue.shift() 31 | curLevel.push(node.val) 32 | node.left && queue.push(node.left) 33 | node.right && queue.push(node.right) 34 | len-- 35 | } 36 | ret.unshift(curLevel) 37 | } 38 | return ret 39 | }; 40 | // @lc code=end 41 | 42 | -------------------------------------------------------------------------------- /tree/108.将有序数组转换为二叉搜索树.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=108 lang=javascript 3 | * 4 | * [108] 将有序数组转换为二叉搜索树 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {number[]} nums 18 | * @return {TreeNode} 19 | */ 20 | var sortedArrayToBST = function(nums) { 21 | if(!nums.length){ 22 | return null 23 | } 24 | // 二叉搜索树的中序遍历,就是升序列表 25 | // 数组中间的位置,可以作为树的根节点 26 | const mid = Math.floor(nums.length/2) 27 | const root = new TreeNode(nums[mid]) 28 | root.left = sortedArrayToBST(nums.slice(0,mid)) 29 | root.right = sortedArrayToBST(nums.slice(mid+1)) 30 | return root 31 | }; 32 | // @lc code=end 33 | 34 | -------------------------------------------------------------------------------- /tree/109.有序链表转换二叉搜索树.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=109 lang=javascript 3 | * 4 | * [109] 有序链表转换二叉搜索树 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val, next) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.next = (next===undefined ? null : next) 13 | * } 14 | */ 15 | /** 16 | * Definition for a binary tree node. 17 | * function TreeNode(val, left, right) { 18 | * this.val = (val===undefined ? 0 : val) 19 | * this.left = (left===undefined ? null : left) 20 | * this.right = (right===undefined ? null : right) 21 | * } 22 | */ 23 | /** 24 | * @param {ListNode} head 25 | * @return {TreeNode} 26 | */ 27 | var sortedListToBST = function(head) { 28 | // let arr = [] 29 | // let cur = head 30 | // while(cur){ 31 | // arr.push(cur.val) 32 | // cur = cur.next 33 | // } 34 | // return sortedArrayToBST(arr) 35 | // 快慢指针 36 | function travese(head,tail){ 37 | if(head===tail){ 38 | return null 39 | } 40 | let slow = fast = head 41 | while(fast!==tail && fast.next!==tail){ 42 | slow = slow.next 43 | fast = fast.next.next 44 | } 45 | let root = new TreeNode(slow.val) 46 | root.left = travese(head,slow) 47 | root.right = travese(slow.next,tail) 48 | return root 49 | } 50 | return travese(head,null) 51 | }; 52 | // var sortedArrayToBST = function(nums) { 53 | // if(!nums.length){ 54 | // return null 55 | // }s 56 | // // 二叉搜索树的中序遍历,就是升序列表 57 | // // 数组中间的位置,可以作为树的根节点 58 | // const mid = Math.floor(nums.length/2) 59 | // const root = new TreeNode(nums[mid]) 60 | // root.left = sortedArrayToBST(nums.slice(0,mid)) 61 | // root.right = sortedArrayToBST(nums.slice(mid+1)) 62 | // return root 63 | // }; 64 | // @lc code=end 65 | 66 | -------------------------------------------------------------------------------- /tree/110.平衡二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=110 lang=javascript 3 | * 4 | * [110] 平衡二叉树 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {boolean} 19 | */ 20 | // -1 21 | var isBalanced = function(root) { 22 | function travese(node){ 23 | if(node===null){ 24 | return 0 25 | } 26 | let leftDepth = travese(node.left) 27 | if(leftDepth===-1){ 28 | return -1 29 | } 30 | let rightDepth = travese(node.right) 31 | if(rightDepth===-1){ 32 | return -1 33 | } 34 | if(Math.abs(leftDepth-rightDepth)>1){ 35 | return -1 36 | }else{ 37 | return 1 + Math.max(leftDepth,rightDepth) 38 | } 39 | } 40 | 41 | return travese(root)!==-1 42 | 43 | }; 44 | // @lc code=end 45 | 46 | -------------------------------------------------------------------------------- /tree/111.二叉树的最小深度.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=111 lang=javascript 3 | * 4 | * [111] 二叉树的最小深度 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number} 19 | */ 20 | // var minDepth = function(root) { 21 | // if(root===null){ 22 | // return 0 23 | // } 24 | // if(root.left===null && root.right===null){ 25 | // return 1 26 | // } 27 | // if(root.left===null){ 28 | // return 1+minDepth(root.right) 29 | // } 30 | // if(root.right===null){ 31 | // return 1+minDepth(root.left) 32 | // } 33 | // return Math.min(minDepth(root.left),minDepth(root.right))+1 34 | // }; 35 | var minDepth = function(root){ 36 | if(root==null){ 37 | return 0 38 | } 39 | // 需要一个记录层级的变量 40 | let dep = 0 41 | const stack = [root] 42 | 43 | while(true){ 44 | let size = stack.length 45 | dep++ 46 | // 精确的控制遍历的个数 47 | while(size--){ 48 | let node = stack.shift() 49 | 50 | if(!node.left && !node.right){ 51 | return dep 52 | } 53 | node.left && stack.push(node.left) 54 | node.right && stack.push(node.right) 55 | } 56 | } 57 | 58 | } 59 | // @lc code=end 60 | 61 | -------------------------------------------------------------------------------- /tree/112.路径总和.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=112 lang=javascript 3 | * 4 | * [112] 路径总和 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @param {number} targetSum 19 | * @return {boolean} 20 | */ 21 | var hasPathSum = function(root, targetSum) { 22 | 23 | if(root==null){ 24 | return false 25 | } 26 | if(!root.left && !root.right){ 27 | return root.val ===targetSum 28 | } 29 | let offset = targetSum - root.val 30 | return hasPathSum(root.left,offset) || hasPathSum(root.right,offset) 31 | }; 32 | // @lc code=end 33 | 34 | -------------------------------------------------------------------------------- /tree/114.二叉树展开为链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=114 lang=javascript 3 | * 4 | * [114] 二叉树展开为链表 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {void} Do not return anything, modify root in-place instead. 19 | */ 20 | var flatten = function(root) { 21 | let list = [] 22 | preTravese(root,list) 23 | 24 | for(let i=1;i0){ 35 | //不是最后一个 36 | node.next = queue[0] 37 | } 38 | node.left && queue.push(node.left) 39 | node.right && queue.push(node.right) 40 | } 41 | } 42 | return root 43 | }; 44 | // @lc code=end 45 | 46 | -------------------------------------------------------------------------------- /tree/117.填充每个节点的下一个右侧节点指针-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=117 lang=javascript 3 | * 4 | * [117] 填充每个节点的下一个右侧节点指针 II 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * // Definition for a Node. 10 | * function Node(val, left, right, next) { 11 | * this.val = val === undefined ? null : val; 12 | * this.left = left === undefined ? null : left; 13 | * this.right = right === undefined ? null : right; 14 | * this.next = next === undefined ? null : next; 15 | * }; 16 | */ 17 | 18 | /** 19 | * @param {Node} root 20 | * @return {Node} 21 | */ 22 | var connect = function(root) { 23 | if(root===null){ 24 | return root 25 | } 26 | let queue = [root] 27 | while(queue.length){ 28 | let len = queue.length 29 | while(len--){ 30 | let node = queue.shift() 31 | if(len>0){ 32 | //不是最后一个 33 | node.next = queue[0] 34 | } 35 | node.left && queue.push(node.left) 36 | node.right && queue.push(node.right) 37 | } 38 | } 39 | return root 40 | }; 41 | // @lc code=end 42 | 43 | -------------------------------------------------------------------------------- /tree/136.只出现一次的数字.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var singleNumber = function(nums) { 6 | let ret = 0 7 | nums.forEach(num=>{ 8 | ret ^= num 9 | }) 10 | return ret 11 | }; -------------------------------------------------------------------------------- /tree/144.二叉树的前序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=144 lang=javascript 3 | * 4 | * [144] 二叉树的前序遍历 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number[]} 19 | */ 20 | // var preorderTraversal1 = function(root) { 21 | // let arr = [] 22 | // // travese, walk 23 | // function dfs(root){ 24 | // if(root==null){ 25 | // return 26 | // } 27 | // arr.push(root.val) 28 | // dfs(root.left) 29 | // dfs(root.right) 30 | // } 31 | // dfs(root) 32 | // return arr 33 | // } 34 | var preorderTraversal = function(root){ 35 | let res = [] 36 | if(root===null){ 37 | return res 38 | } 39 | let stack = [root] 40 | while(stack.length){ 41 | let cur = stack.pop() 42 | res.push(cur.val) 43 | cur.right&& stack.push(cur.right) 44 | cur.left&& stack.push(cur.left) 45 | } 46 | return res 47 | } 48 | // @lc code=end 49 | 50 | -------------------------------------------------------------------------------- /tree/145.二叉树的后序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=145 lang=javascript 3 | * 4 | * [145] 二叉树的后序遍历 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number[]} 19 | */ 20 | var postorderTraversal = function(root) { 21 | let arr = [] 22 | function dfs(root){ 23 | if(root==null){ 24 | return 25 | } 26 | dfs(root.left) 27 | dfs(root.right) 28 | arr.push(root.val) 29 | } 30 | dfs(root) 31 | return arr 32 | }; 33 | // @lc code=end 34 | 35 | -------------------------------------------------------------------------------- /tree/199.二叉树的右视图.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=199 lang=javascript 3 | * 4 | * [199] 二叉树的右视图 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number[]} 19 | */ 20 | var rightSideView = function(root) { 21 | // 每一层最右边的一个值 22 | let ret = [] 23 | if(root===null){ 24 | return ret 25 | } 26 | let queue = [root] 27 | 28 | while(queue.length){ 29 | let len = queue.length 30 | while(len--){ 31 | let node = queue.shift() 32 | if(len===0){ 33 | ret.push(node.val) 34 | } 35 | node.left && queue.push(node.left) 36 | node.right && queue.push(node.right) 37 | } 38 | 39 | } 40 | 41 | return ret 42 | }; 43 | // @lc code=end 44 | 45 | -------------------------------------------------------------------------------- /tree/222.完全二叉树的节点个数.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=222 lang=javascript 3 | * 4 | * [222] 完全二叉树的节点个数 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number} 19 | */ 20 | var countNodes = function(root) { 21 | function travese(node){ 22 | if(node===null){ 23 | return 0 24 | } 25 | let leftNum = travese(node.left) 26 | let rightNum = travese(node.right) 27 | return leftNum + rightNum +1 28 | } 29 | return travese(root) 30 | }; 31 | // @lc code=end 32 | 33 | -------------------------------------------------------------------------------- /tree/226.翻转二叉树.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val, left, right) { 4 | * this.val = (val===undefined ? 0 : val) 5 | * this.left = (left===undefined ? null : left) 6 | * this.right = (right===undefined ? null : right) 7 | * } 8 | */ 9 | /** 10 | * @param {TreeNode} root 11 | * @return {TreeNode} 12 | */ 13 | var invertTree = function(root) { 14 | 15 | if(root==null){ 16 | return root 17 | } 18 | 19 | //递归子问题 20 | [root.left,root.right] = [invertTree(root.right),invertTree(root.left)] 21 | return root 22 | }; -------------------------------------------------------------------------------- /tree/230.二叉搜索树中第k小的元素.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=230 lang=javascript 3 | * 4 | * [230] 二叉搜索树中第K小的元素 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @param {number} k 19 | * @return {number} 20 | */ 21 | var kthSmallest = function(root, k) { 22 | let count = 0 23 | let stack = [] 24 | while(root || stack.length){ 25 | while(root){ 26 | stack.push(root) 27 | root = root.left 28 | } 29 | root = stack.pop() 30 | count++ 31 | if(count===k){ 32 | return root.val 33 | } 34 | root = root.right 35 | } 36 | }; 37 | // @lc code=end 38 | 39 | -------------------------------------------------------------------------------- /tree/236.二叉树的最近公共祖先.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=236 lang=javascript 3 | * 4 | * [236] 二叉树的最近公共祖先 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val) { 11 | * this.val = val; 12 | * this.left = this.right = null; 13 | * } 14 | */ 15 | /** 16 | * @param {TreeNode} root 17 | * @param {TreeNode} p 18 | * @param {TreeNode} q 19 | * @return {TreeNode} 20 | */ 21 | var lowestCommonAncestor = function(root, p, q) { 22 | if(root==null){ 23 | return null 24 | } 25 | if(root==p || root==q){ 26 | return root 27 | } 28 | let left = lowestCommonAncestor(root.left,p,q) 29 | let right = lowestCommonAncestor(root.right,p,q) 30 | if(left && right){ 31 | return root 32 | } 33 | return left?left:right 34 | }; 35 | // @lc code=end 36 | 37 | -------------------------------------------------------------------------------- /tree/257.二叉树的所有路径.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=257 lang=javascript 3 | * 4 | * [257] 二叉树的所有路径 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {string[]} 19 | */ 20 | var binaryTreePaths = function(root) { 21 | let ret = [] 22 | 23 | const travese = (node,path=[])=>{ 24 | if(node===null){ 25 | return null 26 | } 27 | if(node.left===null && node.right===null){ 28 | // 已经到叶子节点了 29 | path.push(node.val) 30 | ret.push(path.join('->')) 31 | } 32 | travese(node.left,path.concat(node.val)) 33 | travese(node.right,path.concat(node.val)) 34 | } 35 | travese(root,[]) 36 | return ret 37 | }; 38 | // @lc code=end 39 | 40 | -------------------------------------------------------------------------------- /tree/404.左叶子之和.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=404 lang=javascript 3 | * 4 | * [404] 左叶子之和 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number} 19 | */ 20 | var sumOfLeftLeaves = function(root) { 21 | let leftSum = 0 22 | function travese(node){ 23 | if(node===null){ 24 | return 25 | } 26 | // left是单独的节点 27 | let left = node.left 28 | if(left && !left.left && !left.right){ 29 | leftSum += left.val 30 | } 31 | // left有嵌套,走递归 32 | travese(node.left) 33 | travese(node.right) 34 | } 35 | travese(root) 36 | return leftSum 37 | }; 38 | // @lc code=end 39 | 40 | -------------------------------------------------------------------------------- /tree/429.n-叉树的层序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=429 lang=javascript 3 | * 4 | * [429] N 叉树的层序遍历 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * // Definition for a Node. 10 | * function Node(val,children) { 11 | * this.val = val; 12 | * this.children = children; 13 | * }; 14 | */ 15 | 16 | /** 17 | * @param {Node|null} root 18 | * @return {number[][]} 19 | */ 20 | // 更像前端的代码 21 | var levelOrder = function(root) { 22 | let ret = [] 23 | if(root===null){ 24 | return ret 25 | } 26 | let queue = [root] 27 | while(queue.length){ 28 | let curLevel = [] 29 | let len = queue.length 30 | for(let i=0;i{ 35 | child && queue.push(child) 36 | }) 37 | // node.left && queue.push(node.left) 38 | // node.right && queue.push(node.right) 39 | } 40 | ret.push(curLevel) 41 | } 42 | return ret 43 | }; 44 | // @lc code=end 45 | 46 | -------------------------------------------------------------------------------- /tree/515.在每个树行中找最大值.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=515 lang=javascript 3 | * 4 | * [515] 在每个树行中找最大值 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number[]} 19 | */ 20 | var largestValues = function(root) { 21 | let ret = [] 22 | if(root===null){ 23 | return ret 24 | } 25 | let queue = [root] 26 | while(queue.length){ 27 | let len = queue.length 28 | let maxVal = queue[0].val 29 | while(len--){ 30 | let node = queue.shift() 31 | maxVal = maxVal>node.val ?maxVal:node.val 32 | node.left && queue.push(node.left) 33 | node.right && queue.push(node.right) 34 | } 35 | ret.push(maxVal) 36 | } 37 | return ret 38 | }; 39 | // @lc code=end 40 | 41 | -------------------------------------------------------------------------------- /tree/543.二叉树的直径.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=543 lang=javascript 3 | * 4 | * [543] 二叉树的直径 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number} 19 | */ 20 | var diameterOfBinaryTree = function(root) { 21 | let len=0 22 | function dfs(root){ 23 | if(root===null){ 24 | return 0 25 | } 26 | // if(root===null){ 27 | // return null 28 | // } 29 | let left = dfs(root.left) 30 | let right = dfs(root.right) 31 | len = Math.max(len,left+right) 32 | 33 | return Math.max(left,right)+1 34 | } 35 | dfs(root) 36 | return len 37 | }; 38 | // @lc code=end 39 | 40 | -------------------------------------------------------------------------------- /tree/572.另一棵树的子树.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=572 lang=javascript 3 | * 4 | * [572] 另一棵树的子树 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @param {TreeNode} subRoot 19 | * @return {boolean} 20 | */ 21 | // react的虚拟dom,树平级对比 22 | 23 | var isSubtree = function(root, subRoot) { 24 | // 不停地比较, 某一个子树,是不是和subRoot一样 25 | if(root===null){ 26 | return false 27 | } 28 | if(root.val===subRoot.val){ 29 | if(isSameTree(root,subRoot)){ 30 | return true 31 | } 32 | } 33 | return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot) 34 | }; 35 | 36 | var isSameTree = function(p, q) { 37 | if(p===null&&q===null){ 38 | return true 39 | } 40 | if(p===null||q===null){ 41 | return false 42 | } 43 | if(p.val!==q.val){ 44 | return false 45 | } 46 | return isSameTree(p.left,q.left) && isSameTree(p.right,q.right) 47 | }; 48 | // @lc code=end 49 | 50 | -------------------------------------------------------------------------------- /tree/617.合并二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=617 lang=javascript 3 | * 4 | * [617] 合并二叉树 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root1 18 | * @param {TreeNode} root2 19 | * @return {TreeNode} 20 | */ 21 | var mergeTrees = function(root1, root2) { 22 | 23 | function dfs(root1,root2){ 24 | if(!root1){ 25 | return root2 26 | } 27 | if(!root2){ 28 | return root1 29 | } 30 | root1.val += root2.val 31 | root1.left =dfs(root1.left,root2.left) 32 | root1.right =dfs(root1.right,root2.right) 33 | return root1 34 | } 35 | return dfs(root1,root2) 36 | }; 37 | // @lc code=end 38 | 39 | -------------------------------------------------------------------------------- /tree/637.二叉树的层平均值.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=637 lang=javascript 3 | * 4 | * [637] 二叉树的层平均值 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {number[]} 19 | */ 20 | var averageOfLevels = function(root) { 21 | let ret = [] 22 | if(root===null){ 23 | return ret 24 | } 25 | let queue = [root] 26 | while(queue.length){ 27 | let len = queue.length 28 | let sum = 0 29 | for(let i=0;ival){ 29 | return searchBST(root.left,val) 30 | }else if(root.valval){ 27 | root.left = insertIntoBST(root.left,val) 28 | }else if(root.val=node.val){ 29 | // 破坏了递增的逻辑 30 | return false 31 | } 32 | prev = node.val 33 | let right = travese(node.right) 34 | return left && right 35 | } 36 | return travese(root) 37 | }; 38 | // @lc code=end 39 | 40 | -------------------------------------------------------------------------------- /tree/99.恢复二叉搜索树.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @lc app=leetcode.cn id=99 lang=javascript 3 | * 4 | * [99] 恢复二叉搜索树 5 | */ 6 | 7 | // @lc code=start 8 | /** 9 | * Definition for a binary tree node. 10 | * function TreeNode(val, left, right) { 11 | * this.val = (val===undefined ? 0 : val) 12 | * this.left = (left===undefined ? null : left) 13 | * this.right = (right===undefined ? null : right) 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {void} Do not return anything, modify root in-place instead. 19 | */ 20 | var recoverTree = function(root) { 21 | 22 | let arr = [] 23 | let first 24 | let second 25 | 26 | function travese(node){ 27 | if(node===null){ 28 | return 29 | } 30 | travese(node.left) 31 | arr.push(node) 32 | travese(node.right) 33 | } 34 | travese(root) 35 | 36 | for(let i=0;iarr[i+1].val){ 38 | // 出错了 39 | // 找到两个值,移动位置 40 | if(!first){ 41 | //第一次遇见 42 | first = arr[i] 43 | } 44 | second = arr[i+1] 45 | } 46 | } 47 | let tmp = first.val 48 | first.val = second.val 49 | second.val = tmp 50 | }; 51 | // @lc code=end 52 | 53 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: { 5 | includeSource: ['interview/**/*.{js,ts}'], 6 | }, 7 | }) --------------------------------------------------------------------------------