├── .gitattributes ├── Algorithm-notes └── README.md ├── DataStructure-homework ├── Experiment(C++) │ ├── 实验一:链式存储结构的基本操作 │ │ ├── 实验一:链式存储结构的基本操作.doc │ │ ├── 实验报告.doc │ │ ├── 模拟循环队列.cpp │ │ ├── 模拟栈.cpp │ │ └── 模拟链表.cpp │ ├── 实验三:图的遍历生成树 │ │ ├── 图的邻接矩阵表示法和遍历.cpp │ │ ├── 实验三 图的遍历生成树.doc │ │ └── 软件171-1706300032-林欣煜-实验三.doc │ ├── 实验二:树和二叉树的实现 │ │ ├── 中缀表达式转换为二叉树并求值.cpp │ │ ├── 实验二:树和二叉树的实现.doc │ │ ├── 实验报告.doc │ │ └── 由先序遍历和中序遍历生成二叉树.cpp │ ├── 实验五:查找算法 │ │ ├── 二叉排序树.cpp │ │ ├── 哈希表.cpp │ │ ├── 实验五 查找算法.doc │ │ └── 软件171-1706300032-林欣煜-实验五.doc │ ├── 实验六:数据结构综合实验 │ │ ├── KMP.cpp │ │ ├── 实验六-数据结构综合实验.docx │ │ └── 软件171-1706300032-林欣煜-实验六.doc │ ├── 实验四:排序算法 │ │ ├── 十大排序.cpp │ │ ├── 实验四 排序算法.doc │ │ ├── 时间和空间复杂度对比.png │ │ └── 软件171-1706300032-林欣煜-实验四.doc │ └── 课程设计 │ │ ├── 数据结构课程设计.docx │ │ ├── 数据结构课程设计题目2019.doc │ │ └── 最短路径.cpp ├── JS模拟单链表.js ├── JS模拟双链表.js ├── chapter2 │ ├── 1.js │ └── 3.js └── 银行家算法.cpp ├── LeetCode ├── 1. 两数之和.js ├── 100. 相同的树.js ├── 1008. 先序遍历构造二叉树.js ├── 101. 对称二叉树.js ├── 1018. 可被 5 整除的二进制前缀.js ├── 1019. 链表中的下一个更大节点.js ├── 102. 二叉树的层次遍历.js ├── 1022. 从根到叶的二进制数之和.js ├── 1026. 节点与其祖先之间的最大差值.js ├── 104. 二叉树的最大深度.js ├── 105. 从前序与中序遍历序列构造二叉树.js ├── 106. 从中序与后序遍历序列构造二叉树.js ├── 107. 二叉树的层次遍历 II.js ├── 108. 将有序数组转换为二叉搜索树.js ├── 109. 有序链表转换二叉搜索树.js ├── 11. 盛最多水的容器.js ├── 110. 平衡二叉树.js ├── 1104. 二叉树寻路.js ├── 111. 二叉树的最小深度.js ├── 1110. 删点成林.js ├── 112. 路径总和.js ├── 1123. 最深叶节点的最近公共祖先.js ├── 113. 路径总和 II.js ├── 1130. 叶值的最小代价生成树.js ├── 114. 二叉树展开为链表.js ├── 1145. 二叉树着色游戏.js ├── 116. 填充每个节点的下一个右侧节点指针.js ├── 117. 填充每个节点的下一个右侧节点指针 II.js ├── 1171. 从链表中删去总和值为零的连续节点.js ├── 118. 杨辉三角.js ├── 119. 杨辉三角 II.js ├── 121. 买卖股票的最佳时机.js ├── 1254. 统计封闭岛屿的数目.js ├── 1261. 在受污染的二叉树中查找元素.js ├── 129. 求根到叶子节点数字之和.js ├── 13. 罗马数字转整数.js ├── 1344. 时钟指针的夹角.js ├── 136. 只出现一次的数字.js ├── 138. 复制带随机指针的链表.js ├── 141. 环形链表.js ├── 142. 环形链表 II.js ├── 143. 重排链表.js ├── 144. 二叉树的前序遍历.js ├── 145. 二叉树的后序遍历.js ├── 147. 对链表进行插入排序.js ├── 148. 排序链表.js ├── 15. 三数之和.js ├── 154. 寻找旋转排序数组中的最小值 II.js ├── 160. 相交链表.js ├── 167. 两数之和 II - 输入有序数组.js ├── 168. Excel表列名称.js ├── 169. 求众数.js ├── 171. Excel表列序号.js ├── 172. 阶乘后的零.js ├── 173. 二叉搜索树迭代器.js ├── 175. 组合两个表.sql ├── 179. 最大数.js ├── 181. 超过经理收入的员工.sql ├── 182. 查找重复的电子邮箱.sql ├── 183. 从不订购的客户.sql ├── 189. 旋转数组.js ├── 19. 删除链表的倒数第N个节点.js ├── 191. 位1的个数.js ├── 196. 删除重复的电子邮箱.sql ├── 199. 二叉树的右视图.js ├── 2. 两数相加.js ├── 20. 有效的括号.js ├── 20. 检测大写字母.js ├── 202. 快乐数.js ├── 203. 移除链表元素.js ├── 204. 计数质数.js ├── 206. 反转链表.js ├── 21. 合并两个有序链表.js ├── 215. 数组中的第K个最大元素.js ├── 217. 存在重复元素.js ├── 219. 存在重复元素 II.js ├── 222. 完全二叉树的节点个数.js ├── 225. 用队列实现栈.js ├── 226. 翻转二叉树.js ├── 229. 求众数 II.js ├── 23. 合并K个排序链表.js ├── 230. 二叉搜索树中第K小的元素.js ├── 231. 2的幂.js ├── 234. 回文链表.js ├── 235. 二叉搜索树的最近公共祖先.js ├── 236. 二叉树的最近公共祖先.js ├── 237. 删除链表中的节点.js ├── 24. 两两交换链表中的节点.js ├── 25. k个一组翻转链表.js ├── 257. 二叉树的所有路径.js ├── 258. 各位相加.js ├── 26. 删除排序数组中的重复项.js ├── 27. 移除元素.js ├── 278. 第一个错误的版本.js ├── 28. 实现strStr().js ├── 283. 移动零.js ├── 292. Nim 游戏.js ├── 328. 奇偶链表.js ├── 337. 打家劫舍 III.js ├── 338. 比特位计数.js ├── 34. 在排序数组中查找元素的第一个和最后一个位置.js ├── 344. 反转字符串.js ├── 345. 反转字符串中的元音字母.js ├── 349. 两个数组的交集.js ├── 35. 搜索插入位置.js ├── 350. 两个数组的交集 II.js ├── 38. 报数.js ├── 383. 赎金信.js ├── 387. 字符串中的第一个唯一字符.js ├── 404. 左叶子之和.js ├── 414. 第三大的数.js ├── 415. 字符串相加.js ├── 429. N叉树的层序遍历.js ├── 430. 扁平化多级双向链表.js ├── 437. 路径总和 III.js ├── 441. 排列硬币.js ├── 445. 两数相加 II.js ├── 447. 回旋镖的数量.js ├── 448. 找到所有数组中消失的数字.js ├── 449. 序列化和反序列化二叉搜索树.js ├── 450. 删除二叉搜索树中的节点.js ├── 455. 分发饼干.js ├── 459. 重复的子字符串.js ├── 46. 全排列.js ├── 461. 汉明距离.js ├── 468. 验证IP地址.js ├── 47. 全排列 II.js ├── 476. 数字的补数.js ├── 485. 最大连续1的个数.js ├── 496. 下一个更大元素 I.js ├── 500. 键盘行.js ├── 501. 二叉搜索树中的众数.js ├── 504. 七进制数.js ├── 508. 出现次数最多的子树元素和.js ├── 509. 斐波那契数.js ├── 513. 找树左下角的值.js ├── 515. 在每个树行中找最大值.js ├── 53. 最大子序和.js ├── 530. 二叉搜索树的最小绝对差.js ├── 538. 把二叉搜索树转换为累加树.js ├── 543. 二叉树的直径.js ├── 557. 反转字符串中的单词 III.js ├── 559. N叉树的最大深度.js ├── 56. 合并区间.js ├── 561. 数组拆分 I.js ├── 563. 二叉树的坡度.js ├── 565. 数组嵌套.js ├── 572. 另一个树的子树.js ├── 589. N叉树的前序遍历.js ├── 590. N叉树的后序遍历.js ├── 606. 根据二叉树创建字符串.js ├── 61. 旋转链表.js ├── 611. 有效三角形的个数.js ├── 617. 合并二叉树.js ├── 623. 在二叉树中增加一行.js ├── 628. 三个数的最大乘积.js ├── 637. 二叉树的层平均值.js ├── 652. 寻找重复的子树.js ├── 653. 两数之和 IV - 输入 BST.js ├── 654. 最大二叉树.js ├── 655. 输出二叉树.js ├── 657. 机器人能否返回原点.js ├── 659. 分割数组为连续子序列.js ├── 66. 加一.js ├── 662. 二叉树最大宽度.js ├── 669. 修剪二叉搜索树.js ├── 67. 二进制求和.js ├── 671. 二叉树中第二小的节点.js ├── 682. 棒球比赛.js ├── 684. 冗余连接.js ├── 687. 最长同值路径.js ├── 69. x 的平方根.js ├── 7. 整数反转.js ├── 70. 爬楼梯.js ├── 700. 二叉搜索树中的搜索.js ├── 701. 二叉搜索树中的插入操作.js ├── 704. 二分查找.js ├── 707. 设计链表.js ├── 709. 转换成小写字母.js ├── 717. 1比特与2比特字符.js ├── 725. 分隔链表.js ├── 728. 自除数.js ├── 73. 矩阵置零.js ├── 744. 寻找比目标字母大的最小字母.js ├── 746. 使用最小花费爬楼梯.js ├── 75. 颜色分类.js ├── 771. 宝石与石头.js ├── 78. 子集.js ├── 783. 二叉搜索树结点最小距离.js ├── 788. 旋转数字.js ├── 80. 删除排序数组中的重复项 II.js ├── 804. 唯一摩尔斯密码词.js ├── 814. 二叉树剪枝.js ├── 817. 链表组件.js ├── 82. 删除排序链表中的重复元素 II.js ├── 824. 山羊拉丁文.js ├── 83. 删除排序链表中的重复元素.js ├── 844. 比较含退格的字符串.js ├── 852. 山脉数组的峰顶索引.js ├── 859. 亲密字符串.js ├── 86. 分隔链表.js ├── 863. 二叉树中所有距离为 K 的结点.js ├── 865. 具有所有最深结点的最小子树.js ├── 867. 转置矩阵.js ├── 872. 叶子相似的树.js ├── 876. 链表的中间结点.js ├── 88. 合并两个有序数组.js ├── 884. 两句话中的不常见单词.js ├── 889. 根据前序和后序遍历构造二叉树.js ├── 894. 所有可能的满二叉树.js ├── 896. 单调数列.js ├── 897. 递增顺序查找树.js ├── 9. 回文数.js ├── 90. 子集 II.js ├── 905. 按奇偶排序数组.js ├── 908. 最小差值 I.js ├── 912. 排序数组.js ├── 919. 完全二叉树插入器.js ├── 92. 反转链表 II.js ├── 922. 按奇偶排序数组 II.js ├── 938. 二叉搜索树的范围和.js ├── 94. 二叉树的中序遍历.js ├── 95. 不同的二叉搜索树 II.js ├── 951. 翻转等价二叉树.js ├── 958. 二叉树的完全性检验.js ├── 96. 不同的二叉搜索树.js ├── 961. 重复 N 次的元素.js ├── 965. 单值二叉树.js ├── 971. 翻转二叉树以匹配先序遍历.js ├── 976. 三角形的最大周长.js ├── 977. 有序数组的平方.js ├── 979. 在二叉树中分配硬币.js ├── 98. 验证二叉搜索树.js ├── 987. 二叉树的垂序遍历.js ├── 988. 从叶结点开始的最小字符串.js ├── 989. 数组形式的整数加法.js ├── 993. 二叉树的堂兄弟节点.js ├── 997. 找到小镇的法官.js ├── 998. 最大二叉树 II.js ├── README.md ├── 力扣杯:1. 有序数组中的缺失元素.js └── 面试题38. 字符串的排列.js ├── README.md └── 剑指Offer ├── README.md ├── 面试题03. 数组中重复的数字.js ├── 面试题04. 二维数组中的查找.js ├── 面试题05. 替换空格.js ├── 面试题06. 从尾到头打印链表.js ├── 面试题07. 重建二叉树.js ├── 面试题09. 用两个栈实现队列.js ├── 面试题10- I. 斐波那契数列.js ├── 面试题10- II. 青蛙跳台阶问题.js └── 面试题11. 旋转数组的最小数字.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /DataStructure-homework/Experiment(C++)/实验一:链式存储结构的基本操作/实验一:链式存储结构的基本操作.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DangoSky/algorithm/458af0b3ec73958d1431b4c20b846f21c7a953ad/DataStructure-homework/Experiment(C++)/实验一:链式存储结构的基本操作/实验一:链式存储结构的基本操作.doc -------------------------------------------------------------------------------- /DataStructure-homework/Experiment(C++)/实验一:链式存储结构的基本操作/实验报告.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DangoSky/algorithm/458af0b3ec73958d1431b4c20b846f21c7a953ad/DataStructure-homework/Experiment(C++)/实验一:链式存储结构的基本操作/实验报告.doc -------------------------------------------------------------------------------- /DataStructure-homework/Experiment(C++)/实验三:图的遍历生成树/实验三 图的遍历生成树.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DangoSky/algorithm/458af0b3ec73958d1431b4c20b846f21c7a953ad/DataStructure-homework/Experiment(C++)/实验三:图的遍历生成树/实验三 图的遍历生成树.doc -------------------------------------------------------------------------------- /DataStructure-homework/Experiment(C++)/实验三:图的遍历生成树/软件171-1706300032-林欣煜-实验三.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DangoSky/algorithm/458af0b3ec73958d1431b4c20b846f21c7a953ad/DataStructure-homework/Experiment(C++)/实验三:图的遍历生成树/软件171-1706300032-林欣煜-实验三.doc -------------------------------------------------------------------------------- /DataStructure-homework/Experiment(C++)/实验二:树和二叉树的实现/实验二:树和二叉树的实现.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DangoSky/algorithm/458af0b3ec73958d1431b4c20b846f21c7a953ad/DataStructure-homework/Experiment(C++)/实验二:树和二叉树的实现/实验二:树和二叉树的实现.doc -------------------------------------------------------------------------------- /DataStructure-homework/Experiment(C++)/实验二:树和二叉树的实现/实验报告.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DangoSky/algorithm/458af0b3ec73958d1431b4c20b846f21c7a953ad/DataStructure-homework/Experiment(C++)/实验二:树和二叉树的实现/实验报告.doc -------------------------------------------------------------------------------- /DataStructure-homework/Experiment(C++)/实验五:查找算法/实验五 查找算法.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DangoSky/algorithm/458af0b3ec73958d1431b4c20b846f21c7a953ad/DataStructure-homework/Experiment(C++)/实验五:查找算法/实验五 查找算法.doc -------------------------------------------------------------------------------- /DataStructure-homework/Experiment(C++)/实验五:查找算法/软件171-1706300032-林欣煜-实验五.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DangoSky/algorithm/458af0b3ec73958d1431b4c20b846f21c7a953ad/DataStructure-homework/Experiment(C++)/实验五:查找算法/软件171-1706300032-林欣煜-实验五.doc -------------------------------------------------------------------------------- /DataStructure-homework/Experiment(C++)/实验六:数据结构综合实验/KMP.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | // 计算next数组 4 | void getNext(string str, int next[]) { 5 | int i = 0, j = -1; 6 | int len = str.length(); 7 | next[0] = -1; 8 | while(i < len - 1) { 9 | if(j == -1 || str[i] == str[j]) { 10 | i++; 11 | j++; 12 | next[i] = j; 13 | } 14 | else { 15 | j = next[j]; 16 | } 17 | } 18 | } 19 | int kmp(string str, string s, int next[]) { 20 | getNext(s, next); 21 | int i = 0, j = 0; 22 | int len1 = str.length(), len2 = s.length(); 23 | while(i < len1 && j < len2) { 24 | if(j == -1 || str[i] == s[j]) { 25 | i++; 26 | j++; 27 | } 28 | else { 29 | j = next[j]; 30 | } 31 | } 32 | if(j == len2) return i - j; 33 | else return -1; 34 | } 35 | 36 | int main() { 37 | while(1) { 38 | string str = ""; 39 | string s = ""; 40 | cout<<"请输入病毒的DNA序列"<>s; 42 | cout<<"请输入患者的DNA序列"<>str; 44 | int next[1000]; 45 | string doubleS = s + s; 46 | int res; 47 | for(int i=0; i list2.data) { 22 | nodeList1.insert(i, list2.data); 23 | list2 = list2.next; 24 | } 25 | else if(list1.data < list2.data) { 26 | list1 = list1.next; 27 | } 28 | else if(list1.data === list2.data) { 29 | list1 = list1.next; 30 | list2 = list2.next; 31 | } 32 | } 33 | else if(!list1 && list2) { 34 | nodeList1.insert(i, list2.data); 35 | list2 = list2.next; 36 | } 37 | } 38 | console.log(nodeList1.toString()); -------------------------------------------------------------------------------- /DataStructure-homework/chapter2/3.js: -------------------------------------------------------------------------------- 1 | /* 2 | 已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出A与B的交集,并存放于A链表中。 3 | */ 4 | 5 | 6 | let Node = require('../JS模拟单链表.js') 7 | // 先创建两条链表 8 | let nodeList1 = new Node(); 9 | nodeList1.init(110, 120, 506); 10 | let nodeList2 = new Node(); 11 | nodeList2.init(110, 120, 510); 12 | let len1 = nodeList1.length(); 13 | let list1 = nodeList1.next; 14 | for(let i=1; i<=len1; i++) { 15 | if(!nodeList2.find(list1.data)) { 16 | nodeList1.remove(nodeList1.find(list1.data)); 17 | } 18 | list1 = list1.next; 19 | } 20 | console.log(nodeList1.toString()); 21 | console.log(nodeList2.toString()); -------------------------------------------------------------------------------- /LeetCode/1. 两数之和.js: -------------------------------------------------------------------------------- 1 | /* 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 2 | 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 3 | 4 | 示例: 5 | 给定 nums = [2, 7, 11, 15], target = 9 6 | 因为 nums[0] + nums[1] = 2 + 7 = 9 7 | 所以返回 [0, 1] */ 8 | 9 | 10 | 11 | // 方法一:暴力破解,两层for循环 12 | var twoSum = function(nums, target) { 13 | let len = nums.length; 14 | for(let i=0; i { 22 | return val % 5 === 0; 23 | }) 24 | }; 25 | console.log(prefixesDivBy5([1, 1, 1])); 26 | console.log(prefixesDivBy5([1,1,1,0,1])); 27 | console.log(prefixesDivBy5([0,1,1,1,1,1])); 28 | -------------------------------------------------------------------------------- /LeetCode/1019. 链表中的下一个更大节点.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给出一个以头节点 head 作为第一个节点的链表。链表中的节点分别编号为:node_1, node_2, node_3, ... 。 3 | 每个节点都可能有下一个更大值(next larger value):对于 node_i,如果其 next_larger(node_i) 是 node_j.val,那么就有 j > i 且 node_j.val > node_i.val,而 j 是可能的选项中最小的那个。如果不存在这样的 j,那么下一个更大值为 0 。 4 | 返回整数答案数组 answer,其中 answer[i] = next_larger(node_{i+1}) 。 5 | 注意:在下面的示例中,诸如 [2,1,5] 这样的输入(不是输出)是链表的序列化表示,其头节点的值为 2,第二个节点值为 1,第三个节点值为 5 。 6 | Definition for singly-linked list: 7 | function ListNode(val) { 8 | this.val = val; 9 | this.next = null; 10 | } 11 | 12 | 示例 1: 13 | 输入:[2,1,5] 14 | 输出:[5,5,0] 15 | 16 | 示例 2: 17 | 输入:[2,7,4,3,5] 18 | 输出:[7,0,5,5,0] 19 | 20 | 示例 3: 21 | 输入:[1,7,5,1,9,2,5,1] 22 | 输出:[7,9,9,9,0,5,0,0] 23 | 24 | */ 25 | 26 | 27 | var nextLargerNodes = function(head) { 28 | // 先把链表转为数组 29 | let arr = []; 30 | while(head) { 31 | arr.push(head.val); 32 | head = head.next; 33 | } 34 | let len = arr.length; 35 | let tem = arr.slice(); // 复制一个用来循环的数组 36 | let res = []; 37 | let value = -1; // 保存找到的值 38 | for(let i=0; i { 41 | if(val > arr[i]) { 42 | value = val; 43 | return true; 44 | } 45 | }); 46 | tem.shift(); // 把当前元素剔出数组 47 | res[i] = judge ? value : 0; 48 | } 49 | return res; 50 | }; -------------------------------------------------------------------------------- /LeetCode/102. 二叉树的层次遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 3 | 例如: 4 | 给定二叉树: [3,9,20,null,null,15,7], 5 | 3 6 | / \ 7 | 9 20 8 | / \ 9 | 15 7 10 | 返回其层次遍历结果: 11 | [ 12 | [3], 13 | [9,20], 14 | [15,7] 15 | ] 16 | */ 17 | /** 18 | * Definition for a binary tree node. 19 | * function TreeNode(val) { 20 | * this.val = val; 21 | * this.left = this.right = null; 22 | * } 23 | */ 24 | /** 25 | * @param {TreeNode} root 26 | * @return {number[][]} 27 | */ 28 | var levelOrder = function(root) { 29 | if(root === null) return []; 30 | let queue = []; 31 | let res = []; 32 | queue.push(root); 33 | // 每一层的节点数量 34 | let sum = 1; 35 | while(queue.length) { 36 | let temp = []; 37 | while(sum--) { 38 | let top = queue.shift(); 39 | temp.push(top.val); 40 | if(top.left) queue.push(top.left); 41 | if(top.right) queue.push(top.right); 42 | } 43 | res.push(temp); 44 | sum = queue.length; 45 | } 46 | return res; 47 | }; -------------------------------------------------------------------------------- /LeetCode/1022. 从根到叶的二进制数之和.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给出一棵二叉树,其上每个结点的值都是 0 或 1 。每一条从根到叶的路径都代表一个从最高有效位开始的二进制数。例如,如果路径为 0 -> 1 -> 1 -> 0 -> 1,那么它表示二进制数 01101,也就是 13 。 3 | 对树上的每一片叶子,我们都要找出从根到该叶子的路径所表示的数字。 4 | 以 10^9 + 7 为模,返回这些数字之和。 5 | */ 6 | 7 | /** 8 | * Definition for a binary tree node. 9 | * function TreeNode(val) { 10 | * this.val = val; 11 | * this.left = this.right = null; 12 | * } 13 | */ 14 | /** 15 | * @param {TreeNode} root 16 | * @return {number} 17 | */ 18 | 19 | // 递归。相当于寻找所有根节点到叶子节点的路径。每下一层,就将已经过路径的数字和乘2,在叶子节点累加结果即可。 20 | var sumRootToLeaf = function(root) { 21 | let ans = 0; 22 | (function fn(root, sum) { 23 | if (!root) { 24 | return; 25 | } 26 | sum = (sum * 2 + root.val) % 1000000007; 27 | if (!root.left && !root.right) { 28 | ans += sum; 29 | ans %= 1000000007; 30 | return; 31 | } 32 | fn(root.left, sum); 33 | fn(root.right, sum); 34 | })(root, 0) 35 | 36 | return ans; 37 | }; -------------------------------------------------------------------------------- /LeetCode/104. 二叉树的最大深度.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,找出其最大深度。 3 | 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 4 | 说明: 叶子节点是指没有子节点的节点。 5 | */ 6 | 7 | var maxDepth = function(root) { 8 | if(root === null) return 0; 9 | let l = maxDepth(root.left); 10 | let r = maxDepth(root.right); 11 | return Math.max(l, r) + 1; 12 | } 13 | 14 | var maxDepth = function(root) { 15 | if(root === null) { 16 | return 0 17 | } 18 | let ans = 0; 19 | function search(node, i) { 20 | if(!node.left && !node.right) { 21 | if(ans < i) { 22 | ans = i; 23 | } 24 | return; 25 | } 26 | if(node.left) { 27 | search(node.left, i+1); 28 | } 29 | if(node.right) { 30 | search(node.right, i+1); 31 | } 32 | } 33 | search(root, 1); 34 | return ans; 35 | }; 36 | -------------------------------------------------------------------------------- /LeetCode/106. 从中序与后序遍历序列构造二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 根据一棵树的中序遍历与后序遍历构造二叉树。 3 | 注意: 4 | 你可以假设树中没有重复的元素。 5 | 例如,给出 6 | 中序遍历 inorder = [9,3,15,20,7] 7 | 后序遍历 postorder = [9,15,7,20,3] 8 | 返回如下的二叉树: 9 | 10 | 3 11 | / \ 12 | 9 20 13 | / \ 14 | 15 7 15 | */ 16 | /** 17 | * Definition for a binary tree node. 18 | * function TreeNode(val) { 19 | * this.val = val; 20 | * this.left = this.right = null; 21 | * } 22 | */ 23 | /** 24 | * @param {number[]} inorder 25 | * @param {number[]} postorder 26 | * @return {TreeNode} 27 | */ 28 | var buildTree = function(inorder, postorder) { 29 | function build(l1, r1, l2, r2) { 30 | if(l1 > r1 || l2 > r2) return null; 31 | let index = 0; 32 | let root = new TreeNode(); 33 | root.val = postorder[r2]; 34 | for(let i=l1; i<=r1; i++) { 35 | if(inorder[i] === postorder[r2]) { 36 | index = i; 37 | break; 38 | } 39 | } 40 | let sum = index - l1; 41 | root.left = build(l1, index - 1, l2, l2 + sum - 1) 42 | root.right = build(index + 1, r1, l2 + sum, r2 - 1); 43 | return root; 44 | } 45 | return build(0, inorder.length - 1, 0, postorder.length - 1); 46 | }; -------------------------------------------------------------------------------- /LeetCode/108. 将有序数组转换为二叉搜索树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。 3 | 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 4 | 5 | 示例: 6 | 给定有序数组: [-10,-3,0,5,9], 7 | 一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树: 8 | 9 | 0 10 | / \ 11 | -3 9 12 | / / 13 | -10 5 14 | */ 15 | /** 16 | * Definition for a binary tree node. 17 | * function TreeNode(val) { 18 | * this.val = val; 19 | * this.left = this.right = null; 20 | * } 21 | */ 22 | /** 23 | * @param {number[]} nums 24 | * @return {TreeNode} 25 | */ 26 | 27 | // 把中间结点作为根节点,左右两边的结点分贝作为左右子树 28 | var sortedArrayToBST = function(nums) { 29 | function build(arr, l, r) { 30 | if(l > r) { 31 | return null; 32 | } 33 | // 中间结点 34 | let mid = l + Math.floor((r - l) / 2); 35 | let root = new TreeNode(arr[mid]); 36 | root.val = arr[mid]; 37 | root.left = build(arr, l, mid-1); 38 | root.right = build(arr, mid+1, r); 39 | return root; 40 | } 41 | return build(nums, 0, nums.length-1); 42 | } -------------------------------------------------------------------------------- /LeetCode/109. 有序链表转换二叉搜索树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。 3 | 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 4 | 5 | 示例: 6 | 给定的有序链表: [-10, -3, 0, 5, 9], 7 | 8 | 一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树: 9 | 0 10 | / \ 11 | -3 9 12 | / / 13 | -10 5 14 | */ 15 | /** 16 | * Definition for singly-linked list. 17 | * function ListNode(val) { 18 | * this.val = val; 19 | * this.next = null; 20 | * } 21 | */ 22 | /** 23 | * Definition for a binary tree node. 24 | * function TreeNode(val) { 25 | * this.val = val; 26 | * this.left = this.right = null; 27 | * } 28 | */ 29 | /** 30 | * @param {ListNode} head 31 | * @return {TreeNode} 32 | */ 33 | 34 | // 把中间结点作为根节点,左右两边的结点分贝作为左右子树 35 | var sortedListToBST = function(head) { 36 | if(head === null) { 37 | return null; 38 | } 39 | let slow = head; 40 | let fast = head; 41 | // 保存中间结点的前一个结点,便于后面切割head分离出左子树 42 | let pre = slow; 43 | // 通过快慢指针找到中间结点 44 | // 此处判断条件不能是 fast && fast.next。如果是这样的话,后续的中间结点可能会和右子树重复。 45 | while(fast.next && fast.next.next) { 46 | pre = slow; 47 | slow = slow.next; 48 | fast = fast.next.next; 49 | } 50 | // 右子树 51 | fast = slow.next; 52 | // 左子树 53 | pre.next = null; 54 | let root = new TreeNode(slow.val); 55 | // 如果左子树是中间结点相同的话,说明此时没有左子树。 56 | if(head !== slow) { 57 | root.left = sortedListToBST(head); 58 | } 59 | root.right = sortedListToBST(fast); 60 | return root; 61 | }; -------------------------------------------------------------------------------- /LeetCode/11. 盛最多水的容器.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 3 | 说明:你不能倾斜容器,且 n 的值至少为 2。 4 | 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 5 | 6 | 示例: 7 | 输入:[1,8,6,2,5,4,8,3,7] 8 | 输出:49 9 | */ 10 | 11 | /** 12 | * @param {number[]} height 13 | * @return {number} 14 | */ 15 | 16 | // 暴力破解,两层 for 算出两两组合的矩形面积 17 | var maxArea = function(height) { 18 | let res = 0; 19 | for(let i=0; i res) { 23 | res = temp; 24 | } 25 | } 26 | } 27 | return res; 28 | }; 29 | 30 | // 双指针,一个在数组头,一个在数位尾。 31 | // 初始时底长已经是最大了,想要更大的面积,就只能寻找更大的边高。所以比较此时的两条边高,更小的那条舍弃,移动指针寻找下一条边看看能不能得到更大的面积 32 | var maxArea = function(height) { 33 | let res = 0; 34 | let l = 0, r = height.length - 1; 35 | while (l < r) { 36 | res = Math.max(res, (r - l) * Math.min(height[l], height[r])); 37 | if (height[l] > height[r]) { 38 | r--; 39 | } else { 40 | l++; 41 | } 42 | } 43 | return res; 44 | } -------------------------------------------------------------------------------- /LeetCode/110. 平衡二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,判断它是否是高度平衡的二叉树。 3 | 本题中,一棵高度平衡二叉树定义为: 4 | 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 5 | 6 | 示例 1: 7 | 给定二叉树 [3,9,20,null,null,15,7] 8 | 9 | 3 10 | / \ 11 | 9 20 12 | / \ 13 | 15 7 14 | 返回 true 。 15 | 16 | 示例 2: 17 | 给定二叉树 [1,2,2,3,3,null,null,4,4] 18 | 19 | 1 20 | / \ 21 | 2 2 22 | / \ 23 | 3 3 24 | / \ 25 | 4 4 26 | 返回 false。 27 | */ 28 | /** 29 | * Definition for a binary tree node. 30 | * function TreeNode(val) { 31 | * this.val = val; 32 | * this.left = this.right = null; 33 | * } 34 | */ 35 | /** 36 | * @param {TreeNode} root 37 | * @return {boolean} 38 | */ 39 | var isBalanced = function(root) { 40 | // 计算子树的深度 41 | function fn(root) { 42 | return root === null ? 0 : Math.max(fn(root.left), fn(root.right)) + 1; 43 | } 44 | if(root === null) return true; 45 | // 判断当前结点的左右子树的深度差 46 | if(Math.abs(fn(root.left) - fn(root.right)) > 1) return false; 47 | // 如果当前结点是平衡二叉树,则递归判断它的左右结点 48 | return isBalanced(root.left) && isBalanced(root.right); 49 | }; -------------------------------------------------------------------------------- /LeetCode/1104. 二叉树寻路.js: -------------------------------------------------------------------------------- 1 | /* 2 | 在一棵无限的二叉树上,每个节点都有两个子节点,树中的节点 逐行 依次按 “之” 字形进行标记。 3 | 如下图所示,在奇数行(即,第一行、第三行、第五行……)中,按从左到右的顺序进行标记; 4 | 而偶数行(即,第二行、第四行、第六行……)中,按从右到左的顺序进行标记。 5 | 给你树上某一个节点的标号 label,请你返回从根节点到该标号为 label 节点的路径,该路径是由途经的节点标号所组成的。 6 | */ 7 | 8 | /** 9 | * @param {number} label 10 | * @return {number[]} 11 | */ 12 | 13 | 14 | // 迭代。 15 | // 如果按照原来满二叉树的性质来,节点 label 的父节点是节点 Math.floor(label/2)。 16 | // 观察得到现在节点label的父节点和节点 Math.floor(label/2)是对称的,所以可以通过这个对称的性质计算得到现在的父节点。 17 | // 现在的父节点 = 父节点层的起始节点 + 从第一层到父节点层的所有节点数 - 原来的父节点Math.floor(label/2) 18 | // = 父节点层的起始节点 + 父节点层的节点数 * 2 - 1 - Math.floor(label / 2))。 19 | var pathInZigZagTree = function(label) { 20 | let res = []; 21 | let curLevelNodeSum = 1; 22 | let allNodeSum = 1; 23 | while(allNodeSum < label) { 24 | curLevelNodeSum *= 2; 25 | allNodeSum += curLevelNodeSum; 26 | } 27 | 28 | while(label >= 1) { 29 | res.unshift(label); 30 | curLevelNodeSum /= 2; 31 | label = curLevelNodeSum + (curLevelNodeSum * 2 - 1 - Math.floor(label / 2)); 32 | } 33 | return res; 34 | }; -------------------------------------------------------------------------------- /LeetCode/111. 二叉树的最小深度.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,找出其最小深度。 3 | 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 4 | 说明: 叶子节点是指没有子节点的节点。 5 | 6 | 示例: 7 | 给定二叉树 [3,9,20,null,null,15,7], 8 | 9 | 3 10 | / \ 11 | 9 20 12 | / \ 13 | 15 7 14 | 返回它的最小深度 2. 15 | */ 16 | /** 17 | * Definition for a binary tree node. 18 | * function TreeNode(val) { 19 | * this.val = val; 20 | * this.left = this.right = null; 21 | * } 22 | */ 23 | /** 24 | * @param {TreeNode} root 25 | * @return {number} 26 | */ 27 | // 最小深度是从根节点到最近叶子节点的最短路径上的节点数量" 也就是说除非是只有一个根节点,不然的话必须要有一个根节点跟叶子节点才能组成路径。 28 | // 根节点自己不能作为叶子节点,所以[1,2]最小深度2,[1]最小深度1. 29 | var minDepth = function(root) { 30 | if(root === null) return 0; 31 | let left = minDepth(root.left); 32 | let right = minDepth(root.right); 33 | if(left && right) { 34 | return Math.min(left, right) + 1; 35 | } 36 | // left或者right至少有一个为0,特殊处理[1,2]的情况 37 | return 1 + left + right; 38 | }; -------------------------------------------------------------------------------- /LeetCode/1110. 删点成林.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给出二叉树的根节点 root,树上每个节点都有一个不同的值。 3 | 如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。 4 | 返回森林中的每棵树。你可以按任意顺序组织答案。 5 | */ 6 | 7 | /** 8 | * Definition for a binary tree node. 9 | * function TreeNode(val) { 10 | * this.val = val; 11 | * this.left = this.right = null; 12 | * } 13 | */ 14 | /** 15 | * @param {TreeNode} root 16 | * @param {number[]} to_delete 17 | * @return {TreeNode[]} 18 | */ 19 | 20 | // 递归。如果当前节点是要删除的话,则判断是否是叶子节点,是叶子节点的话直接返回null给父层用于断开两者之间的连接。 21 | // 如果不是叶子节点的话,则递归判断左右子树,并同样也返回null给父层。如果递归返回的结果不是空的话(子树中有有效的节点,如果不对递归结果判断的话,可能得到的子树是空树,导致把空树也加入res中了),则加入结果数组res中。 22 | // (对于这种会修改二叉树结构的,递归函数需要返回一个值给父层,才能修改父节点的子树从而修改二叉树) 23 | var delNodes = function(root, to_delete) { 24 | let res = []; 25 | // 记得要把根节点也加入res中 26 | if (root && !to_delete.includes(root.val)) { 27 | res.push(root); 28 | } 29 | (function fn(root) { 30 | if (!root) { 31 | return null; 32 | } 33 | if (to_delete.includes(root.val)) { 34 | // 叶子节点 35 | if (!root.left && !root.right) { 36 | return null; 37 | } 38 | // 非叶子节点 39 | let l = fn(root.left); 40 | let r = fn(root.right); 41 | if (l) { 42 | res.push(l); 43 | } 44 | if (r) { 45 | res.push(r); 46 | } 47 | return null; 48 | } else { 49 | root.left = fn(root.left); 50 | root.right = fn(root.right); 51 | return root; 52 | } 53 | })(root) 54 | return res; 55 | }; -------------------------------------------------------------------------------- /LeetCode/112. 路径总和.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。 3 | 说明: 叶子节点是指没有子节点的节点。 4 | 5 | 示例: 6 | 给定如下二叉树,以及目标和 sum = 22, 7 | 8 | 5 9 | / \ 10 | 4 8 11 | / / \ 12 | 11 13 4 13 | / \ \ 14 | 7 2 1 15 | 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。 16 | */ 17 | /** 18 | * Definition for a binary tree node. 19 | * function TreeNode(val) { 20 | * this.val = val; 21 | * this.left = this.right = null; 22 | * } 23 | */ 24 | /** 25 | * @param {TreeNode} root 26 | * @param {number} sum 27 | * @return {boolean} 28 | */ 29 | // 可以先假设一颗空树、只有根结点的树、只有一个根节点和一个叶子结点的树,假设出几颗树后根据这些情况编写递归式和终止条件。 30 | var hasPathSum = function(root, sum) { 31 | if(root === null) { 32 | return false; 33 | } 34 | if(root.left === null && root.right === null) { 35 | return sum === root.val; 36 | } 37 | // 是 || 才可以递归执行左右子树 38 | return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val); 39 | }; -------------------------------------------------------------------------------- /LeetCode/1123. 最深叶节点的最近公共祖先.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给你一个有根节点的二叉树,找到它最深的叶节点的最近公共祖先。 3 | 4 | 示例 1: 5 | 输入:root = [1,2,3] 6 | 输出:[1,2,3] 7 | 8 | 示例 2: 9 | 输入:root = [1,2,3,4] 10 | 输出:[4] 11 | 12 | 示例 3: 13 | 输入:root = [1,2,3,4,5] 14 | 输出:[2,4,5] 15 | */ 16 | 17 | /** 18 | * Definition for a binary tree node. 19 | * function TreeNode(val) { 20 | * this.val = val; 21 | * this.left = this.right = null; 22 | * } 23 | */ 24 | /** 25 | * @param {TreeNode} root 26 | * @return {TreeNode} 27 | */ 28 | 29 | // 递归。如果左右子树深度相等,则当前节点就是最深叶子节点的最近公共祖先,反之在深度更大的子树上。如果只有一个最深的叶结点,那么它的最近公共祖先就是它自己 30 | var lcaDeepestLeaves = function(root) { 31 | function computeDeep(root) { 32 | if (!root) { 33 | return 0; 34 | } 35 | return Math.max(computeDeep(root.left), computeDeep(root.right)) + 1; 36 | } 37 | 38 | return (function fn(root) { 39 | let l = computeDeep(root.left); 40 | let r = computeDeep(root.right); 41 | if (l === r) { 42 | return root; 43 | } else if (l > r) { 44 | return fn(root.left); 45 | } else { 46 | return fn(root.right); 47 | } 48 | })(root) 49 | }; -------------------------------------------------------------------------------- /LeetCode/113. 路径总和 II.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 3 | 说明: 叶子节点是指没有子节点的节点。 4 | 示例: 5 | 给定如下二叉树,以及目标和 sum = 22, 6 | 5 7 | / \ 8 | 4 8 9 | / / \ 10 | 11 13 4 11 | / \ / \ 12 | 7 2 5 1 13 | 返回: 14 | [ 15 | [5,4,11,2], 16 | [5,8,4,5] 17 | ] 18 | */ 19 | 20 | /** 21 | * Definition for a binary tree node. 22 | * function TreeNode(val) { 23 | * this.val = val; 24 | * this.left = this.right = null; 25 | * } 26 | */ 27 | /** 28 | * @param {TreeNode} root 29 | * @param {number} sum 30 | * @return {number[][]} 31 | */ 32 | // 可以画个图模拟一下过程 33 | var pathSum = function(root, sum) { 34 | let res = []; 35 | function fn(root, sum, temp) { 36 | if(root === null) return; 37 | temp.push(root.val); 38 | // 到达叶子结点且路径和等于sum 39 | if(root.left === null && root.right === null && root.val === sum) { 40 | // 需要拷贝一份再加入res,否则会受后面的pop操作影响 41 | res.push(temp.slice(0)); 42 | // 将当前结点pop出当前路径,返回上一层走另一条路 43 | temp.pop(); 44 | return; 45 | } 46 | fn(root.left, sum - root.val, temp); 47 | fn(root.right, sum - root.val, temp); 48 | // 将当前结点pop出当前路径,返回上一层走另一条路 49 | temp.pop(); 50 | } 51 | fn(root, sum, []); 52 | return res; 53 | }; -------------------------------------------------------------------------------- /LeetCode/114. 二叉树展开为链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,原地将它展开为链表。 3 | 例如,给定二叉树 4 | 5 | 1 6 | / \ 7 | 2 5 8 | / \ \ 9 | 3 4 6 10 | 将其展开为: 11 | 12 | 1 13 | \ 14 | 2 15 | \ 16 | 3 17 | \ 18 | 4 19 | \ 20 | 5 21 | \ 22 | 6 23 | */ 24 | /** 25 | * Definition for a binary tree node. 26 | * function TreeNode(val) { 27 | * this.val = val; 28 | * this.left = this.right = null; 29 | * } 30 | */ 31 | /** 32 | * @param {TreeNode} root 33 | * @return {void} Do not return anything, modify root in-place instead. 34 | */ 35 | var flatten = function(root) { 36 | if(root === null) return root; 37 | let left = root.left; 38 | let right = root.right; 39 | flatten(left); 40 | flatten(right); 41 | root.left = null; 42 | root.right = left; 43 | // 对于非叶子结点,需要重新赋值root,把右子树拼接到左子树上,否则会打印不出右子树。可以画个图比如 1->2->3 模拟下过程 44 | while(root.right !== null) { 45 | root = root.right; 46 | } 47 | root.right = right; 48 | }; 49 | 50 | 51 | // 1. 左子树插入到右子树的地方 52 | // 2. 将原来的右子树接到左子树的最右边节点 53 | // 3. 考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null 54 | var flatten = function(root) { 55 | while(root) { 56 | let l = root.left; 57 | if (l !== null) { 58 | // 获取左子树的最右边节点 59 | while(l.right) { 60 | l = l.right; 61 | } 62 | l.right = root.right; 63 | root.right = root.left; 64 | root.left = null; 65 | } 66 | root = root.right; 67 | } 68 | return root; 69 | } -------------------------------------------------------------------------------- /LeetCode/117. 填充每个节点的下一个右侧节点指针 II.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树 3 | 4 | struct Node { 5 | int val; 6 | Node *left; 7 | Node *right; 8 | Node *next; 9 | } 10 | 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。 11 | 12 | 初始状态下,所有 next 指针都被设置为 NULL。 13 | */ 14 | 15 | /** 16 | * // Definition for a Node. 17 | * function Node(val,left,right,next) { 18 | * this.val = val; 19 | * this.left = left; 20 | * this.right = right; 21 | * this.next = next; 22 | * }; 23 | */ 24 | /** 25 | * @param {Node} root 26 | * @return {Node} 27 | */ 28 | 29 | // 层序遍历存储在head中 30 | var connect = function(root) { 31 | let cur = root; 32 | while(cur) { 33 | let dummy = new Node(); // 存储每一层的第一个节点 34 | let head = dummy; // 层序遍历的顺序 35 | while(cur) { 36 | if (cur.left) { 37 | head.next = cur.left; 38 | head = head.next; 39 | } 40 | if (cur.right) { 41 | head.next = cur.right; 42 | head = head.next; 43 | } 44 | cur = cur.next; 45 | } 46 | cur = dummy.next; 47 | } 48 | return root; 49 | }; -------------------------------------------------------------------------------- /LeetCode/118. 杨辉三角.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。 3 | 4 | 示例: 5 | 输入: 5 6 | 输出: 7 | [ 8 | [1], 9 | [1,1], 10 | [1,2,1], 11 | [1,3,3,1], 12 | [1,4,6,4,1] 13 | ] 14 | */ 15 | 16 | 17 | var generate = function(numRows) { 18 | let ans = []; 19 | for(let i=1; i<=numRows; i++) { 20 | let arr = []; 21 | for(let j=0; j max) { 27 | max = prices[i] - min; 28 | } 29 | } 30 | return max; 31 | }; 32 | 33 | 34 | var maxProfit = function(prices) { 35 | let max = 0; 36 | let res = 0; 37 | for(let i=1; i 0 && max > res) { 40 | res = max; 41 | } 42 | else if(max < 0) { 43 | max = 0; 44 | } 45 | } 46 | return res; 47 | }; 48 | console.log(maxProfit([7,1,5,3,6,4])); 49 | console.log(maxProfit([7,6,4,3,1])); 50 | console.log(maxProfit([2,4,1])); -------------------------------------------------------------------------------- /LeetCode/129. 求根到叶子节点数字之和.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。 3 | 例如,从根到叶子节点路径 1->2->3 代表数字 123。 4 | 计算从根到叶子节点生成的所有数字之和。 5 | 说明: 叶子节点是指没有子节点的节点。 6 | 7 | 示例 1: 8 | 输入: [1,2,3] 9 | 1 10 | / \ 11 | 2 3 12 | 输出: 25 13 | 解释: 14 | 从根到叶子节点路径 1->2 代表数字 12. 15 | 从根到叶子节点路径 1->3 代表数字 13. 16 | 因此,数字总和 = 12 + 13 = 25. 17 | */ 18 | 19 | /** 20 | * Definition for a binary tree node. 21 | * function TreeNode(val) { 22 | * this.val = val; 23 | * this.left = this.right = null; 24 | * } 25 | */ 26 | /** 27 | * @param {TreeNode} root 28 | * @return {number} 29 | */ 30 | 31 | var sumNumbers = function(root) { 32 | let res = 0; 33 | function fn(root, sum) { 34 | if(root === null) return; 35 | sum = sum * 10 + root.val; 36 | fn(root.left, sum); 37 | fn(root.right, sum); 38 | if (root.left === null && root.right === null) { 39 | res += sum; 40 | sum -= root.val; 41 | return; 42 | } 43 | } 44 | fn(root, 0); 45 | return res; 46 | }; -------------------------------------------------------------------------------- /LeetCode/1344. 时钟指针的夹角.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给你两个数 hour 和 minutes 。请你返回在时钟上,由给定时间的时针和分针组成的较小角的角度(60 单位制) 3 | */ 4 | 5 | /** 6 | * @param {number} hour 7 | * @param {number} minutes 8 | * @return {number} 9 | */ 10 | 11 | // 时针走一格是 30°,分针走一格是 6°,而分针每走一格对应的时针会走 0.5°(分针走一格表示过了 1/60 小时,1/60 * 30 = 0.5)。 12 | // 所以 m 点 n 分时,时针走了 30 * m + 0.5 * m,分针走了 6 * n,它们的夹角是 `|30 * m - 5.5 * n|`。 13 | // 但因为小时可能为 24 小时制,所以 m 需要去对 12 取余;以及形成的夹角可能是更大的那个,所以还需要再判断取小的那个。 14 | var angleClock = function(hour, minutes) { 15 | hour = hour % 12; 16 | const res = Math.abs(30 * hour - 5.5 * minutes); 17 | return Math.min(res, 360 - res); 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /LeetCode/136. 只出现一次的数字.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 3 | 说明: 4 | 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 5 | 6 | 示例 1: 7 | 输入: [2,2,1] 8 | 输出: 1 9 | 10 | 示例 2: 11 | 输入: [4,1,2,1,2] 12 | 输出: 4 13 | */ 14 | /** 15 | * @param {number[]} nums 16 | * @return {number} 17 | */ 18 | var singleNumber = function(nums) { 19 | for(let i=0, len=nums.length; i a - b); 29 | let len = nums.length; 30 | if(nums[0] !== nums[1]) return nums[0]; 31 | if(nums[len-1] !== nums[len-2]) return nums[len-1]; 32 | for(let i=1; i a ^ c ^ b 43 | // 2. 任何数和0异或结果为任何数: 0 ^ n => n 44 | // 3. 相同的数异或为0: n ^ n => 0 45 | var singleNumber = function(nums) { 46 | let res = 0; 47 | nums.forEach(val => { 48 | res ^= val; 49 | }) 50 | return res; 51 | } -------------------------------------------------------------------------------- /LeetCode/141. 环形链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个链表,判断链表中是否有环。 3 | 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 4 | */ 5 | /** 6 | * Definition for singly-linked list. 7 | * function ListNode(val) { 8 | * this.val = val; 9 | * this.next = null; 10 | * } 11 | */ 12 | /** 13 | * @param {ListNode} head 14 | * @return {boolean} 15 | */ 16 | 17 | // 使用 map 存储每一个节点的地址 18 | var hasCycle = function(head) { 19 | let map = new Map(); 20 | while(head) { 21 | if(map.get(head) === true) { 22 | return true; 23 | } 24 | else { 25 | map.set(head, true); 26 | } 27 | head = head.next; 28 | } 29 | return false; 30 | }; 31 | 32 | // 快慢指针 33 | var hasCycle = function(head) { 34 | if(head === null) { 35 | return false; 36 | } 37 | let slow = head; 38 | let fast = head; 39 | while(fast !== null && fast.next !== null) { 40 | slow = slow.next; 41 | fast = fast.next.next; 42 | if(slow === fast) { 43 | return true; 44 | } 45 | } 46 | return false; 47 | }; 48 | 49 | // 快慢指针 50 | var hasCycle = function(head) { 51 | if(head === null) { 52 | return false; 53 | } 54 | let slow = head; 55 | let fast = head.next; 56 | while(slow !== null && fast !== null) { 57 | if(slow === fast) { 58 | return true; 59 | } 60 | if(fast.next === null) { 61 | return false; 62 | } 63 | slow = slow.next; 64 | fast = fast.next.next; 65 | } 66 | return false; 67 | }; -------------------------------------------------------------------------------- /LeetCode/144. 二叉树的前序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,返回它的 后序 遍历。 3 | */ 4 | /* 5 | 给定一个二叉树,返回它的 前序 遍历。 6 | */ 7 | /** 8 | * Definition for a binary tree node. 9 | * function TreeNode(val) { 10 | * this.val = val; 11 | * this.left = this.right = null; 12 | * } 13 | */ 14 | /** 15 | * @param {TreeNode} root 16 | * @return {number[]} 17 | */ 18 | 19 | // 递归 20 | var preorderTraversal = function(root) { 21 | let res = []; 22 | function print(root) { 23 | if(!root) return root; 24 | res.push(root.val); 25 | print(root.left); 26 | print(root.right); 27 | } 28 | print(root); 29 | return res; 30 | }; 31 | 32 | // 迭代 33 | var preorderTraversal = function(root) { 34 | if(root === null) return []; 35 | let res = []; 36 | let stack = [root]; 37 | while(stack.length) { 38 | let top = stack.shift(); 39 | res.push(top.val); 40 | if(top.right) stack.unshift(top.right); 41 | if(top.left) stack.unshift(top.left); 42 | } 43 | return res; 44 | } 45 | -------------------------------------------------------------------------------- /LeetCode/145. 二叉树的后序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,返回它的 后序 遍历。 3 | */ 4 | /* 5 | 给定一个二叉树,返回它的 前序 遍历。 6 | */ 7 | /** 8 | * Definition for a binary tree node. 9 | * function TreeNode(val) { 10 | * this.val = val; 11 | * this.left = this.right = null; 12 | * } 13 | */ 14 | /** 15 | * @param {TreeNode} root 16 | * @return {number[]} 17 | */ 18 | 19 | // 递归 20 | var postorderTraversal = function(root) { 21 | let res = []; 22 | function print(root) { 23 | if(!root) return root; 24 | print(root.left); 25 | print(root.right); 26 | res.push(root.val); 27 | } 28 | print(root); 29 | return res; 30 | }; 31 | 32 | // 迭代 33 | var postorderTraversal = function(root) { 34 | if(root === null) return []; 35 | let res = []; 36 | let stack = [root]; 37 | while(stack.length) { 38 | let top = stack.shift(); 39 | if(top.left) stack.unshift(top.left); 40 | if(top.right) stack.unshift(top.right); 41 | res.unshift(top.val); 42 | } 43 | return res; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /LeetCode/147. 对链表进行插入排序.js: -------------------------------------------------------------------------------- 1 | /* 2 | 对链表进行插入排序。 3 | 插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。 4 | 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。 5 | 插入排序算法: 6 | 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。 7 | 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。 8 | 重复直到所有输入数据插入完为止。 9 | 10 | 示例 1: 11 | 输入: 4->2->1->3 12 | 输出: 1->2->3->4 13 | */ 14 | /** 15 | * Definition for singly-linked list. 16 | * function ListNode(val) { 17 | * this.val = val; 18 | * this.next = null; 19 | * } 20 | */ 21 | /** 22 | * @param {ListNode} head 23 | * @return {ListNode} 24 | */ 25 | 26 | // 跟选择排序差不多 27 | var insertionSortList = function(head) { 28 | let cur = head; 29 | let ans = null; 30 | while(cur) { 31 | // 先缓存下一个节点信息防止待会被更改了影响循环的进行 32 | let next = cur.next; 33 | // mark为false时代表当前节点要插在已排序链表的首部 34 | // 分为已排序链表为空和已排序链表第一个节点大于当前节点两种情况 35 | let mark = false; 36 | let ansCur = ans; 37 | while(ans) { 38 | if(ans.val > cur.val) { 39 | break; 40 | } 41 | if(ansCur.next === null || ansCur.next.val > cur.val) { 42 | let tem = ansCur.next; 43 | ansCur.next = cur; 44 | cur.next = tem; 45 | mark = true; 46 | break; 47 | } 48 | ansCur = ansCur.next; 49 | } 50 | if(!mark) { 51 | let temp = ans; 52 | ans = cur; 53 | cur.next = temp; 54 | } 55 | cur = next; 56 | } 57 | return ans; 58 | }; -------------------------------------------------------------------------------- /LeetCode/148. 排序链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。 3 | 4 | 示例 1: 5 | 输入: 4->2->1->3 6 | 输出: 1->2->3->4 7 | 8 | 示例 2: 9 | 输入: -1->5->3->4->0 10 | 输出: -1->0->3->4->5 11 | */ 12 | /** 13 | * Definition for singly-linked list. 14 | * function ListNode(val) { 15 | * this.val = val; 16 | * this.next = null; 17 | * } 18 | */ 19 | /** 20 | * @param {ListNode} head 21 | * @return {ListNode} 22 | */ 23 | // 数组缓存 24 | var sortList = function(head) { 25 | let cur = head; 26 | let arr = []; 27 | while(cur) { 28 | arr.push(cur.val); 29 | cur = cur.next; 30 | } 31 | arr.sort((a, b) => a - b); 32 | console.log(arr); 33 | cur = head; 34 | let index = 0; 35 | while(cur) { 36 | cur.val = arr[index++]; 37 | cur = cur.next; 38 | } 39 | return head; 40 | }; 41 | 42 | // 选择排序 43 | var sortList = function(head) { 44 | let l1 = head; 45 | while(l1) { 46 | let l2 = l1; 47 | while(l2) { 48 | if(l2.val < l1.val) { 49 | [l1.val, l2.val] = [l2.val, l1.val]; 50 | } 51 | l2 = l2.next; 52 | } 53 | l1 = l1.next; 54 | } 55 | return head; 56 | }; -------------------------------------------------------------------------------- /LeetCode/15. 三数之和.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 3 | 注意:答案中不可以包含重复的三元组。 4 | 5 | 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], 6 | 满足要求的三元组集合为: 7 | [ 8 | [-1, 0, 1], 9 | [-1, -1, 2] 10 | ] 11 | */ 12 | /** 13 | * @param {number[]} nums 14 | * @return {number[][]} 15 | */ 16 | 17 | // 将数组排序后遍历数组,将问题转化成在当前元素之后的数组中寻找两个数使得nums[l] + nums[r] = -nums[i]。 18 | // 也就是三数之和转换为两数之和 19 | // 问题的另一个关键在于需要去掉重复的数字,比如 [-2,0,0,2,2] 20 | var threeSum = function(nums) { 21 | nums.sort((a, b) => a - b); 22 | let res = []; 23 | for(let i=0, len=nums.length; i -nums[i]) { 30 | // 去重 31 | while(nums[r] === nums[r-1] && l < r) r--; 32 | r--; 33 | } 34 | else if(nums[l] + nums[r] < -nums[i]) { 35 | // 去重 36 | while(nums[l] === nums[l+1] && l < r) l++; 37 | l++; 38 | } 39 | else { 40 | res.push([nums[i], nums[l], nums[r]]); 41 | // 去重 42 | while(nums[r] === nums[r-1] && l < r) r--; 43 | while(nums[l] === nums[l+1] && l < r) l++; 44 | l++; 45 | r--; 46 | } 47 | } 48 | } 49 | return res; 50 | } -------------------------------------------------------------------------------- /LeetCode/154. 寻找旋转排序数组中的最小值 II.js: -------------------------------------------------------------------------------- 1 | /* 2 | 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 3 | ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 4 | 请找出其中最小的元素。注意数组中可能存在重复的元素。 5 | 6 | 示例 1: 7 | 输入: [1,3,5] 8 | 输出: 1 9 | 10 | 示例 2: 11 | 输入: [2,2,2,0,1] 12 | 输出: 0 13 | 14 | 说明: 15 | 这道题是 寻找旋转排序数组中的最小值 的延伸题目。 16 | 允许重复会影响算法的时间复杂度吗?会如何影响,为什么? 17 | */ 18 | 19 | /** 20 | * @param {number[]} nums 21 | * @return {number} 22 | */ 23 | 24 | // 题解参考 https://github.com/DangoSky/algorithm/blob/master/%E5%89%91%E6%8C%87Offer/%E9%9D%A2%E8%AF%95%E9%A2%9811.%20%E6%97%8B%E8%BD%AC%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%80%E5%B0%8F%E6%95%B0%E5%AD%97.js 25 | var findMin = function(nums) { 26 | for(let i=1; i nums[r]) { 39 | l = mid + 1; 40 | } else if (nums[mid] < nums[r]) { 41 | r = mid; 42 | } else { 43 | r--; 44 | } 45 | } 46 | return nums[l]; 47 | } -------------------------------------------------------------------------------- /LeetCode/160. 相交链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | 编写一个程序,找到两个单链表相交的起始节点。 3 | */ 4 | 5 | /** 6 | * Definition for singly-linked list. 7 | * function ListNode(val) { 8 | * this.val = val; 9 | * this.next = null; 10 | * } 11 | */ 12 | 13 | /** 14 | * @param {ListNode} headA 15 | * @param {ListNode} headB 16 | * @return {ListNode} 17 | */ 18 | 19 | 20 | var getIntersectionNode = function(headA, headB) { 21 | let l1 = headA; 22 | let l2 = headB; 23 | let len1 = 0; 24 | let len2 = 0; 25 | // 获取两个链表的长度 26 | while(l1 || l2) { 27 | if(l1) { 28 | l1 = l1.next; 29 | len1++; 30 | } 31 | if(l2) { 32 | l2 = l2.next; 33 | len2++; 34 | } 35 | } 36 | // 重新获取两个链表 37 | l1 = headA; 38 | l2 = headB; 39 | // 使两个链表调整到等长 40 | if(len1 > len2) { 41 | let dis = len1 - len2; 42 | while(dis--) { 43 | l1 = l1.next; 44 | } 45 | } 46 | else if(len1 < len2) { 47 | let dis = len2 - len1; 48 | while(dis--) { 49 | l2 = l2.next; 50 | } 51 | } 52 | // 找到指向相同地址的链表入口 53 | let ans = null; 54 | while(l1 && l2) { 55 | if(l1 === l2) { 56 | ans = l1; 57 | break; 58 | } 59 | l1 = l1.next; 60 | l2 = l2.next; 61 | } 62 | return ans; 63 | }; -------------------------------------------------------------------------------- /LeetCode/167. 两数之和 II - 输入有序数组.js: -------------------------------------------------------------------------------- 1 | /* 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 2 | 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。 3 | 4 | 说明: 5 | 返回的下标值(index1 和 index2)不是从零开始的。 6 | 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 7 | 示例: 8 | 9 | 输入: numbers = [2, 7, 11, 15], target = 9 10 | 输出: [1,2] 11 | 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。 */ 12 | 13 | 14 | 15 | // 方法一:暴力循环 16 | var twoSum = function(numbers, target) { 17 | let len = numbers.length; 18 | for(let i=0; i A 5 | 2 -> B 6 | 3 -> C 7 | ... 8 | 26 -> Z 9 | 27 -> AA 10 | 28 -> AB 11 | ... 12 | 13 | 示例 1: 14 | 输入: 1 15 | 输出: "A" 16 | 17 | 示例 2: 18 | 输入: 28 19 | 输出: "AB" 20 | */ 21 | 22 | 23 | var convertToTitle = function(n) { 24 | let str = ''; 25 | while(n > 0) { 26 | let tem = parseInt(n % 26); 27 | tem = tem ? tem + 64 : 90; 28 | str = String.fromCharCode(tem) + str; 29 | if(n % 26 === 0) n--; 30 | n = parseInt(n / 26); 31 | } 32 | return str; 33 | }; 34 | console.log(convertToTitle(701)); 35 | console.log(convertToTitle(27)); 36 | console.log(convertToTitle(52)); -------------------------------------------------------------------------------- /LeetCode/169. 求众数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 3 | 你可以假设数组是非空的,并且给定的数组总是存在众数。 4 | 5 | 示例 1: 6 | 输入: [3,2,3] 7 | 输出: 3 8 | */ 9 | 10 | // 哈希 11 | var majorityElement = function(nums) { 12 | let arr = []; 13 | let mark = Math.floor(nums.length / 2); 14 | for(let i=0, len=nums.length; i mark) { 17 | return nums[i]; 18 | } 19 | } 20 | }; 21 | 22 | // 摩尔投票算法 23 | // 出现次数大于 ⌊ n/2 ⌋ 的元素,最多只有一个 24 | var majorityElement = function(nums) { 25 | let res = nums[0]; 26 | let count = 1; 27 | for(let i=1, len=nums.length; i 1 6 | B -> 2 7 | C -> 3 8 | ... 9 | Z -> 26 10 | AA -> 27 11 | AB -> 28 12 | ... 13 | 14 | 示例 1: 15 | 输入: "A" 16 | 输出: 1 17 | 18 | 示例 2: 19 | 输入: "AB" 20 | 输出: 28 21 | */ 22 | 23 | 24 | var titleToNumber = function(s) { 25 | let len = s.length; 26 | let res = 0; 27 | for(let i=0; i= 5) { 24 | res += parseInt( n / 5); 25 | n = parseInt(n / 5); 26 | } 27 | return res; 28 | }; -------------------------------------------------------------------------------- /LeetCode/175. 组合两个表.sql: -------------------------------------------------------------------------------- 1 | /* 2 | 表1: Person 3 | 4 | +-------------+---------+ 5 | | 列名 | 类型 | 6 | +-------------+---------+ 7 | | PersonId | int | 8 | | FirstName | varchar | 9 | | LastName | varchar | 10 | +-------------+---------+ 11 | PersonId 是上表主键 12 | 表2: Address 13 | 14 | +-------------+---------+ 15 | | 列名 | 类型 | 16 | +-------------+---------+ 17 | | AddressId | int | 18 | | PersonId | int | 19 | | City | varchar | 20 | | State | varchar | 21 | +-------------+---------+ 22 | AddressId 是上表主键 23 |   24 | 编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息:FirstName, LastName, City, State。 25 | */ 26 | 27 | 28 | -- 左连接 29 | select FirstName, LastName, City, State 30 | from Person left join Address 31 | on Person.PersonId = Address.PersonId; -------------------------------------------------------------------------------- /LeetCode/179. 最大数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。 3 | 4 | 示例 1: 5 | 输入: [10,2] 6 | 输出: 210 7 | */ 8 | 9 | // 从评论区看到的一个神仙操作 10 | var largestNumber = function(nums) { 11 | nums.sort((a, b) => { 12 | let str1 = a.toString(); 13 | let str2 = b.toString(); 14 | return (`${str1}${str2}` > `${str2}${str1}`) ? -1 : 1; 15 | }) 16 | let ans = nums.join(''); 17 | if(Number(ans) === 0) return '0'; 18 | return ans; 19 | } 20 | console.log(largestNumber([128,12])); 21 | console.log(largestNumber([3,30,34,5,9])); 22 | console.log(largestNumber([0, 0])); 23 | 24 | -------------------------------------------------------------------------------- /LeetCode/181. 超过经理收入的员工.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Employee 表包含所有员工,他们的经理也属于员工。每个员工都有一个 Id,此外还有一列对应员工的经理的 Id。 3 | 4 | +----+-------+--------+-----------+ 5 | | Id | Name | Salary | ManagerId | 6 | +----+-------+--------+-----------+ 7 | | 1 | Joe | 70000 | 3 | 8 | | 2 | Henry | 80000 | 4 | 9 | | 3 | Sam | 60000 | NULL | 10 | | 4 | Max | 90000 | NULL | 11 | +----+-------+--------+-----------+ 12 | 给定 Employee 表,编写一个 SQL 查询,该查询可以获取收入超过他们经理的员工的姓名。在上面的表格中,Joe 是唯一一个收入超过他的经理的员工。 13 | 14 | +----------+ 15 | | Employee | 16 | +----------+ 17 | | Joe | 18 | +----------+ 19 | */ 20 | 21 | -- 这里需要获取两次数据表信息,一次用于遍历员工,另一次用于查该员工的经理的收入 22 | -- 对于需要查两次表的,就得 from 两次表,这样会产生 n^2 个记录,n 是该表的行数。 23 | select a.Name as Employee 24 | from Employee a, Employee b 25 | where 26 | a.ManagerId = b.Id 27 | AND 28 | a.Salary > b.Salary; 29 | 30 | 31 | -- 不获取两次数据表,而是建立个临时表 32 | select a.Name as Employee 33 | from Employee a, ( 34 | select Salary, Id from Employee 35 | ) b 36 | where 37 | a.ManagerId = b.Id 38 | AND 39 | a.Salary > b.Salary 40 | 41 | 42 | -- 连接两个表 43 | select a.Name as Employee 44 | from Employee a inner join Employee b 45 | on 46 | a.ManagerId = b.Id 47 | AND 48 | a.Salary > b.Salary -------------------------------------------------------------------------------- /LeetCode/182. 查找重复的电子邮箱.sql: -------------------------------------------------------------------------------- 1 | /* 2 | 编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。 3 | 4 | 示例: 5 | 6 | +----+---------+ 7 | | Id | Email | 8 | +----+---------+ 9 | | 1 | a@b.com | 10 | | 2 | c@d.com | 11 | | 3 | a@b.com | 12 | +----+---------+ 13 | 根据以上输入,你的查询应返回以下结果: 14 | 15 | +---------+ 16 | | Email | 17 | +---------+ 18 | | a@b.com | 19 | +---------+ 20 | 说明:所有电子邮箱都是小写字母。 21 | */ 22 | 23 | -- 等值连接后,使用 distinct 去重 24 | select distinct a.Email 25 | from Person a inner join Person b 26 | on 27 | a.Email = b.Email 28 | AND 29 | a.Id != b.Id; 30 | 31 | 32 | -- 先计算表中相同数据的个数,生成临时表再做筛选 33 | select Email from ( 34 | select Email, count(Email) as num 35 | from Person 36 | group by Email 37 | ) temp_table 38 | where num > 1 -------------------------------------------------------------------------------- /LeetCode/183. 从不订购的客户.sql: -------------------------------------------------------------------------------- 1 | /* 2 | 某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户。 3 | 4 | Customers 表: 5 | 6 | +----+-------+ 7 | | Id | Name | 8 | +----+-------+ 9 | | 1 | Joe | 10 | | 2 | Henry | 11 | | 3 | Sam | 12 | | 4 | Max | 13 | +----+-------+ 14 | Orders 表: 15 | 16 | +----+------------+ 17 | | Id | CustomerId | 18 | +----+------------+ 19 | | 1 | 3 | 20 | | 2 | 1 | 21 | +----+------------+ 22 | 例如给定上述表格,你的查询应返回: 23 | 24 | +-----------+ 25 | | Customers | 26 | +-----------+ 27 | | Henry | 28 | | Max | 29 | +-----------+ 30 | */ 31 | 32 | -- not in 33 | select Name as Customers from Customers 34 | where Id not in ( 35 | select CustomerId from Orders 36 | ) ; 37 | -------------------------------------------------------------------------------- /LeetCode/189. 旋转数组.js: -------------------------------------------------------------------------------- 1 | /* 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 2 | Do not return anything, modify nums in-place instead. 3 | 4 | 示例 1: 5 | 输入: [1,2,3,4,5,6,7] 和 k = 3 6 | 输出: [5,6,7,1,2,3,4] */ 7 | 8 | 9 | // 方法一: 创建一个新数组,一个用于修改,一个用于查询原先的值 10 | var rotate = function(nums, k) { 11 | let len = nums.length; 12 | let arr = nums.slice(); 13 | for(let i=0; i= len ? (i+k-len)%len : i+k; 15 | nums[tem] = arr[i]; 16 | } 17 | }; 18 | rotate([1,2,3,4,5,6,7], 3); 19 | 20 | 21 | // 方法二: 使用map循环,根据结果数组的每一位反推到原始数组对应的那一位 22 | var rotate = function(nums, k) { 23 | let len = nums.length; 24 | nums = nums.map((val, index) => { 25 | let tem = index-k < 0 ? (len+index-k)%len : index-k; 26 | return nums[tem]; 27 | }) 28 | }; 29 | rotate([1, 2], 2); 30 | 31 | 32 | // 方法二: 最简单的办法 33 | var rotate = function(nums, k) { 34 | while(k--) { 35 | nums.unshift(nums.pop()); 36 | } 37 | } -------------------------------------------------------------------------------- /LeetCode/191. 位1的个数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 191. 位1的个数 3 | 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 4 | 5 | 示例 1: 6 | 输入:00000000000000000000000000001011 7 | 输出:3 8 | 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 9 | */ 10 | 11 | /** 12 | * @param {number} n - a positive integer 13 | * @return {number} 14 | */ 15 | 16 | // 对于任意数字 n,将 n 和 n-1 做与运算,都会把最后一个 1 的位变成 0。所以一直对两者做与运算,直至 n 变成 0 即可 17 | var hammingWeight = function(n) { 18 | let res = 0; 19 | while(n) { 20 | n = n & (n - 1); 21 | res++; 22 | } 23 | return res; 24 | }; 25 | -------------------------------------------------------------------------------- /LeetCode/196. 删除重复的电子邮箱.sql: -------------------------------------------------------------------------------- 1 | /* 2 | 编写一个 SQL 查询,来删除 Person 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。 3 | 4 | +----+------------------+ 5 | | Id | Email | 6 | +----+------------------+ 7 | | 1 | john@example.com | 8 | | 2 | bob@example.com | 9 | | 3 | john@example.com | 10 | +----+------------------+ 11 | 12 | Id 是这个表的主键。 13 | 例如,在运行你的查询语句之后,上面的 Person 表应返回以下几行: 14 | 15 | +----+------------------+ 16 | | Id | Email | 17 | +----+------------------+ 18 | | 1 | john@example.com | 19 | | 2 | bob@example.com | 20 | +----+------------------+ 21 |   22 | 23 | 提示: 24 | 执行 SQL 之后,输出是整个 Person 表。 25 | 使用 delete 语句。 26 | */ 27 | 28 | 29 | -- 还是笛卡尔积,可以先筛选出重复的并且 ID 更大的数据,再把它们删掉即可 30 | delete a from Person a, Person b 31 | where 32 | a.Email = b.Email 33 | AND 34 | a.Id > b.Id -------------------------------------------------------------------------------- /LeetCode/199. 二叉树的右视图.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 3 | 4 | 示例: 5 | 输入: [1,2,3,null,5,null,4] 6 | 输出: [1, 3, 4] 7 | 解释: 8 | 9 | 1 <--- 10 | / \ 11 | 2 3 <--- 12 | \ \ 13 | 5 4 <--- 14 | */ 15 | 16 | /** 17 | * Definition for a binary tree node. 18 | * function TreeNode(val) { 19 | * this.val = val; 20 | * this.left = this.right = null; 21 | * } 22 | */ 23 | /** 24 | * @param {TreeNode} root 25 | * @return {number[]} 26 | */ 27 | var rightSideView = function(root) { 28 | const res = []; 29 | (function dfs(root, deep) { 30 | if(root === null) return; 31 | if (deep > res.length) { 32 | res.push(root.val); 33 | } 34 | if (root.right) { 35 | dfs(root.right, deep + 1); 36 | } 37 | if (root.left) { 38 | dfs(root.left, deep + 1); 39 | } 40 | })(root, 1) 41 | return res; 42 | }; -------------------------------------------------------------------------------- /LeetCode/20. 有效的括号.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 3 | 4 | 有效字符串需满足: 5 | 左括号必须用相同类型的右括号闭合。 6 | 左括号必须以正确的顺序闭合。 7 | 注意空字符串可被认为是有效字符串。 8 | */ 9 | 10 | // 使用正则将成对的括号替换成空字符。 11 | // 如果替换前后的字符串长度没有改变则退出循环判断字符串是否为空,为空的话就是有效的括号。 12 | var isValid = function(s) { 13 | do { 14 | var len = s.length; 15 | s = s.replace("()", "").replace("[]", "").replace("{}", ""); 16 | } while(s.length !== len) 17 | return s.length === 0; 18 | }; 19 | 20 | // 使用栈 21 | var isValid = function(s) { 22 | let len = s.length; 23 | if(len % 2) { 24 | return false; 25 | } 26 | let map = new Map([ 27 | ["(", ")"], 28 | ["[", "]"], 29 | ["{", "}"] 30 | ]); 31 | let arr = []; 32 | for(let i=0; i= 'a' ? num1++ : num2++; 17 | if(num1 >= 1 && num2 >= 1) { 18 | // 首字母是小写是则直接false 19 | if(word[0] >= 'a') { 20 | return false; 21 | } 22 | // 首字母是大写是则得等到出现两个大写字母时才false 23 | else if(num2 >= 2) { 24 | return false; 25 | } 26 | } 27 | } 28 | return true; 29 | }; 30 | console.log(detectCapitalUse("ffffffffffffffffffffF")); 31 | console.log(detectCapitalUse("FlaG")); 32 | console.log(detectCapitalUse("Leetcode")); -------------------------------------------------------------------------------- /LeetCode/202. 快乐数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 编写一个算法来判断一个数是不是“快乐数”。 3 | 一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。 4 | 5 | 示例: 6 | 输入: 19 7 | 输出: true 8 | 解释: 9 | 12 + 92 = 82 10 | 82 + 22 = 68 11 | 62 + 82 = 100 12 | 12 + 02 + 02 = 1 13 | */ 14 | 15 | // 使用一个数组记录每次求平方和后的值,若出现重复则不是快乐数 16 | var isHappy = function(n) { 17 | let arr = []; 18 | while(true) { 19 | let num = 0; 20 | let str = n.toString(); 21 | for(let i=0; i2->6->3->4->5->6, val = 6 6 | 输出: 1->2->3->4->5 7 | */ 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val) { 11 | * this.val = val; 12 | * this.next = null; 13 | * } 14 | */ 15 | /** 16 | * @param {ListNode} head 17 | * @param {number} val 18 | * @return {ListNode} 19 | */ 20 | var removeElements = function(head, val) { 21 | let cur = head; 22 | while(cur) { 23 | if(cur.val === val) { 24 | head = cur.next; 25 | cur = head; 26 | continue; 27 | } 28 | if(cur.next && cur.next.val === val) { 29 | cur.next = cur.next.next; 30 | continue; 31 | } 32 | cur = cur.next; 33 | } 34 | return head; 35 | }; 36 | 37 | // 递归 38 | var removeElements = function(head, val) { 39 | if(head === null) { 40 | return head; 41 | } 42 | head.next = removeElements(head.next, val); 43 | return head.val === val ? head.next : head; 44 | }; -------------------------------------------------------------------------------- /LeetCode/204. 计数质数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 统计所有小于非负整数 n 的质数的数量。 3 | 4 | 示例: 5 | 输入: 10 6 | 输出: 4 7 | 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7。 8 | */ 9 | /** 10 | * @param {number} n 11 | * @return {number} 12 | */ 13 | 14 | var countPrimes = function(n) { 15 | // 判断是否是质数 16 | function judge(n) { 17 | for(let i=2, len=Math.sqrt(n); i<=len; i++) { 18 | if(n % i === 0) return false; 19 | } 20 | return true; 21 | } 22 | let ans = 0; 23 | for(let i=2; i2->3->4->5->NULL 6 | 输出: 5->4->3->2->1->NULL 7 | */ 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val) { 11 | * this.val = val; 12 | * this.next = null; 13 | * } 14 | */ 15 | /** 16 | * @param {ListNode} head 17 | * @return {ListNode} 18 | */ 19 | 20 | // 使用一个数组存储每个节点的值,再从数组尾部开始给每一个节点赋值 21 | var reverseList = function(head) { 22 | let arr = []; 23 | let cur = head; 24 | while(cur) { 25 | arr.push(cur.val); 26 | cur = cur.next; 27 | } 28 | cur = head; 29 | for(let i=arr.length-1; i>=0; i--) { 30 | cur.val = arr[i]; 31 | cur = cur.next; 32 | } 33 | return head; 34 | }; 35 | 36 | // 递归 37 | var reverseList = function(head) { 38 | if(head === null || head.next === null) { 39 | return head; 40 | } 41 | let cur = reverseList(head.next); 42 | head.next.next = head 43 | head.next = null; 44 | return cur; 45 | }; 46 | 47 | // 从第一个节点开始遍历,pre 初始化为 null 48 | var reverseList = function(head) { 49 | let cur = head; 50 | let pre = null 51 | while(cur) { 52 | let temp = cur.next; 53 | cur.next = pre; 54 | pre = cur; 55 | cur = temp; 56 | } 57 | return pre; 58 | }; 59 | 60 | // 从第二个节点开始遍历,pre 初始化为头节点 61 | var reverseList = function(head) { 62 | if(!head) { 63 | return null; 64 | } 65 | let cur = head.next; 66 | let pre = head; 67 | pre.next = null; 68 | while(cur) { 69 | let temp = cur.next; 70 | cur.next = pre; 71 | pre = cur; 72 | cur = temp; 73 | } 74 | return pre; 75 | }; -------------------------------------------------------------------------------- /LeetCode/215. 数组中的第K个最大元素.js: -------------------------------------------------------------------------------- 1 | /* 2 | 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 3 | 4 | 示例 1: 5 | 输入: [3,2,1,5,6,4] 和 k = 2 6 | 输出: 5 7 | 8 | 示例 2: 9 | 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 10 | 输出: 4 11 | 12 | 说明: 13 | 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。 14 | */ 15 | /** 16 | * @param {number[]} nums 17 | * @param {number} k 18 | * @return {number} 19 | */ 20 | 21 | // 使用快排对数组进行划分 22 | var findKthLargest = function(nums, k) { 23 | function rec(arr, left, right) { 24 | if(left > right) return; 25 | // 降序排列 26 | let index = partition(arr, left, right); 27 | if(k === index + 1) { 28 | return arr[index]; 29 | } 30 | // 目标元素比arr[index]小 31 | else if(k > index + 1) { 32 | return rec(arr, index + 1, right); 33 | } 34 | // 目标元素比arr[index]大 35 | else if(k < index + 1) { 36 | return rec(arr, left, index - 1); 37 | } 38 | } 39 | function partition(arr, left, right) { 40 | let temp = arr[left]; 41 | while(left < right) { 42 | while(left < right && arr[right] <= temp) right--; 43 | arr[left] = arr[right]; 44 | while(left < right && arr[left] > temp) left++; 45 | arr[right] = arr[left]; 46 | } 47 | arr[left] = temp; 48 | return left; 49 | } 50 | return rec(nums, 0, nums.length-1); 51 | }; -------------------------------------------------------------------------------- /LeetCode/217. 存在重复元素.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个整数数组,判断是否存在重复元素。 3 | 如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 4 | 5 | 示例 1: 6 | 输入: [1,2,3,1] 7 | 输出: true 8 | 9 | 示例 2: 10 | 输入: [1,2,3,4] 11 | 输出: false 12 | */ 13 | /** 14 | * @param {number[]} nums 15 | * @return {boolean} 16 | */ 17 | var containsDuplicate = function(nums) { 18 | for(let i=0, len=nums.length; i= 0 && i - obj[tem] <= k) { 26 | return true; 27 | } 28 | obj[tem] = i; 29 | } 30 | return false; 31 | } 32 | console.log(containsNearbyDuplicate([1, 2, 3, 1], 3)); -------------------------------------------------------------------------------- /LeetCode/225. 用队列实现栈.js: -------------------------------------------------------------------------------- 1 | /* 2 | 使用队列实现栈的下列操作: 3 | push(x) -- 元素 x 入栈 4 | pop() -- 移除栈顶元素 5 | top() -- 获取栈顶元素 6 | empty() -- 返回栈是否为空 7 | 8 | 注意: 9 | 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。 10 | 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。 11 | 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。 12 | */ 13 | 14 | /** 15 | * Initialize your data structure here. 16 | */ 17 | var MyStack = function() { 18 | this.arr = []; 19 | }; 20 | 21 | /** 22 | * Push element x onto stack. 23 | * @param {number} x 24 | * @return {void} 25 | */ 26 | MyStack.prototype.push = function(x) { 27 | this.arr.unshift(x); 28 | }; 29 | 30 | /** 31 | * Removes the element on top of the stack and returns that element. 32 | * @return {number} 33 | */ 34 | MyStack.prototype.pop = function() { 35 | if(this.arr.length !== 0) { 36 | return this.arr.shift(); 37 | } 38 | }; 39 | 40 | /** 41 | * Get the top element. 42 | * @return {number} 43 | */ 44 | MyStack.prototype.top = function() { 45 | if(this.arr.length !== 0) { 46 | return this.arr[0]; 47 | } 48 | }; 49 | 50 | /** 51 | * Returns whether the stack is empty. 52 | * @return {boolean} 53 | */ 54 | MyStack.prototype.empty = function() { 55 | return this.arr.length === 0 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 | */ -------------------------------------------------------------------------------- /LeetCode/226. 翻转二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 翻转一棵二叉树。 3 | 示例: 4 | 输入: 5 | 4 6 | / \ 7 | 2 7 8 | / \ / \ 9 | 1 3 6 9 10 | 输出: 11 | 12 | 4 13 | / \ 14 | 7 2 15 | / \ / \ 16 | 9 6 3 1 17 | 备注: 18 | 19 | 这个问题是受到 Max Howell 的 原问题 启发的: 20 | 谷歌:我们90%的工程师使用您编写的软件(Homebrew),但是您却无法在面试时在白板上写出翻转二叉树这道题,这太糟糕了。 21 | */ 22 | /** 23 | * Definition for a binary tree node. 24 | * function TreeNode(val) { 25 | * this.val = val; 26 | * this.left = this.right = null; 27 | * } 28 | */ 29 | /** 30 | * @param {TreeNode} root 31 | * @return {TreeNode} 32 | */ 33 | 34 | var invertTree = function(root) { 35 | if(root === null) return root; 36 | let left = invertTree(root.left); 37 | let right = invertTree(root.right); 38 | root.left = right; 39 | root.right = left; 40 | return root; 41 | } 42 | -------------------------------------------------------------------------------- /LeetCode/229. 求众数 II.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。 3 | 说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。 4 | 5 | 示例 1: 6 | 输入: [3,2,3] 7 | 输出: [3] 8 | 9 | 示例 2: 10 | 输入: [1,1,1,3,3,2,2,2] 11 | 输出: [1,2] 12 | */ 13 | /** 14 | * @param {number[]} nums 15 | * @return {number[]} 16 | */ 17 | 18 | // 同 169 题 19 | // 最多只有两个数 20 | var majorityElement = function(nums) { 21 | let n = 0, m = 0; 22 | let cn = 0, cm = 0; 23 | for(let i=0, len=nums.length; i temp) res.push(m); 48 | if(cn > temp) res.push(n); 49 | return res; 50 | }; -------------------------------------------------------------------------------- /LeetCode/230. 二叉搜索树中第K小的元素.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。 3 | 说明: 4 | 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。 5 | 6 | 示例 1: 7 | 输入: root = [3,1,4,null,2], k = 1 8 | 3 9 | / \ 10 | 1 4 11 | \ 12 | 2 13 | 输出: 1 14 | 15 | 示例 2: 16 | 输入: root = [5,3,6,2,4,null,null,1], k = 3 17 | 5 18 | / \ 19 | 3 6 20 | / \ 21 | 2 4 22 | / 23 | 1 24 | 输出: 3 25 | 进阶: 26 | 如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数? 27 | */ 28 | /** 29 | * Definition for a binary tree node. 30 | * function TreeNode(val) { 31 | * this.val = val; 32 | * this.left = this.right = null; 33 | * } 34 | */ 35 | /** 36 | * @param {TreeNode} root 37 | * @param {number} k 38 | * @return {number} 39 | */ 40 | // 对于二叉搜索树,中序遍历后的序列就是二叉树的升序序列 41 | // 注意不要使用字符串 42 | var kthSmallest = function(root, k) { 43 | let res = []; 44 | function print(root) { 45 | if(root === null) return root; 46 | print(root.left); 47 | res.push(root.val); 48 | print(root.right); 49 | } 50 | print(root); 51 | return res[k-1]; 52 | }; 53 | 54 | // 不遍历整个二叉树,只遍历到第k小的数 55 | var kthSmallest = function(root, k) { 56 | let res = 0; 57 | (function fn(root) { 58 | if(root === null || k <= 0) { 59 | return; 60 | } 61 | fn(root.left); 62 | res = k > 0 ? root.val : res; 63 | k--; 64 | fn(root.right); 65 | })(root) 66 | return res; 67 | } 68 | -------------------------------------------------------------------------------- /LeetCode/231. 2的幂.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 3 | */ 4 | 5 | // 打表 6 | var isPowerOfTwo = function(n) { 7 | let res = new Map(); 8 | for(let i=1; i<10000000000; i=i*2) { 9 | res.set(i, true); 10 | } 11 | return res.get(n) ? true : false; 12 | }; 13 | 14 | // 递归除2 15 | var isPowerOfTwo = function(n) { 16 | if(n === 1) { 17 | return true; 18 | } 19 | else if(n % 2 === 1 || n === 0) { 20 | return false; 21 | } 22 | else { 23 | return isPowerOfTwo(n / 2); 24 | } 25 | }; 26 | 27 | 28 | // 若是2的幂,则其二进制数中只有一个1。使用位运算 29 | var isPowerOfTwo = function(n) { 30 | if(n <= 0) { 31 | return false; 32 | } 33 | let res = 0; 34 | while(n) { 35 | n &= (n-1); // 去除n最右边的1 36 | res++; 37 | } 38 | return res === 1; 39 | }; 40 | 41 | 42 | // 若是2的幂,则其二进制数中只有一个1。使用indexOf和lastIndexOf 43 | var isPowerOfTwo = function(n) { 44 | if(n <= 0) { 45 | return false; 46 | } 47 | let arr = n.toString(2).split(''); 48 | return arr.indexOf('1') === arr.lastIndexOf('1'); 49 | }; 50 | 51 | var isPowerOfTwo = function(n) { 52 | if(n <= 0) { 53 | return false; 54 | } 55 | return n & (n-1) === 0; // 若二进制数中只有一个1则返回true 56 | }; 57 | console.log(isPowerOfTwo(3)); 58 | console.log(isPowerOfTwo(16777216)); -------------------------------------------------------------------------------- /LeetCode/235. 二叉搜索树的最近公共祖先.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” 3 | 例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5] 4 | 5 | 示例 1: 6 | 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 7 | 输出: 6 8 | 解释: 节点 2 和节点 8 的最近公共祖先是 6。 9 | 10 | 示例 2: 11 | 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 12 | 输出: 2 13 | 解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。 14 | 15 | 说明: 16 | 所有节点的值都是唯一的。 17 | p、q 为不同节点且均存在于给定的二叉搜索树中。 18 | */ 19 | /** 20 | * Definition for a binary tree node. 21 | * function TreeNode(val) { 22 | * this.val = val; 23 | * this.left = this.right = null; 24 | * } 25 | */ 26 | /** 27 | * @param {TreeNode} root 28 | * @param {TreeNode} p 29 | * @param {TreeNode} q 30 | * @return {TreeNode} 31 | */ 32 | // 二叉搜索树:根节点的值大于左子树结点的值,小于右子树结点的值 33 | // 如果root的值位于p和q之间或等于其中一个值,说明该root是p和q最近的公共祖先 34 | var lowestCommonAncestor = function(root, p, q) { 35 | if(root.val > p.val && root.val > q.val) { 36 | return lowestCommonAncestor(root.left, p, q); 37 | } 38 | else if(root.val < p.val && root.val < q.val) { 39 | return lowestCommonAncestor(root.right, p, q); 40 | } 41 | return root; 42 | }; -------------------------------------------------------------------------------- /LeetCode/236. 二叉树的最近公共祖先.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 3 | 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” 4 | 5 | 示例 1: 6 | 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 7 | 输出: 3 8 | 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。 9 | 10 | 示例 2: 11 | 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 12 | 输出: 5 13 | 解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。 14 | */ 15 | /** 16 | * Definition for a binary tree node. 17 | * function TreeNode(val) { 18 | * this.val = val; 19 | * this.left = this.right = null; 20 | * } 21 | */ 22 | /** 23 | * @param {TreeNode} root 24 | * @param {TreeNode} p 25 | * @param {TreeNode} q 26 | * @return {TreeNode} 27 | */ 28 | var lowestCommonAncestor = function(root, p, q) { 29 | if(root === p || root === q || root === null) return root; 30 | let left = lowestCommonAncestor(root.left, p, q); 31 | let right = lowestCommonAncestor(root.right, p, q); 32 | // 从左右子树中都找到了p和q,此时root就是最近公共祖先 33 | if(left !== null && right !== null) return root; 34 | // 在左(右)子树中没有找到,说明p和q都在右(左)子树中,此时最先找到的就是最近公共祖先 35 | if(left === null) return right; 36 | if(right === null) return left; 37 | // 都没有找到说明p和q不在树中 38 | return null; 39 | }; -------------------------------------------------------------------------------- /LeetCode/237. 删除链表中的节点.js: -------------------------------------------------------------------------------- 1 | /* 2 | 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。 3 | */ 4 | /** 5 | * Definition for singly-linked list. 6 | * function ListNode(val) { 7 | * this.val = val; 8 | * this.next = null; 9 | * } 10 | */ 11 | /** 12 | * @param {ListNode} node 13 | * @return {void} Do not return anything, modify node in-place instead. 14 | */ 15 | var deleteNode = function(node) { 16 | node.val = node.next.val; 17 | node.next = node.next.next; 18 | }; -------------------------------------------------------------------------------- /LeetCode/24. 两两交换链表中的节点.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 3 | 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 4 | 5 | 示例: 6 | 给定 1->2->3->4, 你应该返回 2->1->4->3. 7 | */ 8 | 9 | /** 10 | * Definition for singly-linked list. 11 | * function ListNode(val) { 12 | * this.val = val; 13 | * this.next = null; 14 | * } 15 | */ 16 | /** 17 | * @param {ListNode} head 18 | * @return {ListNode} 19 | */ 20 | 21 | // 递归 22 | var swapPairs = function(head) { 23 | if(head === null || head.next === null) { 24 | return head; 25 | } 26 | let first = head; 27 | let second = first.next; 28 | let third = second.next; 29 | second.next = first; 30 | first.next = swapPairs(third); 31 | return second; 32 | }; -------------------------------------------------------------------------------- /LeetCode/257. 二叉树的所有路径.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,返回所有从根节点到叶子节点的路径。 3 | 说明: 叶子节点是指没有子节点的节点。 4 | 5 | 示例: 6 | 输入: 7 | 8 | 1 9 | / \ 10 | 2 3 11 | \ 12 | 5 13 | 14 | 输出: ["1->2->5", "1->3"] 15 | 解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3 16 | */ 17 | /** 18 | * Definition for a binary tree node. 19 | * function TreeNode(val) { 20 | * this.val = val; 21 | * this.left = this.right = null; 22 | * } 23 | */ 24 | /** 25 | * @param {TreeNode} root 26 | * @return {string[]} 27 | */ 28 | var binaryTreePaths = function(root) { 29 | let res = []; 30 | function fn(root, str) { 31 | if(root === null) return; 32 | // 到达叶子结点后就将得到的字符串路径放入到数组中 33 | if(root.left === null && root.right === null) { 34 | res.push(str + root.val); 35 | } 36 | str += root.val + "->"; 37 | return fn(root.left, str) || fn(root.right, str); 38 | } 39 | fn(root, ""); 40 | return res; 41 | }; -------------------------------------------------------------------------------- /LeetCode/258. 各位相加.js: -------------------------------------------------------------------------------- 1 | /* 给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。 2 | 3 | 示例: 4 | 输入: 38 5 | 输出: 2 6 | 解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数,所以返回 2 */ 7 | 8 | 9 | // 模拟过程 10 | var addDigits = function(num) { 11 | let sum = 0; 12 | while(num >= 1) { 13 | sum += num % 10; 14 | num = parseInt(num / 10); // js是弱语言,因此要使用parseInt()转为整数 15 | } 16 | if(sum < 10) return sum; 17 | else return addDigits(sum); 18 | }; 19 | console.log(addDigits(38)); 20 | 21 | 22 | // 直接套公式 23 | // 数组根:https://en.wikipedia.org/wiki/Digital_root 24 | var addDigits = function(num) { 25 | return 1 + (num - 1) % 9; 26 | }; 27 | console.log(addDigits(38)); -------------------------------------------------------------------------------- /LeetCode/26. 删除排序数组中的重复项.js: -------------------------------------------------------------------------------- 1 | /* 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 2 | 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 3 | 4 | 示例 1: 5 | 给定数组 nums = [1,1,2], 6 | 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 7 | 你不需要考虑数组中超出新长度后面的元素。 */ 8 | 9 | 10 | 11 | // 方法一:使用一个变量标记 12 | var removeDuplicates = function(nums) { 13 | let len = nums.length; 14 | let tem = 0; 15 | for(let i=1; i false 9 | 调用 isBadVersion(5) -> true 10 | 调用 isBadVersion(4) -> true 11 | 所以,4 是第一个错误的版本。 12 | */ 13 | /** 14 | * Definition for isBadVersion() 15 | * 16 | * @param {integer} version number 17 | * @return {boolean} whether the version is bad 18 | * isBadVersion = function(version) { 19 | * ... 20 | * }; 21 | */ 22 | 23 | /** 24 | * @param {function} isBadVersion() 25 | * @return {function} 26 | */ 27 | var solution = function(isBadVersion) { 28 | /** 29 | * @param {integer} n Total versions 30 | * @return {integer} The first bad version 31 | */ 32 | return function(n) { 33 | let i = 1, j = n; 34 | while(i <= j) { 35 | let mid = parseInt((j - i) / 2) + i; 36 | if(isBadVersion(mid)) { 37 | j = mid - 1; 38 | } 39 | else { 40 | i = mid + 1; 41 | } 42 | } 43 | return i; 44 | }; 45 | }; -------------------------------------------------------------------------------- /LeetCode/283. 移动零.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 3 | 4 | 示例: 5 | 输入: [0,1,0,3,12] 6 | 输出: [1,3,12,0,0] 7 | */ 8 | 9 | // 边删除为0的元素边添加到数组尾 10 | var moveZeroes = function(nums) { 11 | for(let i=0, len=nums.length; i2->3->4->5->NULL 7 | 输出: 1->3->5->2->4->NULL 8 | */ 9 | /** 10 | * Definition for singly-linked list. 11 | * function ListNode(val) { 12 | * this.val = val; 13 | * this.next = null; 14 | * } 15 | */ 16 | /** 17 | * @param {ListNode} head 18 | * @return {ListNode} 19 | */ 20 | // 不断变化奇偶节点 21 | var oddEvenList = function(head) { 22 | if(!head || !head.next) { 23 | return head; 24 | } 25 | let odd = head; 26 | let even = head.next; 27 | let cur = even; 28 | while(even && even.next) { 29 | odd.next = even.next; 30 | odd = odd.next; 31 | even.next = odd.next; 32 | even = even.next; 33 | } 34 | // 将偶数节点的链表链接到奇数节点的链表后面 35 | odd.next = cur; 36 | return head; 37 | }; 38 | 39 | // 数组缓存 40 | var oddEvenList = function(head) { 41 | let cur = head; 42 | let arr = []; 43 | while(cur) { 44 | arr.push(cur.val); 45 | cur = cur.next; 46 | } 47 | let i = 0, j = 1; 48 | cur = head; 49 | let index = 1; 50 | let len = Math.ceil(arr.length / 2); 51 | while(cur) { 52 | if(index <= len) { 53 | cur.val = arr[i]; 54 | i = i + 2; 55 | } 56 | else { 57 | cur.val = arr[j]; 58 | j = j + 2; 59 | } 60 | index++; 61 | cur = cur.next; 62 | } 63 | return head; 64 | }; -------------------------------------------------------------------------------- /LeetCode/338. 比特位计数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 3 | 4 | 示例 1: 5 | 输入: 2 6 | 输出: [0,1,1] 7 | */ 8 | 9 | var countBits = function(num) { 10 | let arr = []; 11 | for(let i=0; i<=num; i++) { 12 | let sum = 0; 13 | let tem = i; 14 | while(tem) { 15 | tem &= (tem - 1); 16 | sum++; 17 | } 18 | arr.push(sum); 19 | } 20 | return arr; 21 | }; 22 | 23 | 24 | // i 的最低位是0,则 i 中1的个数和 i>>1 中1的个数相同 25 | // i 的最低位是1,则 i 中1的个数是 i>>1 中1的个数再加1 26 | var countBits = function(num) { 27 | let arr = [0]; 28 | for(let i=1; i<=num; i++) { 29 | arr[i] = arr[i >> 1] + (i % 2); 30 | } 31 | return arr; 32 | }; 33 | console.log(countBits(5)); -------------------------------------------------------------------------------- /LeetCode/34. 在排序数组中查找元素的第一个和最后一个位置.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。 3 | 你的算法时间复杂度必须是 O(log n) 级别。 4 | 如果数组中不存在目标值,返回 [-1, -1]。 5 | 6 | 示例 1: 7 | 输入: nums = [5,7,7,8,8,10], target = 8 8 | 输出: [3,4] 9 | 10 | 示例 2: 11 | 输入: nums = [5,7,7,8,8,10], target = 6 12 | 输出: [-1,-1] 13 | */ 14 | 15 | var searchRange = function(nums, target) { 16 | // 当turnLeft是true时表示找左边界,为false时表示找右边界 17 | function binarySearch(arr, target, turnLeft) { 18 | let left = 0, right = arr.length - 1; 19 | while(left <= right) { 20 | let mid = parseInt((right - left) / 2) + left; 21 | // 如果当前的数组元素是target并且是要找左边界,则将右边界置为mid-1,并向左边迭代。 22 | // 如果此时arr[mid]就是左数第一个target了,那么循环结束后找不到target,left也会加1回到此时的mid 23 | if (arr[mid] > target || (turnLeft && arr[mid] === target)) { 24 | right = mid - 1; 25 | } else { 26 | left = mid + 1; 27 | } 28 | } 29 | return left; 30 | } 31 | function judge(index) { 32 | return nums[index] === target ? index : -1; 33 | } 34 | 35 | let indexLeft = judge(binarySearch(nums, target, true)); 36 | // 找右边界时,当退出循环的时候,左边的部分都大于或等于target,所以需要将下标-1 37 | let indexRight = judge(binarySearch(nums, target, false) - 1); 38 | return [indexLeft, indexRight]; 39 | }; 40 | -------------------------------------------------------------------------------- /LeetCode/344. 反转字符串.js: -------------------------------------------------------------------------------- 1 | /* 2 | 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 3 | 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 4 | 你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。 5 | */ 6 | 7 | var reverseString = function(s) { 8 | return s.reverse(); 9 | }; 10 | 11 | var reverseString = function(s) { 12 | let len = Math.ceil(s.length / 2) - 1; 13 | for(let i=0; i<=len; i++) { 14 | let tem = s.length - i - 1; 15 | [s[i], s[tem]] = [s[tem], s[i]]; 16 | } 17 | return s; 18 | }; 19 | console.log(reverseString(["h","e","l","l","o"])); 20 | console.log(reverseString(["H","a","n","n","a","h"])); -------------------------------------------------------------------------------- /LeetCode/349. 两个数组的交集.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定两个数组,编写一个函数来计算它们的交集。 3 | 4 | 示例 1: 5 | 输入: nums1 = [1,2,2,1], nums2 = [2,2] 6 | 输出: [2] 7 | 8 | 示例 2: 9 | 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] 10 | 输出: [9,4] 11 | */ 12 | /** 13 | * @param {number[]} nums1 14 | * @param {number[]} nums2 15 | * @return {number[]} 16 | */ 17 | 18 | // 时间复杂度 O(n + m),空间复杂度 O(n) 19 | var intersection = function(nums1, nums2) { 20 | let mark = []; 21 | // 需要先去重,不然得到的结果数组中可能会有重复 22 | nums1 = [...new Set(nums1)]; 23 | nums2 = [...new Set(nums2)]; 24 | for(let i=0, len=nums1.length; i { return a - b; }) 42 | nums2.sort((a, b) => { return a - b; }) 43 | const res = []; 44 | let i = 0, j = 0; 45 | while(i < nums1.length && j< nums2.length) { 46 | if (nums1[i] === nums2[j]) { 47 | res.push(nums1[i]) 48 | i++; 49 | j++; 50 | } else if (nums1[i] > nums2[j]) { 51 | j++; 52 | } else { 53 | i++; 54 | } 55 | } 56 | return res; 57 | }; 58 | -------------------------------------------------------------------------------- /LeetCode/35. 搜索插入位置.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 3 | 你可以假设数组中无重复元素。 4 | 5 | 示例 1: 6 | 输入: [1,3,5,6], 5 7 | 输出: 2 8 | 9 | 示例 2: 10 | 输入: [1,3,5,6], 2 11 | 输出: 1 12 | */ 13 | /** 14 | * @param {number[]} nums 15 | * @param {number} target 16 | * @return {number} 17 | */ 18 | 19 | var searchInsert = function(nums, target) { 20 | for(let i=0; i= target) { 22 | return i; 23 | } 24 | } 25 | return nums.length; 26 | }; 27 | 28 | // 二分 29 | var searchInsert = function(nums, target) { 30 | let i = 0, j = nums.length; 31 | while(i <= j) { 32 | let mid = parseInt(i + (j - i) / 2); 33 | if(nums[mid] === target) { 34 | return mid; 35 | } 36 | else if(nums[mid] < target) { 37 | i = mid + 1; 38 | } 39 | else { 40 | j = mid - 1; 41 | } 42 | } 43 | return i; 44 | }; 45 | 46 | // 插入排序 47 | var searchInsert = function(nums, target) { 48 | let val = target; 49 | let temp = nums; 50 | let j = temp.length - 1; 51 | while(j >= 0 && val < temp[j]) { 52 | temp[j+1] = temp[j]; 53 | j--; 54 | } 55 | temp[j+1] = val; 56 | if(val === temp[j]) return j; 57 | return j+1; 58 | }; -------------------------------------------------------------------------------- /LeetCode/38. 报数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下: 3 | 1. 1 4 | 2. 11 5 | 3. 21 6 | 4. 1211 7 | 5. 111221 8 | 1 被读作 "one 1" ("一个一") , 即 11。 9 | 11 被读作 "two 1s" ("两个一"), 即 21。 10 | 21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。 11 | 给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。 12 | 注意:整数顺序将表示为一个字符串。 13 | 14 | 示例 1: 15 | 输入: 1 16 | 输出: "1" 17 | 18 | 示例 2: 19 | 输入: 4 20 | 输出: "1211" 21 | */ 22 | /** 23 | * @param {number} n 24 | * @return {string} 25 | */ 26 | var countAndSay = function(n) { 27 | let arr = ["0", "1", "11"]; 28 | // 先打表 29 | function type() { 30 | let temp = "11"; 31 | for(let i=3; i<=30; i++) { 32 | // 同一个数字出现的次数 33 | let sum = 1; 34 | let str = ""; 35 | for(let j=0; j false 8 | canConstruct("aa", "ab") -> false 9 | canConstruct("aa", "aab") -> true 10 | */ 11 | 12 | 13 | // 分别统计两个字符串中各个字符出现的次数再比较 14 | var canConstruct = function(ransomNote, magazine) { 15 | let arr1 = []; 16 | for(let i=0; i { 10 | return b - a; 11 | }) 12 | if(arr.length < 3) { 13 | return arr[0]; 14 | } 15 | else { 16 | return arr[2]; 17 | } 18 | }; 19 | 20 | 21 | // 使用三个变量分别维护第一二三大的数。O(n) 22 | var thirdMax = function(nums) { 23 | let arr = [...new Set(nums)]; 24 | if(arr.length < 3) { 25 | return arr.length === 1 ? arr[0] : Math.max(arr[0], arr[1]); 26 | } 27 | let one = -Infinity, two = -Infinity, three = -Infinity; 28 | for(let i=0; i one) { 30 | [one, two, three] = [arr[i], one, two]; 31 | } 32 | else if(arr[i] > two) { 33 | [two, three] = [arr[i], two]; 34 | } 35 | else if(arr[i] > three) { 36 | three= arr[i]; 37 | } 38 | } 39 | return three; 40 | }; 41 | console.log(thirdMax([2,2,3,1])); 42 | console.log(thirdMax([2,3,1])); 43 | console.log(thirdMax([1,1,1])); 44 | -------------------------------------------------------------------------------- /LeetCode/415. 字符串相加.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。 3 | 注意: 4 | num1 和num2 的长度都小于 5100. 5 | num1 和num2 都只包含数字 0-9. 6 | num1 和num2 都不包含任何前导零。 7 | 你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式。 8 | */ 9 | 10 | var addStrings = function(num1, num2) { 11 | let len = num1.length > num2.length ? num1.length : num2.length; 12 | num1 = num1.padStart(len, 0); 13 | num2 = num2.padStart(len, 0); 14 | let carry = 0; 15 | let str = ''; 16 | for(let i=len-1; i>=0; i--) { 17 | let tem = parseInt(num1[i]) + parseInt(num2[i]) + carry; 18 | str += tem % 10; 19 | carry = parseInt(tem / 10); 20 | } 21 | if(carry) { 22 | str += carry; 23 | } 24 | return str.split('').reverse().join(''); 25 | }; 26 | console.log(addStrings('98', '9')); -------------------------------------------------------------------------------- /LeetCode/429. N叉树的层序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。 3 | */ 4 | 5 | /** 6 | * // Definition for a Node. 7 | * function Node(val,children) { 8 | * this.val = val; 9 | * this.children = children; 10 | * }; 11 | */ 12 | /** 13 | * @param {Node} root 14 | * @return {number[][]} 15 | */ 16 | var levelOrder = function(root) { 17 | let res = []; 18 | if (!root) { 19 | return []; 20 | } 21 | (function fn(root) { 22 | let queue = []; 23 | queue.push(root); 24 | while(queue.length) { 25 | let sum = queue.length; 26 | let arr = []; 27 | while(sum--) { 28 | let node = queue.shift(); 29 | arr.push(node.val); 30 | if (node.children) { 31 | node.children.forEach(item => { 32 | queue.push(item); 33 | }) 34 | } 35 | } 36 | res.push(arr); 37 | } 38 | })(root) 39 | return res; 40 | }; 41 | 42 | // 递归 43 | var levelOrder = function(root) { 44 | let res = []; 45 | (function fn(root, level) { 46 | if (!root) { 47 | return; 48 | } 49 | if (!res[level]) { 50 | res[level] = []; 51 | } 52 | res[level].push(root.val); 53 | root.children.forEach(item => { 54 | fn(item, level + 1); 55 | }) 56 | })(root, 0) 57 | return res; 58 | } -------------------------------------------------------------------------------- /LeetCode/430. 扁平化多级双向链表.js: -------------------------------------------------------------------------------- 1 | /* 2 | 您将获得一个双向链表,除了下一个和前一个指针之外,它还有一个子指针,可能指向单独的双向链表。这些子列表可能有一个或多个自己的子项,依此类推,生成多级数据结构,如下面的示例所示。 3 | 扁平化列表,使所有结点出现在单级双链表中。您将获得列表第一级的头部。 4 | 5 | 示例: 6 | 输入: 7 | 1---2---3---4---5---6--NULL 8 | | 9 | 7---8---9---10--NULL 10 | | 11 | 11--12--NULL 12 | 输出: 13 | 1-2-3-7-8-11-12-9-10-4-5-6-NULL 14 | */ 15 | /** 16 | * // Definition for a Node. 17 | * function Node(val,prev,next,child) { 18 | * this.val = val; 19 | * this.prev = prev; 20 | * this.next = next; 21 | * this.child = child; 22 | * }; 23 | */ 24 | /** 25 | * @param {Node} head 26 | * @return {Node} 27 | */ 28 | 29 | // 遇到有child的先把原链表的next保存到一个数组,等所有的child都添加到链表上后再从数组中取出之前保存的链表剩余部分继续拼接 30 | var flatten = function(head) { 31 | let arr = []; 32 | let cur = head; 33 | while(cur) { 34 | if(cur.child) { 35 | // 先保存链表剩下的部分,等child都拼接完后再开始拼接 36 | arr.unshift(cur.next); 37 | // 将child拼接到当前链表后面 38 | cur.next = cur.child; 39 | cur.child.prev = cur; 40 | cur.child = null; 41 | } 42 | // 所有的child都拼接完成了并且有剩余的链表还没有拼接 43 | else if(cur.next === null && arr.length !== 0) { 44 | cur.next = arr.shift(); 45 | if(cur.next) { 46 | cur.next.prev = cur; 47 | } 48 | } 49 | cur = cur.next; 50 | } 51 | return head; 52 | }; -------------------------------------------------------------------------------- /LeetCode/437. 路径总和 III.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,它的每个结点都存放着一个整数值。 3 | 找出路径和等于给定数值的路径总数。 4 | 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 5 | 二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。 6 | 7 | 示例: 8 | root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 9 | 10 | 10 11 | / \ 12 | 5 -3 13 | / \ \ 14 | 3 2 11 15 | / \ \ 16 | 3 -2 1 17 | 18 | 返回 3。和等于 8 的路径有: 19 | 1. 5 -> 3 20 | 2. 5 -> 2 -> 1 21 | 3. -3 -> 11 22 | */ 23 | /** 24 | * Definition for a binary tree node. 25 | * function TreeNode(val) { 26 | * this.val = val; 27 | * this.left = this.right = null; 28 | * } 29 | */ 30 | /** 31 | * @param {TreeNode} root 32 | * @param {number} sum 33 | * @return {number} 34 | */ 35 | 36 | // 一遍递归遍历每一个结点,再一遍递归以当前的结点作为根节点向下寻找路径数 37 | var pathSum = function(root, sum) { 38 | let res = 0; 39 | // 递归遍历每个结点 40 | function recurNode(root, s) { 41 | if(root === null) return root; 42 | getPath(root, s); 43 | recurNode(root.left, s); 44 | recurNode(root.right, s); 45 | } 46 | // 以当前结点作为根节点递归寻找路径数 47 | function getPath(root, s) { 48 | if(root === null) return 0; 49 | if(root.val === s) res++; 50 | getPath(root.left, s - root.val); 51 | getPath(root.right, s - root.val); 52 | } 53 | recurNode(root, sum); 54 | return res; 55 | }; -------------------------------------------------------------------------------- /LeetCode/441. 排列硬币.js: -------------------------------------------------------------------------------- 1 | /* 2 | 你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。 3 | 给定一个数字 n,找出可形成完整阶梯行的总行数。 4 | n 是一个非负整数,并且在32位有符号整型的范围内。 5 | */ 6 | 7 | 8 | // 先一层for循环求出n层需要多少个硬币并存储在一个数组中 9 | var arrangeCoins = function(n) { 10 | let arr = [0]; 11 | for(let i=1; i<100000; i++) { 12 | arr[i] = arr[i-1] + i; 13 | } 14 | for(let i=0; i<100000; i++) { 15 | if(arr[i] <= n && arr[i+1] > n) { 16 | return i; 17 | } 18 | } 19 | }; 20 | 21 | // 暴力破解 22 | var arrangeCoins = function(n) { 23 | let sum = 0; 24 | let index = 1; 25 | while(sum < n) { 26 | sum += index; 27 | if(sum > n) { 28 | return index - 1; 29 | } 30 | index++; 31 | } 32 | return index - 1; 33 | }; 34 | console.log(arrangeCoins(1)); 35 | console.log(arrangeCoins(2)); 36 | console.log(arrangeCoins(5)); 37 | console.log(arrangeCoins(8)); 38 | console.log(arrangeCoins(1804289383)); -------------------------------------------------------------------------------- /LeetCode/448. 找到所有数组中消失的数字.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。 3 | 找到所有在 [1, n] 范围之间没有出现在数组中的数字。 4 | 您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。 5 | 6 | 示例: 7 | 输入: 8 | [4,3,2,7,8,2,3,1] 9 | 输出: 10 | [5,6] 11 | */ 12 | 13 | // 另起一个数组通过下标标记是否出现过 14 | var findDisappearedNumbers = function(nums) { 15 | let len = nums.length; 16 | let arr = []; 17 | let res = []; 18 | for(let i=0; i 0) { 40 | res.push(i + 1); 41 | } 42 | } 43 | return res; 44 | }; 45 | console.log(findDisappearedNumbers([4,3,2,7,8,2,3,1])); 46 | console.log(findDisappearedNumbers([1, 1])); 47 | console.log(findDisappearedNumbers([2, 2])); -------------------------------------------------------------------------------- /LeetCode/455. 分发饼干.js: -------------------------------------------------------------------------------- 1 | /* 2 | 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 3 | 4 | 注意: 5 | 你可以假设胃口值为正。 6 | 一个小朋友最多只能拥有一块饼干。 7 | 8 | 示例 1: 9 | 输入: [1,2,3], [1,1] 10 | 输出: 1 11 | */ 12 | 13 | // 两层循环 14 | var findContentChildren = function(g, s) { 15 | let arr1 = g.sort((a, b) => { 16 | return a - b; 17 | }) 18 | let arr2 = s.sort((a, b) => { 19 | return a - b; 20 | }) 21 | let sum = 0; 22 | let tem = 0; 23 | for(let i=0; i { 39 | return a - b; 40 | }) 41 | let arr2 = s.sort((a, b) => { 42 | return a - b; 43 | }) 44 | let len1 = arr1.length; 45 | let len2 = arr2.length; 46 | let index1 = 0; 47 | let index2 = 0; 48 | let sum = 0; 49 | while(index1 < len1 && index2 < len2) { 50 | if(arr1[index1] <= arr2[index2]) { 51 | sum++; 52 | index1++; 53 | index2++; 54 | continue; 55 | } 56 | else { 57 | index2++; 58 | } 59 | } 60 | return sum; 61 | }; 62 | console.log(findContentChildren([1,2,3], [1,1])); 63 | console.log(findContentChildren([1,2], [1,2,3])); -------------------------------------------------------------------------------- /LeetCode/459. 重复的子字符串.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。 3 | 4 | 示例 1: 5 | 输入: "abab" 6 | 输出: True 7 | 解释: 可由子字符串 "ab" 重复两次构成。 8 | 9 | 示例 2: 10 | 输入: "aba" 11 | 输出: False 12 | 13 | 示例 3: 14 | 输入: "abcabcabcabc" 15 | 输出: True 16 | 解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。) 17 | */ 18 | /** 19 | * @param {string} s 20 | * @return {boolean} 21 | */ 22 | var repeatedSubstringPattern = function(s) { 23 | let len = s.length; 24 | let half = parseInt(len / 2); 25 | // i 表示子串的长度,最多为half 26 | for(let i=0; i<=half; i++) { 27 | // 如果有余数则该子串一定不能构成字符串s 28 | if(len % i !== 0) continue; 29 | let j; 30 | // 以i为一循环,两个位置上的数得相等,一有不相等的则马上退出循环 31 | for(j=i; j len-1) { 26 | // 需要浅拷贝一次,否则后续的交换操作会影响到res中已排列的序列 27 | res.push(arr.slice(0)); 28 | return; 29 | } 30 | for(let i=start; i>= 1; 23 | } 24 | return ans; 25 | }; 26 | console.log(hammingDistance(1, 4)); -------------------------------------------------------------------------------- /LeetCode/47. 全排列 II.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number[][]} 4 | */ 5 | // 和上一题一样,最后用set去重 6 | var permuteUnique = function(nums) { 7 | let res = []; 8 | function fn(arr, start) { 9 | if(start >= arr.length-1) { 10 | res.push(arr.slice(0)); 11 | return; 12 | } 13 | for(let i=start, len=arr.length; i { 21 | res[index] = val.join(','); 22 | }) 23 | return [...new Set(res)].map(val => { 24 | return val.split(','); 25 | }) 26 | }; 27 | 28 | 29 | var permuteUnique = function(nums) { 30 | let res = []; 31 | function fn(arr, start) { 32 | if(start >= arr.length-1) { 33 | res.push(arr.slice(0)); 34 | return; 35 | } 36 | for(let i=start, len=arr.length; i max ? temp : max; 28 | } 29 | return max; 30 | }; -------------------------------------------------------------------------------- /LeetCode/500. 键盘行.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词。键盘如下图所示。 3 | 4 | 示例: 5 | 输入: ["Hello", "Alaska", "Dad", "Peace"] 6 | 输出: ["Alaska", "Dad"] 7 | 8 | 注意: 9 | 你可以重复使用键盘上同一字符。 10 | 你可以假设输入的字符串将只包含字母。 11 | */ 12 | var findWords = function(words) { 13 | function judge(code) { 14 | let str1 = "qwertyuiop"; 15 | let str2 = "asdfghjkl"; 16 | let str3 = "zxcvbnm"; 17 | if(str1.includes(code)) { 18 | return str1; 19 | } 20 | else if(str2.includes(code)) { 21 | return str2; 22 | } 23 | else if(str3.includes(code)) { 24 | return str3; 25 | } 26 | } 27 | let res = []; 28 | for(let i=0, len=words.length; i maxCount) { 49 | res = []; 50 | res.push(root.val); 51 | maxCount = curCount; 52 | } 53 | pre = root.val; 54 | 55 | fn(root.right); 56 | } 57 | fn(root); 58 | return res; 59 | }; -------------------------------------------------------------------------------- /LeetCode/504. 七进制数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个整数,将其转化为7进制,并以字符串形式输出。 3 | 4 | 示例 1: 5 | 输入: 100 6 | 输出: "202" 7 | */ 8 | 9 | var convertToBase7 = function(num) { 10 | if(num === 0) return '0'; 11 | let arr = []; 12 | let mark = num < 0 ? '-' : ''; 13 | num = Math.abs(num); 14 | while(num >= 1) { 15 | arr.unshift(parseInt(num % 7)); 16 | num = parseInt(num / 7); 17 | } 18 | return mark + arr.join('') ; 19 | }; 20 | console.log(convertToBase7(100)); 21 | console.log(convertToBase7(-7)); -------------------------------------------------------------------------------- /LeetCode/508. 出现次数最多的子树元素和.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给出二叉树的根,找出出现次数最多的子树元素和。一个结点的子树元素和定义为以该结点为根的二叉树上所有结点的元素之和(包括结点本身)。然后求出出现次数最多的子树元素和。如果有多个元素出现的次数相同,返回所有出现次数最多的元素(不限顺序)。 3 | 4 | 示例 1 5 | 输入: 6 | 7 | 5 8 | / \ 9 | 2 -3 10 | 返回 [2, -3, 4],所有的值均只出现一次,以任意顺序返回所有值。 11 | 12 | 示例 2 13 | 输入: 14 | 15 | 5 16 | / \ 17 | 2 -5 18 | 返回 [2],只有 2 出现两次,-5 只出现 1 次。 19 | */ 20 | /** 21 | * Definition for a binary tree node. 22 | * function TreeNode(val) { 23 | * this.val = val; 24 | * this.left = this.right = null; 25 | * } 26 | */ 27 | /** 28 | * @param {TreeNode} root 29 | * @return {number[]} 30 | */ 31 | var findFrequentTreeSum = function(root) { 32 | let obj = {} 33 | function fn(root) { 34 | if (!root) return 0; 35 | let l = fn(root.left); // 当前节点的左子树的元素和 36 | let r = fn(root.right); // 当前节点的右子树的元素和 37 | 38 | let sum = l + r + root.val; // 当前节点的元素和 39 | obj[sum] = obj[sum] ? obj[sum] + 1 : 1; 40 | return sum; 41 | } 42 | fn(root); 43 | let max = 0; // 记录出现的最大次数 44 | let res = []; 45 | for (key in obj) { 46 | if (obj[key] === max) { 47 | res.push(key); 48 | } else if (obj[key] > max) { 49 | res = []; 50 | res.push(key); 51 | max = obj[key]; 52 | } 53 | } 54 | return res; 55 | }; -------------------------------------------------------------------------------- /LeetCode/509. 斐波那契数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: 3 | F(0) = 0, F(1) = 1 4 | F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 5 | 给定 N,计算 F(N)。 6 | */ 7 | 8 | // 打表 9 | var fib = function(N) { 10 | let arr = [0, 1]; 11 | for(let i=2; i<=50; i++) { 12 | arr[i] = arr[i-1] + arr[i-2]; 13 | } 14 | return arr[N]; 15 | }; 16 | 17 | // 递归 18 | var fib = function(N) { 19 | function fn(n) { 20 | if(n === 0) { 21 | return 0; 22 | } 23 | else if(n === 1) { 24 | return 1; 25 | } 26 | else { 27 | return fn(n-1) + fn(n-2); 28 | } 29 | } 30 | return fn(N); 31 | }; 32 | 33 | // 记忆函数 34 | var fib = function(N) { 35 | let res = [0, 1]; 36 | if(typeof res[N] === 'number') { 37 | return res[N]; 38 | } 39 | function fn(n) { 40 | if(!typeof res[n] === 'number') { 41 | res[n] = fn(n-1) + fn(n-2); 42 | } 43 | return res[n]; 44 | } 45 | return (function() { 46 | res[N] = fn(N); 47 | return res[N]; 48 | })() 49 | } 50 | console.log(fib(10)); 51 | 52 | 53 | -------------------------------------------------------------------------------- /LeetCode/513. 找树左下角的值.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,在树的最后一行找到最左边的值。 3 | 4 | 示例 1: 5 | 输入: 6 | 7 | 1 8 | / \ 9 | 2 3 10 | / / \ 11 | 4 5 6 12 | / 13 | 7 14 | 15 | 输出: 7 16 | */ 17 | 18 | /** 19 | * Definition for a binary tree node. 20 | * function TreeNode(val) { 21 | * this.val = val; 22 | * this.left = this.right = null; 23 | * } 24 | */ 25 | /** 26 | * @param {TreeNode} root 27 | * @return {number} 28 | */ 29 | 30 | // 比较左右子树哪个更深,每次都在深度更大的子树里面找,深度相等的话则在左子树里找。判断收否是叶子节点并返回即可。 31 | var findBottomLeftValue = function(root) { 32 | function computedDeep(root) { 33 | if (root === null) { 34 | return 0; 35 | } 36 | return Math.max(computedDeep(root.left), computedDeep(root.right)) + 1; 37 | } 38 | 39 | return (function fn(root) { 40 | if (root.left === null && root.right === null) { 41 | return root.val; 42 | } 43 | if (computedDeep(root.left) >= computedDeep(root.right)) { 44 | return fn(root.left); 45 | } else { 46 | return fn(root.right); 47 | } 48 | })(root) 49 | }; 50 | 51 | // 中序遍历(从左往右)。维护一个最大深度并以此更新结果值。 52 | var findBottomLeftValue = function(root) { 53 | let res; 54 | let maxDeep = -1; 55 | (function fn(root, deep) { 56 | if (root === null) { 57 | return root; 58 | } 59 | fn(root.left, deep + 1); 60 | if (deep > maxDeep) { 61 | maxDeep = deep; 62 | res = root.val; 63 | } 64 | fn(root.right, deep + 1); 65 | })(root, 0); 66 | return res; 67 | } -------------------------------------------------------------------------------- /LeetCode/515. 在每个树行中找最大值.js: -------------------------------------------------------------------------------- 1 | /* 2 | 您需要在二叉树的每一行中找到最大的值。 3 | 4 | 示例: 5 | 输入: 6 | 1 7 | / \ 8 | 3 2 9 | / \ \ 10 | 5 3 9 11 | 输出: [1, 3, 9] 12 | */ 13 | 14 | /** 15 | * Definition for a binary tree node. 16 | * function TreeNode(val) { 17 | * this.val = val; 18 | * this.left = this.right = null; 19 | * } 20 | */ 21 | /** 22 | * @param {TreeNode} root 23 | * @return {number[]} 24 | */ 25 | 26 | // 层序遍历,记录每层的最大值 27 | var largestValues = function(root) { 28 | if (root === null) { 29 | return []; 30 | } 31 | let res = []; 32 | let level = []; 33 | level.push(root); 34 | let sum = level.length; 35 | while(level.length) { 36 | let max = -Infinity; 37 | level.forEach(item => { 38 | if (item.val > max) { 39 | max = item.val; 40 | } 41 | }) 42 | res.push(max); 43 | while(sum--) { 44 | let node = level.shift(); 45 | if (node.left) { 46 | level.push(node.left); 47 | } 48 | if (node.right) { 49 | level.push(node.right); 50 | } 51 | } 52 | sum = level.length; 53 | } 54 | return res; 55 | }; -------------------------------------------------------------------------------- /LeetCode/53. 最大子序和.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 3 | 4 | 示例: 5 | 输入: [-2,1,-3,4,-1,2,1,-5,4], 6 | 输出: 6 7 | 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 8 | 9 | 进阶: 10 | 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 11 | */ 12 | /** 13 | * @param {number[]} nums 14 | * @return {number} 15 | */ 16 | 17 | // 动态规划 18 | var maxSubArray = function(nums) { 19 | let res = 0; 20 | let sum = 0; 21 | for(let i=0; i res ? sum : res; 24 | } 25 | return res; 26 | }; 27 | 28 | 29 | // 暴力破解 30 | var maxSubArray = function(nums) { 31 | let res = nums[0]; 32 | for(let i=0, len=nums.length; i res ? sum : res; 37 | } 38 | } 39 | return res; 40 | } -------------------------------------------------------------------------------- /LeetCode/530. 二叉搜索树的最小绝对差.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个所有节点为非负值的二叉搜索树,求树中任意两节点的差的绝对值的最小值。 3 | 4 | 示例 : 5 | 输入: 6 | 7 | 1 8 | \ 9 | 3 10 | / 11 | 2 12 | 13 | 输出:1 14 | 15 | 解释: 16 | 最小绝对差为1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。 17 | 注意: 树中至少有2个节点。 18 | */ 19 | 20 | /** 21 | * Definition for a binary tree node. 22 | * function TreeNode(val) { 23 | * this.val = val; 24 | * this.left = this.right = null; 25 | * } 26 | */ 27 | /** 28 | * @param {TreeNode} root 29 | * @return {number} 30 | */ 31 | 32 | // 中序遍历就是升序,比较相邻两个节点的值(使用一个变量来存储上一个节点值) 33 | var getMinimumDifference = function(root) { 34 | let minGap = Infinity; 35 | let pre = Infinity; 36 | 37 | (function fn(root) { 38 | if (root === null) { 39 | return; 40 | } 41 | fn(root.left); 42 | minGap = Math.min(Math.abs(root.val - pre), minGap); 43 | pre = root.val; 44 | fn(root.right); 45 | })(root) 46 | return minGap; 47 | }; -------------------------------------------------------------------------------- /LeetCode/538. 把二叉搜索树转换为累加树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。 3 | 4 | 例如: 5 | 输入: 二叉搜索树: 6 | 5 7 | / \ 8 | 2 13 9 | 10 | 输出: 转换为累加树: 11 | 18 12 | / \ 13 | 20 13 14 | */ 15 | /** 16 | * Definition for a binary tree node. 17 | * function TreeNode(val) { 18 | * this.val = val; 19 | * this.left = this.right = null; 20 | * } 21 | */ 22 | /** 23 | * @param {TreeNode} root 24 | * @return {TreeNode} 25 | */ 26 | 27 | // 从右节点 -> 根节点 -> 左节点(从大到小),使用一个变量记录累加和 28 | var convertBST = function(root) { 29 | let sum = 0; 30 | (function fn(root) { 31 | if (root === null) { 32 | return null; 33 | } 34 | fn(root.right); 35 | root.val += sum; 36 | sum = root.val; 37 | fn(root.left); 38 | })(root) 39 | return root; 40 | }; -------------------------------------------------------------------------------- /LeetCode/543. 二叉树的直径.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。 3 | 示例 : 4 | 给定二叉树 5 | 6 | 1 7 | / \ 8 | 2 3 9 | / \ 10 | 4 5 11 | 返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。 12 | 13 | 注意:两结点之间的路径长度是以它们之间边的数目表示。 14 | */ 15 | 16 | /** 17 | * Definition for a binary tree node. 18 | * function TreeNode(val) { 19 | * this.val = val; 20 | * this.left = this.right = null; 21 | * } 22 | */ 23 | /** 24 | * @param {TreeNode} root 25 | * @return {number} 26 | */ 27 | 28 | // 左子树的深度+右子树的深度+根节点 = 一条路径的节点个数,边数等于路径上节点数-1 29 | var diameterOfBinaryTree = function(root) { 30 | let res = 1; 31 | (function computedDeep(root) { 32 | if (root === null) { 33 | return 0; 34 | } 35 | let l = computedDeep(root.left); 36 | let r = computedDeep(root.right); 37 | res = Math.max(res, l + r + 1); 38 | return Math.max(l, r) + 1; 39 | })(root) 40 | return res - 1; 41 | }; -------------------------------------------------------------------------------- /LeetCode/557. 反转字符串中的单词 III.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 3 | 4 | 示例 1: 5 | 输入: "Let's take LeetCode contest" 6 | 输出: "s'teL ekat edoCteeL tsetnoc" 7 | */ 8 | 9 | // 使用内置的 api 10 | var reverseWords = function(s) { 11 | let arr = s.split(' '); 12 | let ans = ''; 13 | for(let i=0, len=arr.length; i= len) { 32 | break; 33 | } 34 | } 35 | ans += tem + ' '; 36 | } 37 | return ans.substr(0, ans.length-1); 38 | }; 39 | console.log(reverseWords("Let's take LeetCode contest")); -------------------------------------------------------------------------------- /LeetCode/559. N叉树的最大深度.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个 N 叉树,找到其最大深度。 3 | 最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。 4 | 5 | 说明: 6 | 树的深度不会超过 1000。 7 | 树的节点总不会超过 5000。 8 | */ 9 | /** 10 | * // Definition for a Node. 11 | * function Node(val,children) { 12 | * this.val = val; 13 | * this.children = children; 14 | * }; 15 | */ 16 | /** 17 | * @param {Node} root 18 | * @return {number} 19 | */ 20 | var maxDepth = function(root) { 21 | function fn(root, deep) { 22 | if(root === null) return 0; 23 | max = Math.max(max, deep); 24 | root.children.forEach(val => { 25 | fn(val, deep + 1); 26 | }) 27 | } 28 | 29 | if(root === null) return 0; 30 | let max = 0; 31 | fn(root, 1); 32 | return max; 33 | }; -------------------------------------------------------------------------------- /LeetCode/56. 合并区间.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给出一个区间的集合,请合并所有重叠的区间。 3 | 4 | 示例 1: 5 | 输入: [[1,3],[2,6],[8,10],[15,18]] 6 | 输出: [[1,6],[8,10],[15,18]] 7 | 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. 8 | 9 | 示例 2: 10 | 输入: [[1,4],[4,5]] 11 | 输出: [[1,5]] 12 | */ 13 | 14 | 15 | // 每个数组元素为 item,先根据 item[0] 升序排序,循环数组判断 item[1] 和它的下一个数组元素 next[0] 的大小关系 16 | // 大于等于就合并,合并后删除 next 以便合并后的区间和下一个区间继续比较(并且删除后需要 i-- 避免循环向前推进) 17 | var merge = function(intervals) { 18 | const res = []; 19 | intervals.sort((a, b) => { 20 | return a[0] - b[0]; 21 | }) 22 | for(let i=0; i= next[0]) { 26 | item[1] = Math.max(next[1], item[1]); 27 | intervals.splice(i+1, 1); 28 | i--; 29 | continue; 30 | } 31 | res.push(item); 32 | } 33 | return res; 34 | }; -------------------------------------------------------------------------------- /LeetCode/561. 数组拆分 I.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从1 到 n 的 min(ai, bi) 总和最大。 3 | 4 | 示例 1: 5 | 输入: [1,4,3,2] 6 | 输出: 4 7 | 解释: n 等于 2, 最大总和为 4 = min(1, 2) + min(3, 4). 8 | 9 | 提示: 10 | n 是正整数,范围在 [1, 10000]. 11 | 数组中的元素范围在 [-10000, 10000]. 12 | */ 13 | 14 | var arrayPairSum = function(nums) { 15 | let sum = 0; 16 | nums.sort((a, b) => { 17 | return a -b 18 | }); 19 | for(let i=0; i count ? max : count; 38 | } 39 | return max; 40 | }; 41 | 42 | console.log(arrayNesting([5,4,0,3,1,6,2])); -------------------------------------------------------------------------------- /LeetCode/589. N叉树的前序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个 N 叉树,返回其节点值的前序遍历。 3 | */ 4 | /** 5 | * // Definition for a Node. 6 | * function Node(val, children) { 7 | * this.val = val; 8 | * this.children = children; 9 | * }; 10 | */ 11 | /** 12 | * @param {Node} root 13 | * @return {number[]} 14 | */ 15 | 16 | // 递归 17 | var preorder = function(root) { 18 | let res = []; 19 | (function fn(root) { 20 | if (!root) { 21 | return; 22 | } 23 | res.push(root.val); 24 | root.children.forEach(item => { 25 | fn(item); 26 | }) 27 | })(root) 28 | return res; 29 | }; 30 | 31 | 32 | // 迭代 33 | var preorder = function(root) { 34 | if (!root) { 35 | return []; 36 | } 37 | const res = []; 38 | const queue = [root]; 39 | while(queue.length) { 40 | let node = queue.shift(); 41 | res.push(node.val); 42 | for(let i=node.children.length-1; i>=0; i--) { 43 | queue.unshift(node.children[i]); 44 | } 45 | } 46 | return res; 47 | } -------------------------------------------------------------------------------- /LeetCode/590. N叉树的后序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个 N 叉树,返回其节点值的后序遍历。 3 | */ 4 | 5 | /** 6 | * // Definition for a Node. 7 | * function Node(val,children) { 8 | * this.val = val; 9 | * this.children = children; 10 | * }; 11 | */ 12 | /** 13 | * @param {Node} root 14 | * @return {number[]} 15 | */ 16 | 17 | // 递归 18 | var postorder = function(root) { 19 | let res = []; 20 | (function fn(root) { 21 | if (!root) { 22 | return; 23 | } 24 | root.children.forEach(item => { 25 | fn(item); 26 | }) 27 | res.push(root.val); 28 | })(root) 29 | 30 | return res; 31 | }; 32 | 33 | 34 | // 迭代 35 | var postorder = function(root) { 36 | if (!root) { 37 | return []; 38 | } 39 | let res = []; 40 | let queue = [root]; 41 | while(queue.length) { 42 | let node = queue.shift(); 43 | node.children.forEach(item => { 44 | queue.unshift(item); 45 | }) 46 | res.unshift(node.val); 47 | } 48 | return res; 49 | } -------------------------------------------------------------------------------- /LeetCode/606. 根据二叉树创建字符串.js: -------------------------------------------------------------------------------- 1 | /* 2 | 你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。空节点则用一对空括号 "()" 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。 3 | 4 | 示例 1: 5 | 输入: 二叉树: [1,2,3,4] 6 | 1 7 | / \ 8 | 2 3 9 | / 10 | 4 11 | 12 | 输出: "1(2(4))(3)" 13 | 解释: 原本将是“1(2(4)())(3())”, 14 | 在你省略所有不必要的空括号对之后, 15 | 它将是“1(2(4))(3)”。 16 | 17 | 示例 2: 18 | 输入: 二叉树: [1,2,3,null,4] 19 | 1 20 | / \ 21 | 2 3 22 | \ 23 | 4 24 | 25 | 输出: "1(2()(4))(3)" 26 | 解释: 和第一个示例相似, 27 | 除了我们不能省略第一个对括号来中断输入和输出之间的一对一映射关系。 28 | */ 29 | 30 | /** 31 | * Definition for a binary tree node. 32 | * function TreeNode(val) { 33 | * this.val = val; 34 | * this.left = this.right = null; 35 | * } 36 | */ 37 | /** 38 | * @param {TreeNode} t 39 | * @return {string} 40 | */ 41 | 42 | // 分四种情况进行递归:没有左右子树、只有右子树、只有左子树、左右子树都有 43 | var tree2str = function(t) { 44 | function fn(root) { 45 | if (!root) { 46 | return ''; 47 | } else if (!root.left && !root.right) { 48 | return `${root.val}`; 49 | } else if (!root.left) { 50 | return `${root.val}()(${fn(root.right)})`; 51 | } else if (!root.right) { 52 | return `${root.val}(${fn(root.left)})`; 53 | } 54 | 55 | return `${root.val}(${fn(root.left)})(${fn(root.right)})`; 56 | } 57 | return fn(t); 58 | }; 59 | -------------------------------------------------------------------------------- /LeetCode/617. 合并二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。 3 | 4 | 示例 1: 5 | 输入: 6 | Tree 1 Tree 2 7 | 1 2 8 | / \ / \ 9 | 3 2 1 3 10 | / \ \ 11 | 5 4 7 12 | 输出: 13 | 合并后的树: 14 | 3 15 | / \ 16 | 4 5 17 | / \ \ 18 | 5 4 7 19 | 注意: 合并必须从两个树的根节点开始。 20 | */ 21 | 22 | /** 23 | * Definition for a binary tree node. 24 | * function TreeNode(val) { 25 | * this.val = val; 26 | * this.left = this.right = null; 27 | * } 28 | */ 29 | /** 30 | * @param {TreeNode} t1 31 | * @param {TreeNode} t2 32 | * @return {TreeNode} 33 | */ 34 | 35 | // 递归。如果有一棵树为空,则给上层返回另一棵非空的树。若两棵树都非空,则节点值进行合并,左右子树再递归合并。 36 | var mergeTrees = function(t1, t2) { 37 | if (!t1) { 38 | return t2; 39 | } 40 | if (!t2) { 41 | return t1; 42 | } 43 | t1.val += t2.val; 44 | t1.left = mergeTrees(t1.left, t2.left); 45 | t1.right = mergeTrees(t1.right, t2.right); 46 | return t1; 47 | }; -------------------------------------------------------------------------------- /LeetCode/628. 三个数的最大乘积.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个整型数组,在数组中找出由三个数组成的最大乘积,并输出这个乘积。 3 | 4 | 示例 1: 5 | 输入: [1,2,3] 6 | 输出: 6 7 | 8 | 示例 2: 9 | 输入: [1,2,3,4] 10 | 输出: 24 11 | 12 | 注意: 13 | 给定的整型数组长度范围是[3,104],数组中所有的元素范围是[-1000, 1000]。 14 | 输入的数组中任意三个数的乘积不会超出32位有符号整数的范围。 15 | */ 16 | /** 17 | * @param {number[]} nums 18 | * @return {number} 19 | */ 20 | var maximumProduct = function(nums) { 21 | nums.sort((a, b) => b - a); 22 | let len = nums.length; 23 | return nums[0] * (Math.max(nums[1] * nums[2], nums[len-1] * nums[len-2])); 24 | }; -------------------------------------------------------------------------------- /LeetCode/637. 二叉树的层平均值.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个非空二叉树, 返回一个由每层节点平均值组成的数组. 3 | 示例 1: 4 | 5 | 输入: 6 | 3 7 | / \ 8 | 9 20 9 | / \ 10 | 15 7 11 | 输出: [3, 14.5, 11] 12 | 解释: 第0层的平均值是 3, 第1层是 14.5, 第2层是 11. 因此返回 [3, 14.5, 11]. 13 | 注意:节点值的范围在32位有符号整数范围内。 14 | */ 15 | 16 | /** 17 | * Definition for a binary tree node. 18 | * function TreeNode(val) { 19 | * this.val = val; 20 | * this.left = this.right = null; 21 | * } 22 | */ 23 | /** 24 | * @param {TreeNode} root 25 | * @return {number[]} 26 | */ 27 | 28 | // 只是层次遍历 29 | var averageOfLevels = function(root) { 30 | let queue = []; 31 | queue.push(root); 32 | let res = []; 33 | while(queue.length) { 34 | let sum = queue.length; 35 | let tempSum = sum; 36 | let temp = 0; 37 | while(sum--) { 38 | let top = queue.shift(); 39 | temp += top.val; 40 | if(top.left) queue.push(top.left); 41 | if(top.right) queue.push(top.right); 42 | } 43 | res.push(temp / tempSum); 44 | temp = 0; 45 | } 46 | return res; 47 | }; -------------------------------------------------------------------------------- /LeetCode/654. 最大二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下: 3 | 4 | 二叉树的根是数组中的最大元素。 5 | 左子树是通过数组中最大值左边部分构造出的最大二叉树。 6 | 右子树是通过数组中最大值右边部分构造出的最大二叉树。 7 | 通过给定的数组构建最大二叉树,并且输出这个树的根节点。 8 | 9 | 示例 : 10 | 输入:[3,2,1,6,0,5] 11 | 输出:返回下面这棵树的根节点: 12 | 13 | 6 14 | / \ 15 | 3 5 16 | \ / 17 | 2 0 18 | \ 19 | 1 20 | */ 21 | 22 | /** 23 | * Definition for a binary tree node. 24 | * function TreeNode(val) { 25 | * this.val = val; 26 | * this.left = this.right = null; 27 | * } 28 | */ 29 | /** 30 | * @param {number[]} nums 31 | * @return {TreeNode} 32 | */ 33 | 34 | // 类似于先(后)序遍历+中序遍历构建二叉树 35 | var constructMaximumBinaryTree = function(nums) { 36 | return (function fn(l, r) { 37 | if (l > r) { 38 | return null; 39 | } 40 | let node = new TreeNode(); 41 | let index = findMax(l ,r); 42 | node.val = nums[index]; 43 | node.left = fn(l, index - 1); 44 | node.right = fn(index + 1, r); 45 | return node; 46 | })(0, nums.length - 1); 47 | 48 | function findMax(start, end) { 49 | let max = -Infinity; 50 | let index = -1; 51 | for(let i=start; i<=end; i++) { 52 | if (nums[i] > max) { 53 | max = nums[i]; 54 | index = i; 55 | } 56 | } 57 | return index; 58 | } 59 | }; -------------------------------------------------------------------------------- /LeetCode/657. 机器人能否返回原点.js: -------------------------------------------------------------------------------- 1 | /* 2 | 在二维平面上,有一个机器人从原点 (0, 0) 开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0) 处结束。 3 | 移动顺序由字符串表示。字符 move[i] 表示其第 i 次移动。机器人的有效动作有 R(右),L(左),U(上)和 D(下)。如果机器人在完成所有动作后返回原点,则返回 true。否则,返回 false。 4 | 注意:机器人“面朝”的方向无关紧要。 “R” 将始终使机器人向右移动一次,“L” 将始终向左移动等。此外,假设每次移动机器人的移动幅度相同。 5 | */ 6 | 7 | var judgeCircle = function(moves) { 8 | let vertical = 0, horizontal = 0; 9 | for(let i=0, len=moves.length; i { 37 | hash[val] = hash[val] + 1 || 1; 38 | tail[val] = 0; 39 | }) 40 | for(let i=0; i 0) { 46 | hash[val]--; 47 | tail[val-1]--; 48 | tail[val]++; 49 | } else if (hash[val+1] > 0 && hash[val+2] > 0) { 50 | hash[val]--; 51 | hash[val+1]--; 52 | hash[val+2]--; 53 | tail[val+2]++; 54 | } else { 55 | return false; 56 | } 57 | } 58 | return true; 59 | }; 60 | -------------------------------------------------------------------------------- /LeetCode/66. 加一.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 3 | 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。 4 | 你可以假设除了整数 0 之外,这个整数不会以零开头。 5 | 6 | 示例 1: 7 | 输入: [1,2,3] 8 | 输出: [1,2,4] 9 | */ 10 | 11 | var plusOne = function(digits) { 12 | let carry = 1; 13 | for(let i=digits.length-1; i>=0; i--) { 14 | let tem = carry + digits[i]; 15 | carry = parseInt(tem / 10); 16 | digits[i] = tem % 10; 17 | if(carry === 0) { 18 | return digits; 19 | } 20 | } 21 | if(carry) { 22 | return [1].concat(digits); 23 | } 24 | }; 25 | 26 | 27 | var plusOne = function(digits) { 28 | let i = digits.length - 1; 29 | while(i >= 0) { 30 | if(digits[i] == 9){ 31 | digits[i--] = 0; 32 | } 33 | else { 34 | digits[i] += 1; 35 | break; 36 | } 37 | } 38 | if(digits[0] == 0) { 39 | digits.splice(0,0,1); 40 | } 41 | return digits; 42 | }; 43 | console.log(plusOne([1, 2, 3])); 44 | console.log(plusOne([9])); -------------------------------------------------------------------------------- /LeetCode/662. 二叉树最大宽度.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。 3 | 每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。 4 | 5 | 示例 1: 6 | 输入: 7 | 8 | 1 9 | / 10 | 3 11 | / \ 12 | 5 3 13 | 14 | 输出: 2 15 | 解释: 最大值出现在树的第 3 层,宽度为 2 (5,3)。 16 | 17 | 示例 2: 18 | 输入: 19 | 20 | 1 21 | / \ 22 | 3 2 23 | / 24 | 5 25 | 26 | 输出: 2 27 | 解释: 最大值出现在树的第 2 层,宽度为 2 (3,2)。 28 | */ 29 | 30 | /** 31 | * Definition for a binary tree node. 32 | * function TreeNode(val) { 33 | * this.val = val; 34 | * this.left = this.right = null; 35 | * } 36 | */ 37 | /** 38 | * @param {TreeNode} root 39 | * @return {number} 40 | */ 41 | 42 | // 给每个节点编号,从1开始,只将每层最左边的节点编号加入到数组中,则arr[i-1]是第i层最左边节点的编号 43 | // 将当前的节点编号减去arr[i-1]就是当前的宽度,和最大宽度比较并不断更新即可 44 | var widthOfBinaryTree = function(root) { 45 | let arr = []; 46 | let res = 1; 47 | (function fn(node, curDeep, pos) { 48 | if (!node) { 49 | return; 50 | } 51 | // 只将每层最左边的节点编号加入数组 52 | if (curDeep > arr.length) { 53 | arr.push(pos); 54 | } 55 | let temp = pos - arr[curDeep-1] + 1; 56 | res = temp > res ? temp : res; 57 | // 不能直接使用 Math.max(res, pos - arr[curDeep-1] + 1),否则会得到NaN 58 | fn(node.left, curDeep + 1, pos * 2); 59 | fn(node.right, curDeep + 1, pos * 2 + 1); 60 | })(root, 1, 1); 61 | return res; 62 | }; -------------------------------------------------------------------------------- /LeetCode/669. 修剪二叉搜索树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。 3 | 4 | 示例 1: 5 | 输入: 6 | 1 7 | / \ 8 | 0 2 9 | 10 | L = 1 11 | R = 2 12 | 13 | 输出: 14 | 1 15 | \ 16 | 2 17 | 18 | 示例 2: 19 | 输入: 20 | 3 21 | / \ 22 | 0 4 23 | \ 24 | 2 25 | / 26 | 1 27 | 28 | L = 1 29 | R = 3 30 | 31 | 输出: 32 | 3 33 | / 34 | 2 35 | / 36 | 1 37 | */ 38 | 39 | /** 40 | * Definition for a binary tree node. 41 | * function TreeNode(val) { 42 | * this.val = val; 43 | * this.left = this.right = null; 44 | * } 45 | */ 46 | /** 47 | * @param {TreeNode} root 48 | * @param {number} L 49 | * @param {number} R 50 | * @return {TreeNode} 51 | */ 52 | 53 | // 递归。若当前的节点值小于L,说明新节点在右子树,则返回右子树给上层上层。若大于R,则返回左子树给上层,否则返回原节点给上层。 54 | var trimBST = function(root, L, R) { 55 | return (function fn(root) { 56 | if (!root) { 57 | return null; 58 | } 59 | root.left = fn(root.left); 60 | root.right = fn(root.right); 61 | if (root.val < L) { 62 | return root.right; 63 | } else if (root.val > R) { 64 | return root.left; 65 | } else { 66 | return root; 67 | } 68 | })(root) 69 | }; -------------------------------------------------------------------------------- /LeetCode/671. 二叉树中第二小的节点.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值。  3 | 给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。 4 | 5 | 示例 1: 6 | 输入: 7 | 2 8 | / \ 9 | 2 5 10 | / \ 11 | 5 7 12 | 13 | 输出: 5 14 | 说明: 最小的值是 2 ,第二小的值是 5 。 15 | 16 | 示例 2: 17 | 输入: 18 | 2 19 | / \ 20 | 2 2 21 | 22 | 输出: -1 23 | 说明: 最小的值是 2, 但是不存在第二小的值。 24 | */ 25 | 26 | /** 27 | * Definition for a binary tree node. 28 | * function TreeNode(val) { 29 | * this.val = val; 30 | * this.left = this.right = null; 31 | * } 32 | */ 33 | /** 34 | * @param {TreeNode} root 35 | * @return {number} 36 | */ 37 | 38 | // 最小的节点是根节点,所以第二小的节点是第一个大于根节点的节点。因为子节点的值不小于根节点的值,所以递归查找左右子树 39 | var findSecondMinimumValue = function(root) { 40 | const min = root.val; 41 | return (function fn(root) { 42 | if (!root) { 43 | return -1; 44 | } 45 | if (root.val > min) { 46 | return root.val; 47 | } 48 | let l = fn(root.left); 49 | let r = fn(root.right); 50 | if (l === -1) { 51 | return r; 52 | } 53 | if (r === -1) { 54 | return l; 55 | } 56 | return Math.min(l, r); 57 | })(root) 58 | }; -------------------------------------------------------------------------------- /LeetCode/682. 棒球比赛.js: -------------------------------------------------------------------------------- 1 | /* 2 | 你现在是棒球比赛记录员。 3 | 给定一个字符串列表,每个字符串可以是以下四种类型之一: 4 | 1.整数(一轮的得分):直接表示您在本轮中获得的积分数。 5 | 2. "+"(一轮的得分):表示本轮获得的得分是前两轮有效 回合得分的总和。 6 | 3. "D"(一轮的得分):表示本轮获得的得分是前一轮有效 回合得分的两倍。 7 | 4. "C"(一个操作,这不是一个回合的分数):表示您获得的最后一个有效 回合的分数是无效的,应该被移除。 8 | 9 | 每一轮的操作都是永久性的,可能会对前一轮和后一轮产生影响。 10 | 你需要返回你在所有回合中得分的总和。 11 | 12 | 示例 1: 13 | 输入: ["5","2","C","D","+"] 14 | 输出: 30 15 | 解释: 16 | 第1轮:你可以得到5分。总和是:5。 17 | 第2轮:你可以得到2分。总和是:7。 18 | 操作1:第2轮的数据无效。总和是:5。 19 | 第3轮:你可以得到10分(第2轮的数据已被删除)。总数是:15。 20 | 第4轮:你可以得到5 + 10 = 15分。总数是:30。 21 | */ 22 | 23 | var calPoints = function(ops) { 24 | // 使用一个数组来存储每一轮的有效得分 25 | let res = []; 26 | for(let i=0; i { 42 | return total + val; 43 | }, 0) 44 | }; 45 | console.log(calPoints(["5","2","C","D","+"])); 46 | console.log(calPoints(["5","-2","4","C","D","9","+","+"])); -------------------------------------------------------------------------------- /LeetCode/684. 冗余连接.js: -------------------------------------------------------------------------------- 1 | /* 2 | 在本问题中, 树指的是一个连通且无环的无向图。 3 | 输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, ..., N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。 4 | 结果图是一个以边组成的二维数组。每一个边的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v的无向图的边。 5 | 返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v] 应满足相同的格式 u < v。 6 | 7 | 示例 1: 8 | 输入: [[1,2], [1,3], [2,3]] 9 | 输出: [2,3] 10 | 解释: 给定的无向图为: 11 | 1 12 | / \ 13 | 2 - 3 14 | 15 | 示例 2: 16 | 输入: [[1,2], [2,3], [3,4], [1,4], [1,5]] 17 | 输出: [1,4] 18 | 解释: 给定的无向图为: 19 | 5 - 1 - 2 20 | | | 21 | 4 - 3 22 | */ 23 | 24 | /** 25 | * @param {number[][]} edges 26 | * @return {number[]} 27 | */ 28 | 29 | // 并查集。去掉冗余边后树就不连通了,所以在连通的树中,可以通过其中一条边找到其他的边。所以可以给每个节点标记一个父节点,表示该节点最终可以到达的节点。 30 | // 如果有一条边,两个节点的父节点相等,也就是它们可以和同一个节点连通(形成环了),则该边是冗余边。 31 | var findRedundantConnection = function(edges) { 32 | function find(val) { 33 | if (father[val] === val) { 34 | return val; 35 | } 36 | return find(father[val]); 37 | } 38 | 39 | function init() { 40 | for(let i=1, len=edges.length; i<=len; i++) { 41 | father[i] = i; 42 | } 43 | } 44 | 45 | const father = []; 46 | init(); 47 | for(let i=0; i (lSum + rSum) ? ans : (lSum + rSum); 59 | return Math.max(lSum, rSum); 60 | })(root) 61 | 62 | return ans; 63 | }; -------------------------------------------------------------------------------- /LeetCode/69. x 的平方根.js: -------------------------------------------------------------------------------- 1 | /* 2 | 实现 int sqrt(int x) 函数。 3 | 计算并返回 x 的平方根,其中 x 是非负整数。 4 | 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 5 | */ 6 | 7 | var mySqrt = function(x) { 8 | return parseInt(Math.sqrt(x)); 9 | }; 10 | console.log(mySqrt(4)); 11 | console.log(mySqrt(8)); -------------------------------------------------------------------------------- /LeetCode/7. 整数反转.js: -------------------------------------------------------------------------------- 1 | /* 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 2 | 3 | 示例 1: 4 | 输入: 123 5 | 输出: 321 6 | 7 | 示例 2: 8 | 输入: -123 9 | 输出: -321 10 | 11 | 示例 3: 12 | 输入: 120 13 | 输出: 21 14 | 15 | 注意: 16 | 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。 */ 17 | 18 | 19 | 20 | // 先将 x 转换为数组,再使用 reverse 方法反转 21 | var reverse = function(x) { 22 | const MAX = Math.pow(2, 31) - 1; 23 | const MIN = -Math.pow(2, 31); 24 | let arr = x.toString().split(''); 25 | let mark = arr[0] === '-' ? -1 : 1; 26 | arr = arr.reverse(); 27 | let result = parseInt(arr.join('')) * mark; 28 | return result <= MAX && result >= MIN ? result : 0; 29 | }; -------------------------------------------------------------------------------- /LeetCode/700. 二叉搜索树中的搜索.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。 3 | 4 | 例如, 5 | 给定二叉搜索树: 6 | 7 | 4 8 | / \ 9 | 2 7 10 | / \ 11 | 1 3 12 | 13 | 和值: 2 14 | 你应该返回如下子树: 15 | 16 | 2 17 | / \ 18 | 1 3 19 | 在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。 20 | */ 21 | 22 | /** 23 | * Definition for a binary tree node. 24 | * function TreeNode(val) { 25 | * this.val = val; 26 | * this.left = this.right = null; 27 | * } 28 | */ 29 | /** 30 | * @param {TreeNode} root 31 | * @param {number} val 32 | * @return {TreeNode} 33 | */ 34 | 35 | // 常规递归。根据当前节点的值和val的大小关系,选择递归左/右子树或者直接返回当前的节点。 36 | var searchBST = function(root, val) { 37 | return (function fn(root) { 38 | if (!root) { 39 | return null; 40 | } 41 | if (root.val === val) { 42 | return root; 43 | } else if (root.val > val) { 44 | return fn(root.left); 45 | } else { 46 | return fn(root.right); 47 | } 48 | })(root) 49 | }; -------------------------------------------------------------------------------- /LeetCode/701. 二叉搜索树中的插入操作.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 保证原始二叉搜索树中不存在新值。 3 | 注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。 4 | 5 | 例如,  6 | 给定二叉搜索树: 7 | 8 | 4 9 | / \ 10 | 2 7 11 | / \ 12 | 1 3 13 | 14 | 和 插入的值: 5 15 | 你可以返回这个二叉搜索树: 16 | 4 17 | / \ 18 | 2 7 19 | / \ / 20 | 1 3 5 21 | 或者这个树也是有效的: 22 | 5 23 | / \ 24 | 2 7 25 | / \ 26 | 1 3 27 | \ 28 | 4 29 | */ 30 | 31 | /** 32 | * Definition for a binary tree node. 33 | * function TreeNode(val) { 34 | * this.val = val; 35 | * this.left = this.right = null; 36 | * } 37 | */ 38 | /** 39 | * @param {TreeNode} root 40 | * @param {number} val 41 | * @return {TreeNode} 42 | */ 43 | 44 | // 根据当前节点值和val的大小关系,更新左/右子树 45 | var insertIntoBST = function(root, val) { 46 | if(!root) { 47 | return new TreeNode(val); 48 | } 49 | if (root.val > val) { 50 | root.left = insertIntoBST(root.left, val); 51 | } else if (root.val < val) { 52 | root.right = insertIntoBST(root.right, val); 53 | } 54 | return root; 55 | }; -------------------------------------------------------------------------------- /LeetCode/704. 二分查找.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 3 | */ 4 | 5 | var search = function(nums, target) { 6 | let i = 0, j = nums.length; 7 | while(i < j) { 8 | let mid = parseInt((j - i) / 2) + i; 9 | if(nums[mid] < target) { 10 | i = mid + 1; 11 | } 12 | else if(nums[mid] > target) { 13 | j = mid; 14 | } 15 | else { 16 | return mid; 17 | } 18 | } 19 | return -1; 20 | }; 21 | console.log(search([-1,0,3,5,9,12], 2)); 22 | console.log(search([-1,0,3,5,9,12], 9)); -------------------------------------------------------------------------------- /LeetCode/709. 转换成小写字母.js: -------------------------------------------------------------------------------- 1 | var toLowerCase = function(str) { 2 | let res = ''; 3 | for(let i=0, len=str.length; i=0; i--) { 14 | if(bits[i] !== 1) { 15 | break; 16 | } 17 | sum++; 18 | } 19 | return sum % 2 === 0 ? true : false; 20 | }; 21 | console.log(isOneBitCharacter([1,1,1,0])); -------------------------------------------------------------------------------- /LeetCode/728. 自除数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 自除数 是指可以被它包含的每一位数除尽的数。 3 | 例如,128 是一个自除数,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。 4 | 还有,自除数不允许包含 0 。 5 | 给定上边界和下边界数字,输出一个列表,列表的元素是边界(含边界)内所有的自除数。 6 | 7 | 示例 1: 8 | 输入: 9 | 上边界left = 1, 下边界right = 22 10 | 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22] 11 | 12 | 注意: 13 | 每个输入参数的边界满足 1 <= left <= right <= 10000。 14 | */ 15 | 16 | var selfDividingNumbers = function(left, right) { 17 | let res = []; 18 | for(let i=left; i<=right; i++) { 19 | let str = i + ''; 20 | let mark = true; 21 | for(let j=0; j target ) { 11 | return letters[i]; 12 | } 13 | } 14 | return letters[0]; 15 | }; 16 | console.log(nextGreatestLetter(["c", "f", "j"], "a")); -------------------------------------------------------------------------------- /LeetCode/746. 使用最小花费爬楼梯.js: -------------------------------------------------------------------------------- 1 | /* 2 | 数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 cost[i](索引从0开始)。 3 | 每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。 4 | 您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。 5 | 6 | 示例 1: 7 | 输入: cost = [10, 15, 20] 8 | 输出: 15 9 | 解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15。 10 | 11 | 示例 2: 12 | 输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 13 | 输出: 6 14 | 解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6。 15 | 16 | 注意: 17 | cost 的长度将会在 [2, 1000]。 18 | 每一个 cost[i] 将会是一个Integer类型,范围为 [0, 999]。 19 | */ 20 | 21 | /** 22 | * @param {number[]} cost 23 | * @return {number} 24 | */ 25 | var minCostClimbingStairs = function(cost) { 26 | let last = 0; 27 | let lastLast = 0; 28 | for(let i=0; i= 0) { 28 | ans++; 29 | } 30 | } 31 | return ans; 32 | }; 33 | console.log(numJewelsInStones("aA", "aAABBBB")); -------------------------------------------------------------------------------- /LeetCode/78. 子集.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 3 | 说明:解集不能包含重复的子集。 4 | 5 | 示例: 6 | 输入: nums = [1,2,3] 7 | 输出: 8 | [ 9 | [3], 10 | [1], 11 | [2], 12 | [1,2,3], 13 | [1,3], 14 | [2,3], 15 | [1,2], 16 | [] 17 | ] 18 | */ 19 | 20 | // 遍历时遇到一个数就把所有子集加上该数组成新的子集,遍历完毕即是所有子集 21 | var subsets = function(nums) { 22 | let res = []; 23 | res.push([]); 24 | for(let i=0, len=nums.length; i1->2->3 9 | G = [0, 1, 3] 10 | 输出: 2 11 | 解释: 12 | 链表中,0 和 1 是相连接的,且 G 中不包含 2,所以 [0, 1] 是 G 的一个组件,同理 [3] 也是一个组件,故返回 2。 13 | 14 | 示例 2: 15 | 输入: 16 | head: 0->1->2->3->4 17 | G = [0, 3, 1, 4] 18 | 输出: 2 19 | 解释: 20 | 链表中,0 和 1 是相连接的,3 和 4 是相连接的,所以 [0, 1] 和 [3, 4] 是两个组件,故返回 2。 21 | */ 22 | /** 23 | * Definition for singly-linked list. 24 | * function ListNode(val) { 25 | * this.val = val; 26 | * this.next = null; 27 | * } 28 | */ 29 | /** 30 | * @param {ListNode} head 31 | * @param {number[]} G 32 | * @return {number} 33 | */ 34 | var numComponents = function(head, G) { 35 | let map = new Map(); 36 | for(let i=0; i1->2 6 | 输出: 1->2 7 | 8 | 示例 2: 9 | 输入: 1->1->2->3->3 10 | 输出: 1->2->3 11 | */ 12 | 13 | /** 14 | * Definition for singly-linked list. 15 | * function ListNode(val) { 16 | * this.val = val; 17 | * this.next = null; 18 | * } 19 | */ 20 | /** 21 | * @param {ListNode} head 22 | * @return {ListNode} 23 | */ 24 | 25 | // 常规解法 26 | var deleteDuplicates = function(head) { 27 | if(head === null) { 28 | return null; 29 | } 30 | let cur = head; 31 | while(cur.next) { 32 | if(cur.val === cur.next.val) { 33 | cur.next = cur.next.next; 34 | continue; 35 | } 36 | cur = cur.next; 37 | } 38 | return head; 39 | }; 40 | 41 | // 递归 42 | var deleteDuplicates = function(head) { 43 | if(head === null || head.next === null) { 44 | return head; 45 | } 46 | head.next = deleteDuplicates(head.next); 47 | if(head.val === head.next.val) { 48 | head = head.next; 49 | // 或者 50 | // head.next = head.next.next; 51 | } 52 | return head; 53 | }; 54 | 55 | // 使用一个数组记录每个节点值出现的次数,判断当前节点的下一个节点值对应的数组值是否大于1,是则删除 56 | var deleteDuplicates = function(head) { 57 | if(head === null) { 58 | return null; 59 | } 60 | let cur = head; 61 | let arr = []; 62 | arr[head.val] = 1; 63 | while(cur.next) { 64 | let temp = cur.next; 65 | arr[temp.val] = arr[temp.val] + 1 || 1; 66 | if(arr[temp.val] > 1) { 67 | cur.next = temp.next; 68 | continue; 69 | } 70 | cur = temp; 71 | } 72 | return head; 73 | }; -------------------------------------------------------------------------------- /LeetCode/844. 比较含退格的字符串.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。 3 | */ 4 | 5 | 6 | var backspaceCompare = function(S, T) { 7 | let len1 = S.length; 8 | let len2 = T.length; 9 | let str1 = ''; 10 | let str2 = ''; 11 | for(let i=0, j=0; i= 3,存在 0 < i < A.length - 1 使得A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1]。 3 | 给定一个确定为山脉的数组,返回任何满足 A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1] 的 i 的值。 4 | 5 | 示例 1: 6 | 输入:[0,1,0] 7 | 输出:1 8 | 9 | 示例 2: 10 | 输入:[0,2,1,0] 11 | 输出:1 12 | */ 13 | 14 | 15 | var peakIndexInMountainArray = function(A) { 16 | return A.indexOf(Math.max(...A)); 17 | }; 18 | peakIndexInMountainArray([0,2,1,0]); -------------------------------------------------------------------------------- /LeetCode/859. 亲密字符串.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定两个由小写字母构成的字符串 A 和 B ,只要我们可以通过交换 A 中的两个字母得到与 B 相等的结果,就返回 true ;否则返回 false 。 3 | 4 | 示例 1: 5 | 输入: A = "ab", B = "ba" 6 | 输出: true 7 | 8 | 示例 2: 9 | 输入: A = "ab", B = "ab" 10 | 输出: false 11 | 12 | 示例 3: 13 | 输入: A = "aa", B = "aa" 14 | 输出: true 15 | */ 16 | 17 | 18 | var buddyStrings = function(A, B) { 19 | let len1 = A.length; 20 | let len2 = B.length; 21 | // 两个字符串长度不等或长度等于1就直接返回false 22 | if(len1 !== len2 || len1 === 1) return false; 23 | let num = 0; 24 | let diff = []; 25 | let len = 0; 26 | for(let i=0; i 2) return false; 34 | } 35 | // 不相等的个数等于2并且交换后相等则返回true 36 | if(num === 2 && (diff[0] == diff[3] && diff[1] === diff[2])) { 37 | return true; 38 | } 39 | // 如果两字符串相等则判断是否有重复的元素,有的话直接返回true,没有的话则返回false 40 | if(num === 0) { 41 | let mark = {}; 42 | for(let i=0; i4->3->2->5->2, x = 3 7 | 输出: 1->2->2->4->3->5 8 | */ 9 | /** 10 | * Definition for singly-linked list. 11 | * function ListNode(val) { 12 | * this.val = val; 13 | * this.next = null; 14 | * } 15 | */ 16 | /** 17 | * @param {ListNode} head 18 | * @param {number} x 19 | * @return {ListNode} 20 | */ 21 | 22 | // 双指针,一个收集小于x的,一个收集大于等于x的,最后把后者链接到前者上 23 | var partition = function(head, x) { 24 | let ans1 = new ListNode(), ans2 = new ListNode(); 25 | let list1 = ans1, list2 = ans2; 26 | while(head) { 27 | let temp = head.next; 28 | if(head.val < x) { 29 | list1.next = head; 30 | list1 = list1.next; 31 | } 32 | else if(head.val >= x) { 33 | list2.next = head; 34 | list2 = list2.next; 35 | } 36 | head = temp; 37 | } 38 | list1.next = ans2.next; 39 | list2.next = null; 40 | return ans1.next; 41 | }; 42 | 43 | // 先把结点值缓存到两个数组,然后再根据小的数组链接链表,再继续链接大的数组 44 | var partition = function(head, x) { 45 | let arr1 = [], arr2 = []; 46 | while(head) { 47 | head.val < x ? arr1.push(head.val) : arr2.push(head.val); 48 | head = head.next; 49 | } 50 | let ans = new ListNode(); 51 | let cur = ans; 52 | while(arr1.length) { 53 | cur.next = new ListNode(arr1.shift()); 54 | cur = cur.next; 55 | } 56 | while(arr2.length) { 57 | cur.next = new ListNode(arr2.shift()); 58 | cur = cur.next; 59 | } 60 | return ans.next; 61 | }; -------------------------------------------------------------------------------- /LeetCode/865. 具有所有最深结点的最小子树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个根为 root 的二叉树,每个结点的深度是它到根的最短距离。 3 | 如果一个结点在整个树的任意结点之间具有最大的深度,则该结点是最深的。 4 | 一个结点的子树是该结点加上它的所有后代的集合。 5 | 返回能满足“以该结点为根的子树中包含所有最深的结点”这一条件的具有最大深度的结点。 6 | */ 7 | 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 | * @return {TreeNode} 18 | */ 19 | var subtreeWithAllDeepest = function(root) { 20 | function computeDeep(root) { 21 | if (!root) { 22 | return 0; 23 | } 24 | return Math.max(computeDeep(root.left), computeDeep(root.right)) + 1; 25 | } 26 | 27 | return (function fn(root) { 28 | let l = computeDeep(root.left); 29 | let r = computeDeep(root.right); 30 | if (l === r) { 31 | return root; 32 | } else if (l > r) { 33 | return fn(root.left); 34 | } else { 35 | return fn(root.right); 36 | } 37 | })(root) 38 | }; -------------------------------------------------------------------------------- /LeetCode/867. 转置矩阵.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个矩阵 A, 返回 A 的转置矩阵。 3 | 矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。 4 | 5 | 示例 1: 6 | 输入:[[1,2,3],[4,5,6],[7,8,9]] 7 | 输出:[[1,4,7],[2,5,8],[3,6,9]] 8 | 9 | 示例 2: 10 | 输入:[[1,2,3],[4,5,6]] 11 | 输出:[[1,4],[2,5],[3,6]] 12 | */ 13 | 14 | var transpose = function(A) { 15 | let rowLen = A[0].length; 16 | let colLen = A.length; 17 | let ans = []; 18 | for(let i=0; i a - b); 28 | }; 29 | 30 | // 从后往前比较 31 | var merge = function(nums1, m, nums2, n) { 32 | while(n > 0) { 33 | if(m === 0 || nums1[m-1] <= nums2[n-1]) { 34 | nums1[n+m-1] = nums2[n-1]; 35 | n--; 36 | } 37 | else if(nums1[m-1] > nums2[n-1]) { 38 | nums1[n+m-1] = nums1[m-1]; 39 | m--; 40 | } 41 | } 42 | return nums1; 43 | }; -------------------------------------------------------------------------------- /LeetCode/884. 两句话中的不常见单词.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定两个句子 A 和 B 。 (句子是一串由空格分隔的单词。每个单词仅由小写字母组成。) 3 | 如果一个单词在其中一个句子中只出现一次,在另一个句子中却没有出现,那么这个单词就是不常见的。 4 | 返回所有不常用单词的列表。 5 | 您可以按任何顺序返回列表。 6 | 7 | 示例 1: 8 | 输入:A = "this apple is sweet", B = "this apple is sour" 9 | 输出:["sweet","sour"] 10 | 11 | 示例 2: 12 | 输入:A = "apple apple", B = "banana" 13 | 输出:["banana"] 14 | 15 | 提示: 16 | 0 <= A.length <= 200 17 | 0 <= B.length <= 200 18 | A 和 B 都只包含空格和小写字母。 19 | */ 20 | /** 21 | * @param {string} A 22 | * @param {string} B 23 | * @return {string[]} 24 | */ 25 | 26 | // 使用map缓存对应数据及其出现的次数,如果只出现一次就是不常见单词 27 | var uncommonFromSentences = function(A, B) { 28 | // 将两个字符串按单词转换为数组 29 | A = A.split(' '); 30 | B = B.split(' '); 31 | let map = new Map(); 32 | [...A, ...B].map((val) => { 33 | let temp = map.get(val) + 1 || 1; 34 | map.set(val, temp); 35 | }); 36 | return [...A, ...B].filter((val) => { 37 | if(map.get(val) === 1) { 38 | return val; 39 | } 40 | }) 41 | }; -------------------------------------------------------------------------------- /LeetCode/889. 根据前序和后序遍历构造二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 返回与给定的前序和后序遍历匹配的任何二叉树。pre 和 post 遍历中的值是不同的正整数。 3 | 4 | 示例: 5 | 输入:pre = [1,2,4,5,3,6,7], post = [4,5,2,6,7,3,1] 6 | 输出:[1,2,3,4,5,6,7] 7 | 提示: 8 | 1 <= pre.length == post.length <= 30 9 | pre[] 和 post[] 都是 1, 2, ..., pre.length 的排列 10 | 每个输入保证至少有一个答案。如果有多个答案,可以返回其中一个。 11 | */ 12 | 13 | /** 14 | * Definition for a binary tree node. 15 | * function TreeNode(val) { 16 | * this.val = val; 17 | * this.left = this.right = null; 18 | * } 19 | */ 20 | /** 21 | * @param {number[]} pre 22 | * @param {number[]} post 23 | * @return {TreeNode} 24 | */ 25 | 26 | // 大致同前/后+中序遍历构建二叉树。后续遍历中倒数第二个元素是右子树的根节点。 27 | // 所以先循环前序遍历序列,找到该根节点的索引为rightIndex,因此可以算出左子树的节点个数是rightIndex-1-l1,进一步可得左右子树的范围 28 | var constructFromPrePost = function(pre, post) { 29 | // l1和r1是左子树的序列范围,l2和r2是右子树的序列范围 30 | return (function fn(l1, r1, l2, r2) { 31 | if (l1 > r1 || l2 > r2) { 32 | return null; 33 | } 34 | let node = new TreeNode(pre[l1]); 35 | let rightIndex = l1 + 1; 36 | for(let i=l1+1; i<=r1; i++) { 37 | if(pre[i] === post[r2-1]) { 38 | rightIndex = i; 39 | break; 40 | } 41 | } 42 | // 左子树的元素个数是 rightIndex - 1 - l1 43 | node.left = fn(l1 + 1, rightIndex - 1, l2, l2 + rightIndex - l1 - 2); 44 | node.right = fn(rightIndex, r1, l2 + rightIndex - l1 - 1, r2 - 1); 45 | return node; 46 | })(0, pre.length - 1, 0, post.length - 1); 47 | }; 48 | -------------------------------------------------------------------------------- /LeetCode/894. 所有可能的满二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 满二叉树是一类二叉树,其中每个结点恰好有 0 或 2 个子结点。 3 | 返回包含 N 个结点的所有可能满二叉树的列表。 答案的每个元素都是一个可能树的根结点。 4 | 答案中每个树的每个结点都必须有 node.val=0。 5 | 你可以按任何顺序返回树的最终列表。 6 | */ 7 | 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 {number} N 17 | * @return {TreeNode[]} 18 | */ 19 | 20 | // 满二叉树的节点数只能是奇数,且如果N为1的话得到的满二叉树只有根节点。假设左子树有leftTreeSum个节点,则右子树有N-1-leftTreeSum个节点。 21 | // 每次递归时都将leftTreeSum+2,将得到的左右子树组合分配并放入结果数组中返回给父节点。 22 | var allPossibleFBT = function(N) { 23 | return (function fn(sum) { 24 | let res = []; 25 | if (sum === 1) { 26 | return [new TreeNode(0)]; 27 | } else if (sum % 2 === 0) { 28 | return res; 29 | } 30 | let leftTreeSum = 1; 31 | while (leftTreeSum < sum) { 32 | let lTree = fn(leftTreeSum); 33 | let rTree = fn(sum - leftTreeSum - 1); 34 | lTree.forEach(l => { 35 | rTree.forEach(r => { 36 | let node = new TreeNode(0); 37 | node.left = l; 38 | node.right = r; 39 | res.push(node); 40 | }) 41 | }) 42 | leftTreeSum += 2; 43 | } 44 | return res; 45 | })(N) 46 | }; -------------------------------------------------------------------------------- /LeetCode/896. 单调数列.js: -------------------------------------------------------------------------------- 1 | /* 2 | 如果数组是单调递增或单调递减的,那么它是单调的。 3 | 如果对于所有 i <= j,A[i] <= A[j],那么数组 A 是单调递增的。 如果对于所有 i <= j,A[i]> = A[j],那么数组 A 是单调递减的。 4 | 当给定的数组 A 是单调数组时返回 true,否则返回 false。 5 | 6 | 示例 1: 7 | 输入:[1,2,2,3] 8 | 输出:true 9 | */ 10 | /** 11 | * @param {number[]} A 12 | * @return {boolean} 13 | */ 14 | var isMonotonic = function(A) { 15 | let increase = false; 16 | let decrease = false; 17 | for(let i=1, len=A.length; i A[i-1]) increase = true; 19 | else if(A[i] < A[i-1]) decrease = true; 20 | } 21 | return increase && decrease ? false : true; 22 | }; 23 | 24 | var isMonotonic = function(A) { 25 | // mark为true表示递减,为false表示递增 26 | let mark = null; 27 | for(let i=1, len=A.length; i A[i-1]) { 37 | return false; 38 | } 39 | else if(mark === false && A[i] < A[i-1]) { 40 | return false; 41 | } 42 | } 43 | return true; 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /LeetCode/9. 回文数.js: -------------------------------------------------------------------------------- 1 | /* 2 | 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 3 | */ 4 | 5 | // 翻转 6 | var isPalindrome = function(x) { 7 | x = x + ''; 8 | let str = x.split('').reverse().join(''); 9 | return str === x; 10 | }; 11 | 12 | // 字符串模拟翻转 13 | var isPalindrome = function(x) { 14 | x = x + ''; 15 | let str = ''; 16 | for(let i=x.length-1; i>=0; i--) { 17 | str += x[i]; 18 | } 19 | return str === x; 20 | }; 21 | 22 | // 模拟实现 23 | var isPalindrome = function(x) { 24 | let num = x; 25 | let ans = 0; 26 | while(x > 0) { 27 | ans = ans * 10 + x % 10; 28 | x = parseInt(x / 10); 29 | } 30 | return ans === num; 31 | }; 32 | console.log(isPalindrome(-121)); 33 | console.log(isPalindrome(121)); -------------------------------------------------------------------------------- /LeetCode/90. 子集 II.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 3 | 说明:解集不能包含重复的子集。 4 | 5 | 示例: 6 | 输入: [1,2,2] 7 | 输出: 8 | [ 9 | [2], 10 | [1], 11 | [1,2,2], 12 | [2,2], 13 | [1,2], 14 | [] 15 | ] 16 | */ 17 | /** 18 | * @param {number[]} nums 19 | * @return {number[][]} 20 | */ 21 | // 思路同第78题,只是需要去重 22 | // 得到重复子集的原因在于,有两个相同的数都添加进了前面的序列中,比如[1,2,2],第一个2已经生成了[1,2],第二个又生成了一次[1,2] 23 | // 所以可以先对nums排序,遇到相同的数则只在上一次得到的新子集上添加,否则向所有的res元素里添加。 24 | // 所以这里只需要标记出上一次得到的新子集的起始就可以了,终点自然是res.length,而起点可以由当前的res长度减去上次增加子集前的res长度之差得到 25 | var subsetsWithDup = function(nums) { 26 | let res = []; 27 | res.push([]); 28 | nums.sort((a, b) => a - b); 29 | // 表示上一次的res长度 30 | let lastLen = 0; 31 | // 表示上一次得到的新子集的起始位置 32 | let left = 0, right = 0; 33 | for(let i=0, len=nums.length; i a - b); 24 | let tem = A[A.length-1] - A[0]; 25 | if(tem <= 2 * K) { 26 | return 0; 27 | } 28 | else { 29 | return tem - 2 * K; 30 | } 31 | }; 32 | console.log(smallestRangeI([2, 7, 2], 1)); 33 | // console.log(smallestRangeI([0, 10], 2)); 34 | // console.log(smallestRangeI([1, 3, 6], 3)); -------------------------------------------------------------------------------- /LeetCode/922. 按奇偶排序数组 II.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。 3 | 对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。 4 | 你可以返回任何满足上述条件的数组作为答案。 5 | 6 | 示例: 7 | 输入:[4,2,5,7] 8 | 输出:[4,5,2,7] 9 | 解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。 10 | */ 11 | 12 | // 双数组下标 13 | var sortArrayByParityII = function(A) { 14 | let res = A.slice(); 15 | let index1 = 1, index2 = 0; 16 | for(let i=0; i= L && root.val <= R) { 35 | ans += root.val; 36 | } 37 | if (root.val < L) { 38 | fn(root.right); 39 | } else if (root.val > R) { 40 | fn(root.left); 41 | } 42 | })(root) 43 | return ans; 44 | }; 45 | 46 | 47 | // 递归。先底向上返回底层的结果最终累加给根节点。 48 | // 当前节点值小于L,则只需要递归右子树;当前节点值大于R,则只需要递归左子树。若L<=当前节点值<=R,则返回左右子树的递归结果+当前的节点值给上层。 49 | var rangeSumBST = function(root, L, R) { 50 | return (function fn(root) { 51 | if (!root) { 52 | return 0; 53 | } 54 | if (root.val < L) { 55 | return fn(root.right); 56 | } 57 | if (root.val > R) { 58 | return fn(root.left); 59 | } 60 | return fn(root.left) + fn(root.right) + root.val; 61 | })(root) 62 | } -------------------------------------------------------------------------------- /LeetCode/94. 二叉树的中序遍历.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,返回它的中序 遍历。 3 | */ 4 | /** 5 | * Definition for a binary tree node. 6 | * function TreeNode(val) { 7 | * this.val = val; 8 | * this.left = this.right = null; 9 | * } 10 | */ 11 | /** 12 | * @param {TreeNode} root 13 | * @return {number[]} 14 | */ 15 | 16 | // 递归 17 | var inorderTraversal = function(root) { 18 | let res = []; 19 | function print(root) { 20 | if(root === null) return root; 21 | print(root.left); 22 | res.push(root.val); 23 | print(root.right); 24 | } 25 | print(root); 26 | return res; 27 | }; 28 | 29 | // 迭代 30 | var inorderTraversal = function(root) { 31 | let cur = root; 32 | let stack = []; 33 | let res = []; 34 | while(cur || stack.length !== 0) { 35 | // 先遍历左子树 36 | if(cur) { 37 | stack.unshift(cur); 38 | cur = cur.left; 39 | } 40 | // 再遍历右子树 41 | else { 42 | cur = stack.shift(); 43 | res.push(cur.val); 44 | cur = cur.right; 45 | } 46 | } 47 | return res; 48 | }; -------------------------------------------------------------------------------- /LeetCode/951. 翻转等价二叉树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 我们可以为二叉树 T 定义一个翻转操作,如下所示:选择任意节点,然后交换它的左子树和右子树。 3 | 只要经过一定次数的翻转操作后,能使 X 等于 Y,我们就称二叉树 X 翻转等价于二叉树 Y。 4 | 编写一个判断两个二叉树是否是翻转等价的函数。这些树由根节点 root1 和 root2 给出。 5 | */ 6 | 7 | /** 8 | * Definition for a binary tree node. 9 | * function TreeNode(val) { 10 | * this.val = val; 11 | * this.left = this.right = null; 12 | * } 13 | */ 14 | /** 15 | * @param {TreeNode} root1 16 | * @param {TreeNode} root2 17 | * @return {boolean} 18 | */ 19 | 20 | // 如果当前根节点相等,则不用继续比较直接返回true。如果根节点只有一个为null或者两个根节点值不相等,则直接返回false。 21 | // 否则按当前树的状态递归,和翻转后(左子树和右子树比较,右子树和左子树比较)递归,对两者的递归结果取或即可。 22 | var flipEquiv = function(root1, root2) { 23 | return (function fn(t1, t2) { 24 | if (t1 === t2) { 25 | return true; 26 | } 27 | if (t1 === null || t2 === null || t1.val !== t2.val) { 28 | return false; 29 | } 30 | return (fn(t1.left, t2.left) && fn(t1.right, t2.right)) || (fn(t1.left, t2.right) && fn(t1.right, t2.left)); 31 | })(root1, root2) 32 | }; 33 | -------------------------------------------------------------------------------- /LeetCode/958. 二叉树的完全性检验.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,确定它是否是一个完全二叉树。 3 | */ 4 | /** 5 | * Definition for a binary tree node. 6 | * function TreeNode(val) { 7 | * this.val = val; 8 | * this.left = this.right = null; 9 | * } 10 | */ 11 | /** 12 | * @param {TreeNode} root 13 | * @return {boolean} 14 | */ 15 | 16 | // 层序遍历。使用一个变量finished标记是否已经遇到空节点。finished为true后若还遇到空节点说明不是完全二叉树。 17 | var isCompleteTree = function(root) { 18 | let arr = [root]; 19 | let finished = false; 20 | while(arr.length) { 21 | let node = arr.shift(); 22 | if (node && finished) { 23 | return false; 24 | } 25 | if (node === null) { 26 | finished = true; 27 | continue; 28 | } 29 | arr.push(node.left); 30 | arr.push(node.right); 31 | } 32 | return true; 33 | }; -------------------------------------------------------------------------------- /LeetCode/96. 不同的二叉搜索树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 3 | 4 | 示例: 5 | 输入: 3 6 | 输出: 5 7 | 解释: 8 | 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 9 | 10 | 1 3 3 2 1 11 | \ / / / \ \ 12 | 3 2 1 1 3 2 13 | / / \ \ 14 | 2 1 2 3 15 | */ 16 | /** 17 | * @param {number} n 18 | * @return {number} 19 | */ 20 | 21 | // 来自该题题解: 22 | // 假设n个节点存在二叉排序树的个数是G(n),令f(i)为以i为根的二叉搜索树的个数,则 23 | // G(n) = f(1) + f(2) + f(3) + f(4) + ... + f(n) 24 | 25 | // 当i为根节点时,其左子树节点个数为i-1个,右子树节点为n-i,则 26 | // f(i) = G(i-1)*G(n-i) 27 | 28 | // 综合两个公式可以得到 卡特兰数 公式 29 | // G(n) = G(0)*G(n-1)+G(1)*(n-2)+...+G(n-1)*G(0) 30 | var numTrees = function(n) { 31 | let arr = [1, 1]; 32 | for(let i=2; i<=n; i++) { 33 | arr[i] = 0; 34 | for(let j=1; j<=i; j++) { 35 | arr[i] += arr[j-1] * arr[i-j]; 36 | } 37 | } 38 | return arr[n]; 39 | }; -------------------------------------------------------------------------------- /LeetCode/961. 重复 N 次的元素.js: -------------------------------------------------------------------------------- 1 | /* 2 | 在大小为 2N 的数组 A 中有 N+1 个不同的元素,其中有一个元素重复了 N 次。 3 | 返回重复了 N 次的那个元素。 4 | */ 5 | 6 | var repeatedNTimes = function(A) { 7 | let res = []; 8 | let length = A.length; 9 | for(let i=0; i a - b); 20 | for(let i=0, len=A.length; i { 8 | return b - a; 9 | }) 10 | for(let i=2; i A[i-2]) { 12 | return A[i] + A[i-1] + A[i-2]; 13 | } 14 | } 15 | return 0; 16 | }; 17 | console.log(largestPerimeter([2, 1, 2])); 18 | console.log(largestPerimeter([3, 2, 3, 4])); 19 | console.log(largestPerimeter([1, 2, 1])); 20 | -------------------------------------------------------------------------------- /LeetCode/977. 有序数组的平方.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个按非递减顺序排序的整数数组 A,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。 3 | 4 | 示例 1: 5 | 输入:[-4,-1,0,3,10] 6 | 输出:[0,1,9,16,100] 7 | */ 8 | 9 | var sortedSquares = function(A) { 10 | A = A.map((val) => { 11 | return val ** 2; 12 | }) 13 | A.sort((a, b) => { 14 | return a - b; 15 | }) 16 | return A; 17 | }; 18 | 19 | // 双指针 20 | var sortedSquares = function(A) { 21 | let len = A.length, k = len - 1; 22 | let i = 0, j = len - 1; 23 | let arr = []; 24 | while(i <= j) { 25 | if(Math.abs(A[i]) > Math.abs(A[j])) { 26 | arr[k] = A[i] ** 2; 27 | i++; 28 | k--; 29 | } 30 | else { 31 | arr[k] = A[j] ** 2; 32 | j--; 33 | k--; 34 | } 35 | } 36 | return arr; 37 | }; 38 | console.log(sortedSquares([-4,-1,0,3,10])); -------------------------------------------------------------------------------- /LeetCode/979. 在二叉树中分配硬币.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个有 N 个结点的二叉树的根结点 root,树中的每个结点上都对应有 node.val 枚硬币,并且总共有 N 枚硬币。 3 | 在一次移动中,我们可以选择两个相邻的结点,然后将一枚硬币从其中一个结点移动到另一个结点。(移动可以是从父结点到子结点,或者从子结点移动到父结点。)。 4 | 返回使每个结点上只有一枚硬币所需的移动次数。 5 | */ 6 | 7 | /** 8 | * Definition for a binary tree node. 9 | * function TreeNode(val) { 10 | * this.val = val; 11 | * this.left = this.right = null; 12 | * } 13 | */ 14 | /** 15 | * @param {TreeNode} root 16 | * @return {number} 17 | */ 18 | 19 | // 递归。从底向上,每次都给父节点返回子树的过载量(超出/缺少多少枚硬币),累加左右子树的过载量即可。 20 | // 注意在累加过载量时需要取绝对值,因为过载量可能是负的。 21 | var distributeCoins = function(root) { 22 | let ans = 0; 23 | (function fn(root) { 24 | if (!root) { 25 | return 0; 26 | } 27 | let l = fn(root.left); 28 | let r = fn(root.right); 29 | ans += Math.abs(l) + Math.abs(r); 30 | return root.val + l + r - 1; 31 | })(root) 32 | return ans; 33 | }; -------------------------------------------------------------------------------- /LeetCode/98. 验证二叉搜索树.js: -------------------------------------------------------------------------------- 1 | /* 2 | 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 3 | 4 | 假设一个二叉搜索树具有如下特征: 5 | 节点的左子树只包含小于当前节点的数。 6 | 节点的右子树只包含大于当前节点的数。 7 | 所有左子树和右子树自身必须也是二叉搜索树。 8 | 9 | 示例 1: 10 | 输入: 11 | 2 12 | / \ 13 | 1 3 14 | 输出: true 15 | 16 | 示例 2: 17 | 输入: 18 | 5 19 | / \ 20 | 1 4 21 | / \ 22 | 3 6 23 | 输出: false 24 | 解释: 输入为: [5,1,4,null,null,3,6]。 25 | 根节点的值为 5 ,但是其右子节点值为 4 。 26 | */ 27 | /** 28 | * Definition for a binary tree node. 29 | * function TreeNode(val) { 30 | * this.val = val; 31 | * this.left = this.right = null; 32 | * } 33 | */ 34 | /** 35 | * @param {TreeNode} root 36 | * @return {boolean} 37 | */ 38 | var isValidBST = function(root) { 39 | let arr = []; 40 | let res = true; 41 | function fn(root) { 42 | if(root === null) return; 43 | fn(root.left); 44 | if(root.val <= arr[arr.length - 1]) { 45 | res = false; 46 | return false; 47 | } 48 | arr.push(root.val); 49 | fn(root.right); 50 | } 51 | fn(root); 52 | return res; 53 | }; -------------------------------------------------------------------------------- /LeetCode/988. 从叶结点开始的最小字符串.js: -------------------------------------------------------------------------------- 1 | import { EOPNOTSUPP } from "constants"; 2 | 3 | /* 4 | 给定一颗根结点为 root 的二叉树,书中的每个结点都有一个从 0 到 25 的值,分别代表字母 'a' 到 'z':值 0 代表 'a',值 1 代表 'b',依此类推。 5 | 找出按字典序最小的字符串,该字符串从这棵树的一个叶结点开始,到根结点结束。 6 | (小贴士:字符串中任何较短的前缀在字典序上都是较小的:例如,在字典序上 "ab" 比 "aba" 要小。叶结点是指没有子结点的结点。) 7 | */ 8 | 9 | /** 10 | * Definition for a binary tree node. 11 | * function TreeNode(val) { 12 | * this.val = val; 13 | * this.left = this.right = null; 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @return {string} 19 | */ 20 | 21 | // 递归。记录从根节点到叶子节点的各条路径后,翻转路径序列变成从叶子节点到根节点,和结果序列比较大小。 22 | var smallestFromLeaf = function(root) { 23 | let res = '{'; 24 | (function fn(root, str) { 25 | if (!root) { 26 | return; 27 | } 28 | str += String.fromCodePoint(root.val + 97); 29 | if (!root.left && !root.right) { 30 | const tem = str.split('').reverse().join(''); 31 | if (res > tem) { 32 | res = tem; 33 | } 34 | } 35 | fn(root.left, str); 36 | fn(root.right, str); 37 | })(root, '') 38 | return res; 39 | }; -------------------------------------------------------------------------------- /LeetCode/989. 数组形式的整数加法.js: -------------------------------------------------------------------------------- 1 | /* 2 | 对于非负整数 X 而言,X 的数组形式是每位数字按从左到右的顺序形成的数组。例如,如果 X = 1231,那么其数组形式为 [1,2,3,1]。 3 | 给定非负整数 X 的数组形式 A,返回整数 X+K 的数组形式。 4 | 5 | 示例 1: 6 | 输入:A = [1,2,0,0], K = 34 7 | 输出:[1,2,3,4] 8 | 解释:1200 + 34 = 1234 9 | */ 10 | 11 | 12 | var addToArrayForm = function(A, K) { 13 | let str = A.join(''); 14 | let str1 = K + ''; 15 | let len = str.length > str1.length ? str.length : str1.length; 16 | str = str.padStart(len, 0); 17 | str1 = str1.padStart(len, 0); 18 | let arr = []; 19 | let carry = 0; 20 | for(let i=len-1; i>=0; i--) { 21 | let tem = parseInt(str[i]) + parseInt(str1[i]) + carry; 22 | carry = parseInt(tem / 10); 23 | arr.unshift(parseInt(tem % 10)); 24 | } 25 | if(carry) { 26 | arr.unshift(carry); 27 | } 28 | return arr; 29 | }; 30 | 31 | console.log(addToArrayForm([1,2,6,3,0,7,1,7,1,9,7,5,6,6,4,4,0,0,6,3], 516)); 32 | console.log(addToArrayForm([2, 7, 4], 181)); 33 | console.log(addToArrayForm([2, 1, 5], 806)); -------------------------------------------------------------------------------- /LeetCode/993. 二叉树的堂兄弟节点.js: -------------------------------------------------------------------------------- 1 | /* 2 | 在二叉树中,根节点位于深度 0 处,每个深度为 k 的节点的子节点位于深度 k+1 处。 3 | 如果二叉树的两个节点深度相同,但父节点不同,则它们是一对堂兄弟节点。 4 | 我们给出了具有唯一值的二叉树的根节点 root,以及树中两个不同节点的值 x 和 y。 5 | 只有与值 x 和 y 对应的节点是堂兄弟节点时,才返回 true。否则,返回 false。 6 | */ 7 | /** 8 | * Definition for a binary tree node. 9 | * function TreeNode(val) { 10 | * this.val = val; 11 | * this.left = this.right = null; 12 | * } 13 | */ 14 | /** 15 | * @param {TreeNode} root 16 | * @param {number} x 17 | * @param {number} y 18 | * @return {boolean} 19 | */ 20 | 21 | // 记录首先遇到的目标节点的父节点值和深度值,父节点值和深度值作为递归函数的参数传递。 22 | var isCousins = function(root, x, y) { 23 | let first = null; 24 | let ans = false; 25 | (function fn(root, deep, father) { 26 | if (!root) { 27 | return; 28 | } 29 | if (root.val === x || root.val === y) { 30 | if (first) { 31 | ans = (father !== first.father && deep === first.deep) ? true : false; 32 | return; 33 | } else { 34 | first = { 35 | father, 36 | deep 37 | } 38 | } 39 | } 40 | fn(root.left, deep + 1, root.val); 41 | fn(root.right, deep + 1, root.val); 42 | })(root, 0, null) 43 | return ans; 44 | }; -------------------------------------------------------------------------------- /LeetCode/997. 找到小镇的法官.js: -------------------------------------------------------------------------------- 1 | /* 2 | 在一个小镇里,按从 1 到 N 标记了 N 个人。传言称,这些人中有一个是小镇上的秘密法官。 3 | 4 | 如果小镇的法官真的存在,那么: 5 | 小镇的法官不相信任何人。 6 | 每个人(除了小镇法官外)都信任小镇的法官。 7 | 只有一个人同时满足属性 1 和属性 2 。 8 | 给定数组 trust,该数组由信任对 trust[i] = [a, b] 组成,表示标记为 a 的人信任标记为 b 的人。 9 | 10 | 如果小镇存在秘密法官并且可以确定他的身份,请返回该法官的标记。否则,返回 -1。 11 | */ 12 | 13 | 14 | var findJudge = function(N, trust) { 15 | if(trust.length === 0) return true; 16 | // 用于标记有多少个人信任这个人 17 | let trustNum = []; 18 | // 用于标记这个人是否信任别人,是的话则为true 19 | let mark = []; 20 | for(let i=0; i= str.length) { 20 | res.push(str); 21 | } 22 | for(let i=start; i { 30 | return a - b; 31 | }) 32 | for(let i=0; i= 0) { 41 | if(matrix[row][col] === target) { 42 | return true; 43 | } else if (matrix[row][col] > target) { 44 | col--; 45 | } else if (matrix[row][col] < target) { 46 | row++ 47 | } 48 | } 49 | return false; 50 | } 51 | -------------------------------------------------------------------------------- /剑指Offer/面试题05. 替换空格.js: -------------------------------------------------------------------------------- 1 | /* 2 | 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。 3 | 4 | 示例 1: 5 | 输入:s = "We are happy." 6 | 输出:"We%20are%20happy." 7 | 8 | 限制:0 <= s 的长度 <= 10000 9 | */ 10 | 11 | /** 12 | * @param {string} s 13 | * @return {string} 14 | */ 15 | 16 | // replace + 正则表达式 17 | var replaceSpace = function(s) { 18 | return s.replace(/ /g, '%20'); 19 | }; 20 | 21 | // 使用一个新的字符串,遇到空格就拼接 %20,否则就拼接原来的字符 22 | var replaceSpace = function(s) { 23 | let res = ''; 24 | for(let i=0; i r1 || l2 > r2) { 32 | return null; 33 | } 34 | let mid = 0; 35 | for(let i=l2; i<=r2; i++) { 36 | if (inorder[i] === preorder[l1]) { 37 | mid = i; 38 | break; 39 | } 40 | } 41 | const leftSum = mid - l2; 42 | const node = new TreeNode(preorder[l1]); 43 | node.left = fn(l1 + 1, l1 + leftSum, l2, mid - 1); 44 | node.right = fn(l1 + leftSum + 1, r1, mid + 1, r2); 45 | return node; 46 | } 47 | return fn(0, preorder.length - 1, 0, inorder.length - 1); 48 | } 49 | -------------------------------------------------------------------------------- /剑指Offer/面试题09. 用两个栈实现队列.js: -------------------------------------------------------------------------------- 1 | /* 2 | 用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 ) 3 | 4 | 示例 1: 5 | 输入: 6 | ["CQueue","appendTail","deleteHead","deleteHead"] 7 | [[],[3],[],[]] 8 | 输出:[null,null,3,-1] 9 | 10 | 示例 2: 11 | 输入: 12 | ["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"] 13 | [[],[],[5],[2],[],[]] 14 | 输出:[null,-1,null,null,5,2] 15 | 16 | 提示: 17 | 1 <= values <= 10000 18 | 最多会对 appendTail、deleteHead 进行 10000 次调用 19 | */ 20 | 21 | // 把 arr1 和 arr2 当做是两个栈,后进先出,所以只能使用 push 和 pop 方法 22 | // 入队的时候,都将数据放到 arr1 里面。 23 | // 出队的时候,如果 arr2 为空,就将 arr1 的所有元素 pop 到 arr2 中,这样 arr2 中的数据顺序就符合先进先出了。 24 | // 如果 arr2 不为空,就直接从 arr2 里取数据,这样就不用每次出队都将 arr1 里的数据放到 arr2 里 25 | var CQueue = function() { 26 | this.arr1 = []; 27 | this.arr2 = []; 28 | }; 29 | 30 | /** 31 | * @param {number} value 32 | * @return {void} 33 | */ 34 | CQueue.prototype.appendTail = function(value) { 35 | this.arr1.push(value); 36 | }; 37 | 38 | /** 39 | * @return {number} 40 | */ 41 | CQueue.prototype.deleteHead = function() { 42 | if(this.arr2.length === 0) { 43 | while(this.arr1.length) { 44 | this.arr2.push(this.arr1.pop()); 45 | } 46 | } 47 | return this.arr2.length === 0 ? -1 : this.arr2.pop(); 48 | }; 49 | -------------------------------------------------------------------------------- /剑指Offer/面试题10- I. 斐波那契数列.js: -------------------------------------------------------------------------------- 1 | /* 2 | 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下: 3 | F(0) = 0,   F(1) = 1 4 | F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 5 | 斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。 6 | 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 7 | 8 | 示例 1: 9 | 输入:n = 2 10 | 输出:1 11 | 12 | 示例 2: 13 | 输入:n = 5 14 | 输出:5 15 |   16 | 提示: 17 | 0 <= n <= 100 18 | */ 19 | 20 | /** 21 | * @param {number} n 22 | * @return {number} 23 | */ 24 | 25 | // 递归,会超时 26 | var fib = function(n) { 27 | if (n === 0) { 28 | return 0; 29 | } 30 | if (n === 1) { 31 | return 1; 32 | } 33 | return (fib(n-1) + fib(n-2)) % 1000000007; 34 | }; 35 | 36 | // 递归 + 记忆数组,防止对已经计算出来的值重复递归计算 37 | // 时间复杂度 O(n),空间复杂度 O(n) 38 | var fib = function(n) { 39 | const arr = [0, 1]; 40 | function fn(n) { 41 | if (arr[n] !== undefined) { 42 | return arr[n]; 43 | } 44 | arr[n] = (fn(n-1) + fn(n-2)) % 1000000007; 45 | return arr[n]; 46 | } 47 | return fn(n); 48 | }; 49 | 50 | // DP,使用两个变量来保存上一个和上上一个值,可以使得空间复杂度为 O(1) 51 | var fib = function(n) { 52 | let first = 0, second = 1; 53 | if (n === 0) { 54 | return first; 55 | } 56 | if (n === 1) { 57 | return second; 58 | } 59 | for(let i=2; i<=n; i++) { 60 | [first, second] = [second, (first + second) % 1000000007]; 61 | } 62 | return second; 63 | } 64 | 65 | // 斐波那契数列还可以用矩阵来求解,印象中用矩阵是最快的(时间复杂度是 O(logN)),但已经忘了怎么写了。 -------------------------------------------------------------------------------- /剑指Offer/面试题10- II. 青蛙跳台阶问题.js: -------------------------------------------------------------------------------- 1 | /* 2 | 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。 3 | 4 | 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 5 | 6 | 示例 1: 7 | 输入:n = 2 8 | 输出:2 9 | 10 | 示例 2: 11 | 输入:n = 7 12 | 输出:21 13 | 14 | 提示: 15 | 0 <= n <= 100 16 | */ 17 | 18 | /** 19 | * @param {number} n 20 | * @return {number} 21 | */ 22 | var numWays = function(n) { 23 | var fib = function(n) { 24 | const arr = [1, 1]; 25 | function fn(n) { 26 | if (arr[n] !== undefined) { 27 | return arr[n]; 28 | } 29 | arr[n] = (fn(n-1) + fn(n-2)) % 1000000007; 30 | return arr[n]; 31 | } 32 | return fn(n); 33 | }; 34 | return fib(n); 35 | }; 36 | 37 | var numWays = function(n) { 38 | var fib = function(n) { 39 | let first = 1, second = 1; 40 | if (n === 0) { 41 | return first; 42 | } 43 | if (n === 1) { 44 | return second; 45 | } 46 | for(let i=2; i<=n; i++) { 47 | [first, second] = [second, (first + second) % 1000000007]; 48 | } 49 | return second; 50 | } 51 | return fib(n); 52 | } 53 | --------------------------------------------------------------------------------