diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..931e226 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +.DS_Store +._* +.cache +.project +.settings +.tmproj +*.esproj +*.sublime-project +*.sublime-workspace +nbproject +thumbs.db +*.iml + +# Folders to ignore +.hg +.svn +.CVS +.idea +node_modules/ +jscoverage_lib/ +bower_components/ +dist/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index f04c200..6d334cc 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,5 @@ { "printWidth": 80, - "tabWidth": 2 + "tabWidth": 2, + "semi": false } \ No newline at end of file diff --git "a/BFS\351\227\256\351\242\230/\350\267\263\350\267\203\346\270\270\346\210\217 III-1306.js" "b/BFS\351\227\256\351\242\230/\350\267\263\350\267\203\346\270\270\346\210\217 III-1306.js" new file mode 100644 index 0000000..73d910e --- /dev/null +++ "b/BFS\351\227\256\351\242\230/\350\267\263\350\267\203\346\270\270\346\210\217 III-1306.js" @@ -0,0 +1,27 @@ +/** + * @param {number[]} arr + * @param {number} start + * @return {boolean} + */ +let canReach = function (arr, start) { + let n = arr.length + let visited = [] + let queue = [start] + while (queue.length) { + let index = queue.pop() + let val = arr[index] + if (val === 0) { + return true + } + let left = index - val + let right = index + val + if (left >= 0 && !visited[left]) { + queue.push(left) + } + if (right < n && !visited[right]) { + queue.push(right) + } + visited[index] = true + } + return false +}; \ No newline at end of file diff --git "a/BFS\351\227\256\351\242\230/\350\267\263\350\267\203\346\270\270\346\210\217 IV-1345.js" "b/BFS\351\227\256\351\242\230/\350\267\263\350\267\203\346\270\270\346\210\217 IV-1345.js" new file mode 100644 index 0000000..be115b2 --- /dev/null +++ "b/BFS\351\227\256\351\242\230/\350\267\263\350\267\203\346\270\270\346\210\217 IV-1345.js" @@ -0,0 +1,72 @@ +/** + * @param {number[]} arr + * @return {number} + */ +let minJumps = function (arr) { + let n = arr.length + if (n === 1) { + return 0 + } + + // 连续出现超过两次的数字就抛弃掉 + let newArr = [] + let sameCount = 0 + for (let i = 0; i < arr.length; i++) { + if (arr[i] === arr[i - 1]) { + sameCount += 1 + if (sameCount >= 2) { + continue + } else { + newArr.push(arr[i]) + } + } else { + newArr.push(arr[i]) + sameCount = 0 + } + } + arr = newArr + n = arr.length + // 遍历一遍 记录每个数字出现的下标位置 + let indexesMap = new Map() + for (let i = 0; i < n; i++) { + let val = arr[i] + let indexes = indexesMap.get(val) + if (!indexes) { + indexesMap.set(val, [i]) + } else { + indexes.push(i) + } + } + + let visited = [] + let count = 0 + let queue = [0] + while (queue.length) { + count++ + let len = queue.length + for (let i = 0; i < len; i++) { + let index = queue.shift() + // 找到了 由于bfs的特性 此时用的跳跃次数一定是最少的 + if (index === n - 1) { + return count - 1 + } + + // 没找到 继续把可以跳的几个位置都放入队列中 + let val = arr[index] + let left = index - 1 + let right = index + 1 + let sameIndexes = indexesMap.get(val) + + if (left >= 0 && !visited[left]) queue.push(left) + if (right < n && !visited[right]) queue.push(right) + for (let sameIndex of sameIndexes) { + if (sameIndex !== index && !visited[sameIndex]) { + queue.push(sameIndex) + } + } + + visited[index] = true + } + } + return n +} diff --git "a/LRU\347\274\223\345\255\230.js" "b/LRU\347\274\223\345\255\230.js" new file mode 100644 index 0000000..25d09e7 --- /dev/null +++ "b/LRU\347\274\223\345\255\230.js" @@ -0,0 +1,94 @@ +class DoubleNode { + constructor(key, val) { + this.key = key + this.val = val + + this.prev = null + this.next = null + } +} + +class LRUCache { + constructor(max) { + this.max = max + this.map = new Map() + + this.head = null + this.tail = null + } + + get(key) { + const node = this.map.get(key) + if (!node) { + return -1 + } else { + const res = node.val + this.remove(node) + this.appendHead(node) + return res + } + } + + put(key, value) { + let node = this.map.get(key) + // 有这个缓存 + if (node) { + node.val = value + // 新加入的 放在最前面 + this.remove(node) + this.appendHead(node) + } else { + // 没有这个缓存 + node = new DoubleNode(key, value) + // 如果超出容量了 删除最后一个 再放到头部 + if (this.map.size >= this.max) { + this.map.delete(this.tail.key) + this.remove(this.tail) + this.appendHead(node) + this.map.set(key, node) + } else { + // 未超出容量 就直接放到头部 + this.appendHead(node) + this.map.set(key, node) + } + } + } + + /** + * 把头部指针的改变成新的node + * @param {DoubleNode} node + */ + appendHead(node) { + if (this.head === null) { + this.head = this.tail = node + } else { + node.next = this.head + this.head.prev = node + this.head = node + } + } + + /** + * 删除某个节点 + * @param {DoubleNode} node + */ + remove(node) { + if (this.head === this.tail) { + this.head = this.tail = null + } else { + // 删除头部 + if (this.head === node) { + this.head = this.head.next + node.next = null + } else if (this.tail === node) { + this.tail = this.tail.prev + this.tail.next = null + node.prev = null + } else { + node.prev.next = node.next + node.next.prev = node.prev + node.prev = node.next = null + } + } + } +} diff --git a/README.md b/README.md index c2fd139..11f4963 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,13 @@ > 力扣的题解记录(JavaScript) +## 关于我 +大家好,我是 ssh,现在在字节跳动的 Web Infra 担任前端工程师,微信:**[sshsunlight](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/017d568dc1d14cd883cc3238350a39ec~tplv-k3u1fbpfcp-watermark.image)**,欢迎找我交个朋友。 + +一些算法相关的资料,我放在「前端从进阶到入院」公众号里了,回复「资料」即可获取。 + +![qrcode_for_gh_d2b31290dd8b_258](https://user-images.githubusercontent.com/23615778/134800856-9a44fa9a-4f1b-4884-a0b6-b58c5f3331df.jpg) + ## 调试 提供了 .vscode 配置文件,在 vscode 中选择「小爬虫」图标,点击启动程序,即可启动断点调试。 @@ -15,6 +22,323 @@ 思路会记录在本仓库的 Issues 中,按照 label 进行分类。比如想查看 「DFS」 分类下的问题,那么选择标签进行筛选即可。 +## 目录 + + +### 例题详解 + +[最接近的三数之和-16](https://github.com/sl1673495/leetcode-javascript/issues/115) + +[分发饼干-455](https://github.com/sl1673495/leetcode-javascript/issues/88) + +[N皇后-51](https://github.com/sl1673495/leetcode-javascript/issues/78) + +[单词搜索-79](https://github.com/sl1673495/leetcode-javascript/issues/77) + +[二进制手表-401](https://github.com/sl1673495/leetcode-javascript/issues/76) + +[电话号码的字母组合-17](https://github.com/sl1673495/leetcode-javascript/issues/65) + +[二叉树的所有路径-257](https://github.com/sl1673495/leetcode-javascript/issues/59) + +[路径总和-112](https://github.com/sl1673495/leetcode-javascript/issues/57) + +[两两交换链表中的节点-24](https://github.com/sl1673495/leetcode-javascript/issues/51) + +[有效的括号-20](https://github.com/sl1673495/leetcode-javascript/issues/48) + +[无重复字符的最长子串-3](https://github.com/sl1673495/leetcode-javascript/issues/42) + +[二分查找-704](https://github.com/sl1673495/leetcode-javascript/issues/23) + +### 递归与回溯 + +[跳水板-面试题 16.11 ](https://github.com/sl1673495/leetcode-javascript/issues/118) + +[顺次数-1291](https://github.com/sl1673495/leetcode-javascript/issues/116) + +[螺旋矩阵 II-59](https://github.com/sl1673495/leetcode-javascript/issues/113) + +[螺旋矩阵-54](https://github.com/sl1673495/leetcode-javascript/issues/112) + +[矩阵置零-73](https://github.com/sl1673495/leetcode-javascript/issues/111) + +[不同路径 III-980](https://github.com/sl1673495/leetcode-javascript/issues/107) + +[字母大小写全排列-784](https://github.com/sl1673495/leetcode-javascript/issues/106) + +[黄金矿工-1219](https://github.com/sl1673495/leetcode-javascript/issues/105) + +[有重复字符串的排列组合-面试题 08.08](https://github.com/sl1673495/leetcode-javascript/issues/104) + +[单词搜索 II-212](https://github.com/sl1673495/leetcode-javascript/issues/92) + +[解数独-37](https://github.com/sl1673495/leetcode-javascript/issues/79) + +[N皇后-51](https://github.com/sl1673495/leetcode-javascript/issues/78) + +[单词搜索-79](https://github.com/sl1673495/leetcode-javascript/issues/77) + +[二进制手表-401](https://github.com/sl1673495/leetcode-javascript/issues/76) + +[子集 II-90](https://github.com/sl1673495/leetcode-javascript/issues/75) + +[ 组合总和 III-216](https://github.com/sl1673495/leetcode-javascript/issues/74) + +[组合总和 II-40](https://github.com/sl1673495/leetcode-javascript/issues/73) + +[组合总和-39](https://github.com/sl1673495/leetcode-javascript/issues/72) + +[子集-78](https://github.com/sl1673495/leetcode-javascript/issues/71) + +[组合-77](https://github.com/sl1673495/leetcode-javascript/issues/70) + +[全排列 II-47](https://github.com/sl1673495/leetcode-javascript/issues/69) + +[全排列-46](https://github.com/sl1673495/leetcode-javascript/issues/68) + +[分割回文串-131](https://github.com/sl1673495/leetcode-javascript/issues/67) + +[复原IP地址-93](https://github.com/sl1673495/leetcode-javascript/issues/66) + +[电话号码的字母组合-17](https://github.com/sl1673495/leetcode-javascript/issues/65) + +[括号生成-22](https://github.com/sl1673495/leetcode-javascript/issues/31) + +### 动态规划 + +[最长的斐波那契子序列的长度-873](https://github.com/sl1673495/leetcode-javascript/issues/117) + +[最长重复子数组-718](https://github.com/sl1673495/leetcode-javascript/issues/114) + +[下降路径最小和-931](https://github.com/sl1673495/leetcode-javascript/issues/108) + +[最大正方形-221](https://github.com/sl1673495/leetcode-javascript/issues/101) + +[恢复空格-面试题 17.13](https://github.com/sl1673495/leetcode-javascript/issues/100) + +[最长单词-面试题 17.15](https://github.com/sl1673495/leetcode-javascript/issues/99) + +[单词拆分 II-140](https://github.com/sl1673495/leetcode-javascript/issues/95) + +[单词拆分-139](https://github.com/sl1673495/leetcode-javascript/issues/93) + +[最长回文子串-5](https://github.com/sl1673495/leetcode-javascript/issues/91) + +[无重叠区间-435](https://github.com/sl1673495/leetcode-javascript/issues/90) + +[目标和-494](https://github.com/sl1673495/leetcode-javascript/issues/87) + +[一和零-474](https://github.com/sl1673495/leetcode-javascript/issues/86) + +[最长公共子序列-1143](https://github.com/sl1673495/leetcode-javascript/issues/85) + +[摆动序列-376](https://github.com/sl1673495/leetcode-javascript/issues/84) + +[最长上升子序列-300](https://github.com/sl1673495/leetcode-javascript/issues/83) + +[最长等差数列-1027](https://github.com/sl1673495/leetcode-javascript/issues/82) + +[解码方法-91](https://github.com/sl1673495/leetcode-javascript/issues/81) + +[三角形最小路径和-120](https://github.com/sl1673495/leetcode-javascript/issues/80) + +[最小路径和-64](https://github.com/sl1673495/leetcode-javascript/issues/34) + +[括号生成-22](https://github.com/sl1673495/leetcode-javascript/issues/31) + +[爬楼梯-70](https://github.com/sl1673495/leetcode-javascript/issues/22) + +[买卖股票的最佳时机-121](https://github.com/sl1673495/leetcode-javascript/issues/19) + +### 双指针 + +[最接近的三数之和-16](https://github.com/sl1673495/leetcode-javascript/issues/115) + +[通过删除字母匹配到字典里最长单词-524](https://github.com/sl1673495/leetcode-javascript/issues/98) + +[搜索二维矩阵 II-240](https://github.com/sl1673495/leetcode-javascript/issues/96) + +[判断子序列-392](https://github.com/sl1673495/leetcode-javascript/issues/89) + +[分发饼干-455](https://github.com/sl1673495/leetcode-javascript/issues/88) + +[验证回文串-125](https://github.com/sl1673495/leetcode-javascript/issues/33) + +[两数之和 II - 输入有序数组-167](https://github.com/sl1673495/leetcode-javascript/issues/32) + +[合并两个有序数组-88](https://github.com/sl1673495/leetcode-javascript/issues/29) + +[移动零-283](https://github.com/sl1673495/leetcode-javascript/issues/26) + +### 前缀和 + +[和为K的子数组-560](https://github.com/sl1673495/leetcode-javascript/issues/110) + +### 位运算 + +[找不同-389](https://github.com/sl1673495/leetcode-javascript/issues/109) + +### 查找表 + +[找不同-389](https://github.com/sl1673495/leetcode-javascript/issues/109) + +[两个数组的交集 II-350](https://github.com/sl1673495/leetcode-javascript/issues/37) + +### BFS + +[跳跃游戏 IV-1345](https://github.com/sl1673495/leetcode-javascript/issues/103) + +[跳跃游戏 III-1306](https://github.com/sl1673495/leetcode-javascript/issues/102) + +[二叉树的最小深度-111](https://github.com/sl1673495/leetcode-javascript/issues/54) + +[二叉树的最大深度-104](https://github.com/sl1673495/leetcode-javascript/issues/53) + +[二叉树的右视图-199](https://github.com/sl1673495/leetcode-javascript/issues/52) + +[二叉树的层序遍历-102](https://github.com/sl1673495/leetcode-javascript/issues/30) + +[相同的树-100](https://github.com/sl1673495/leetcode-javascript/issues/21) + +### 排序 + +[最长单词-面试题 17.15](https://github.com/sl1673495/leetcode-javascript/issues/99) + +[通过删除字母匹配到字典里最长单词-524](https://github.com/sl1673495/leetcode-javascript/issues/98) + +[快速排序](https://github.com/sl1673495/leetcode-javascript/issues/41) + +[颜色分类-75](https://github.com/sl1673495/leetcode-javascript/issues/28) + +### 链表 + +[移除链表元素-203](https://github.com/sl1673495/leetcode-javascript/issues/97) + +[两数相加-3](https://github.com/sl1673495/leetcode-javascript/issues/94) + +[两两交换链表中的节点-24](https://github.com/sl1673495/leetcode-javascript/issues/51) + +[删除链表的倒数第N个节点-19](https://github.com/sl1673495/leetcode-javascript/issues/46) + +[删除链表的节点-面试题18](https://github.com/sl1673495/leetcode-javascript/issues/40) + +[反转链表II-92](https://github.com/sl1673495/leetcode-javascript/issues/39) + +[反转链表 206](https://github.com/sl1673495/leetcode-javascript/issues/38) + +### 贪心算法 + +[判断子序列-392](https://github.com/sl1673495/leetcode-javascript/issues/89) + +[分发饼干-455](https://github.com/sl1673495/leetcode-javascript/issues/88) + +[买卖股票的最佳时机 II-122](https://github.com/sl1673495/leetcode-javascript/issues/20) + +### DFS + +[二叉树的最近公共祖先-236](https://github.com/sl1673495/leetcode-javascript/issues/64) + +[将有序数组转换为二叉搜索树](https://github.com/sl1673495/leetcode-javascript/issues/63) + +[删除二叉搜索树中的节点-450](https://github.com/sl1673495/leetcode-javascript/issues/62) + +[路径总和 III-437](https://github.com/sl1673495/leetcode-javascript/issues/61) + +[求根到叶子节点数字之和-129](https://github.com/sl1673495/leetcode-javascript/issues/60) + +[二叉树的所有路径-257](https://github.com/sl1673495/leetcode-javascript/issues/59) + +[左叶子之和-404](https://github.com/sl1673495/leetcode-javascript/issues/58) + +[路径总和-112](https://github.com/sl1673495/leetcode-javascript/issues/57) + +[平衡二叉树-110](https://github.com/sl1673495/leetcode-javascript/issues/56) + +[对称二叉树-101](https://github.com/sl1673495/leetcode-javascript/issues/55) + +[二叉树的最小深度-111](https://github.com/sl1673495/leetcode-javascript/issues/54) + +[二叉树的最大深度-104](https://github.com/sl1673495/leetcode-javascript/issues/53) + +[二叉树的层序遍历-102](https://github.com/sl1673495/leetcode-javascript/issues/30) + +[路径总和 II-113](https://github.com/sl1673495/leetcode-javascript/issues/27) + +[相同的树-100](https://github.com/sl1673495/leetcode-javascript/issues/21) + +### 二叉树 + +[二叉树的最近公共祖先-236](https://github.com/sl1673495/leetcode-javascript/issues/64) + +[将有序数组转换为二叉搜索树](https://github.com/sl1673495/leetcode-javascript/issues/63) + +[删除二叉搜索树中的节点-450](https://github.com/sl1673495/leetcode-javascript/issues/62) + +[路径总和 III-437](https://github.com/sl1673495/leetcode-javascript/issues/61) + +[求根到叶子节点数字之和-129](https://github.com/sl1673495/leetcode-javascript/issues/60) + +[二叉树的所有路径-257](https://github.com/sl1673495/leetcode-javascript/issues/59) + +[左叶子之和-404](https://github.com/sl1673495/leetcode-javascript/issues/58) + +[路径总和-112](https://github.com/sl1673495/leetcode-javascript/issues/57) + +[平衡二叉树-110](https://github.com/sl1673495/leetcode-javascript/issues/56) + +[对称二叉树-101](https://github.com/sl1673495/leetcode-javascript/issues/55) + +[二叉树的最小深度-111](https://github.com/sl1673495/leetcode-javascript/issues/54) + +[二叉树的最大深度-104](https://github.com/sl1673495/leetcode-javascript/issues/53) + +[二叉树的右视图-199](https://github.com/sl1673495/leetcode-javascript/issues/52) + +[二叉树的前序遍历-144](https://github.com/sl1673495/leetcode-javascript/issues/50) + +[二叉树的层序遍历-102](https://github.com/sl1673495/leetcode-javascript/issues/30) + +[路径总和 II-113](https://github.com/sl1673495/leetcode-javascript/issues/27) + +[相同的树-100](https://github.com/sl1673495/leetcode-javascript/issues/21) + +### 栈和队列 + +[二叉树的右视图-199](https://github.com/sl1673495/leetcode-javascript/issues/52) + +[二叉树的前序遍历-144](https://github.com/sl1673495/leetcode-javascript/issues/50) + +[简化路径-71](https://github.com/sl1673495/leetcode-javascript/issues/49) + +[有效的括号-20](https://github.com/sl1673495/leetcode-javascript/issues/48) + +[逆波兰表达式求值-150](https://github.com/sl1673495/leetcode-javascript/issues/47) + +### 滑动窗口 + +[滑动窗口的最大值-239](https://github.com/sl1673495/leetcode-javascript/issues/45) + +[找到字符串中所有字母异位词-438](https://github.com/sl1673495/leetcode-javascript/issues/44) + +[最小覆盖子串-76](https://github.com/sl1673495/leetcode-javascript/issues/43) + +[无重复字符的最长子串-3](https://github.com/sl1673495/leetcode-javascript/issues/42) + +[长度最小的子数组-209](https://github.com/sl1673495/leetcode-javascript/issues/36) + +### 数据结构 + +[LRU 缓存机制-146](https://github.com/sl1673495/leetcode-javascript/issues/35) + +### 二分查找 + +[Pow(x, n)-50](https://github.com/sl1673495/leetcode-javascript/issues/25) + +[x 的平方根-69](https://github.com/sl1673495/leetcode-javascript/issues/24) + +[二分查找-704](https://github.com/sl1673495/leetcode-javascript/issues/23) + ## Author 👤 **ssh** diff --git a/longest-prefix.js b/longest-prefix.js deleted file mode 100644 index 389f83e..0000000 --- a/longest-prefix.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * 「快乐前缀」是在原字符串中既是 非空 前缀也是后缀(不包括原字符串自身)的字符串。 - - 给你一个字符串 s,请你返回它的 最长快乐前缀。 - - 如果不存在满足题意的前缀,则返回一个空字符串。 - - 示例: - - 输入:s = 'level' - - 输出:'l' - - 解释:不包括 s 自己,一共有 4 个前缀('l', 'le', 'lev', 'leve')和 4 个后缀('l', 'el', 'vel', 'evel')。最长的既是前缀也是后缀的字符串是 'l' 。 - */ - -function makeNext(str) { - let index = 1 - let k = 0 - const len = str.length - const next = Array(len).fill(0) - for (; index < len; index += 1) { - while(k > 0 && str[index] !== str[k]) { - k = next[k - 1] - } - if (str[index] === str[k]) { - k++ - } - next[index] = k - } - return next -} - -// function longestPrefix(s) { -// const max = s.length -// const next = makeNext(s) -// if (max > 0) { -// return s.slice(0, next[max - 1]) -// } -// return '' -// } - -console.log(makeNext('leabcdleabcdlv')) \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..3c48796 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "glob": "^7.1.6" + } +} diff --git a/sum-four-divisors.js b/sum-four-divisors.js deleted file mode 100644 index aeaa8d5..0000000 --- a/sum-four-divisors.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @param {number[]} nums - * @return {number} - */ -let sumFourDivisors = function(nums) { - let sum = 0 - for (let i = 0; i < nums.length; i++) { - let divisorSet = findDivisor(nums[i]) - if (divisorSet.size === 4) { - divisorSet.forEach(num => { - sum += num - }) - } - } - return sum -}; - -function findDivisor(num) { - // 超过这个边界就不用继续求值了 - let max = Math.floor(Math.sqrt(num)) - let set = new Set() - for (let i = 1; i <= max; i ++) { - let result = num / i - // 除数是整数 - if (result % 1 === 0) { - set.add(result) - // 除以结果 是另一个因数 - set.add(num / result) - } - } - return set -} - -console.log(sumFourDivisors([21,4,7])) \ No newline at end of file diff --git "a/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206II-350.js" "b/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206II-350.js" new file mode 100644 index 0000000..be6e139 --- /dev/null +++ "b/\344\270\244\344\270\252\346\225\260\347\273\204\347\232\204\344\272\244\351\233\206II-350.js" @@ -0,0 +1,36 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number[]} + */ +let intersect = function (nums1, nums2) { + let map1 = makeCountMap(nums1) + let map2 = makeCountMap(nums2) + let res = [] + for (let num of map1.keys()) { + const count1 = map1.get(num) + const count2 = map2.get(num) + + if (count2) { + const pushCount = Math.min(count1, count2) + for (let i = 0; i < pushCount; i++) { + res.push(num) + } + } + } + return res +} + +function makeCountMap(nums) { + let map = new Map() + for (let i = 0; i < nums.length; i++) { + let num = nums[i] + let count = map.get(num) + if (count) { + map.set(num, count + 1) + } else { + map.set(num, 1) + } + } + return map +} diff --git "a/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.js" "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.js" new file mode 100644 index 0000000..30d1ff5 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240.js" @@ -0,0 +1,34 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @param {number} k + * @return {number} + */ +var kthSmallest = function (root, k) { + let count = 0 + let finded + + let dfs = (node) => { + if (!node) { + return + } + dfs(node.left) + count++ + if (count === k) { + finded = node.val + return + } + dfs(node.right) + } + + dfs(root) + + return finded +} diff --git "a/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276-199.js" "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276-199.js" new file mode 100644 index 0000000..5ef8278 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\217\263\350\247\206\345\233\276-199.js" @@ -0,0 +1,23 @@ +let rightSideView = function (root) { + if (!root) return [] + let queue = [root] + let res = [] + while (queue.length) { + let len = queue.length + let last + for (let i = 0; i < len; i++) { + let node = queue.shift() + if (node.left) { + queue.push(node.left) + } + if (node.right) { + queue.push(node.right) + } + if (node.val !== undefined) { + last = node.val + } + } + res.push(last) + } + return res +} diff --git "a/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206 II-107.js" "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206 II-107.js" new file mode 100644 index 0000000..52ff27d --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\346\254\241\351\201\215\345\216\206 II-107.js" @@ -0,0 +1,40 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ + +let TreeNode = require('../工具/二叉树.js') + +/** + * @param {TreeNode} root + * @return {number[][]} + */ +var levelOrderBottom = function (root) { + let res = [] + let dfs = (node, level = 0) => { + if (!node) return + + if (!res[level]) { + res[level] = [] + } + + dfs(node.left, level + 1) + dfs(node.right, level + 1) + + res[level].push(node.val) + } + + dfs(root) + return res.reverse() +}; + +var t = new TreeNode(3) +t.left = new TreeNode(9) +t.right = new TreeNode(20) +t.right.left = new TreeNode(15) +t.right.right = new TreeNode(7) + +console.log(levelOrderBottom(t)) \ No newline at end of file diff --git "a/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204-257.js" "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204-257.js" new file mode 100644 index 0000000..9df9927 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\211\200\346\234\211\350\267\257\345\276\204-257.js" @@ -0,0 +1,18 @@ +let binaryTreePaths = function (root) { + let res = [] + let dfs = (node, path = "") => { + if (!node) { + return + } + + let newPath = path ? `${path}->${node.val}` : `${node.val}` + if (!node.left && !node.right) { + res.push(newPath) + } + + dfs(node.left, newPath) + dfs(node.right, newPath) + } + dfs(root) + return res +} diff --git "a/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246-104.js" "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246-104.js" new file mode 100644 index 0000000..285021b --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246-104.js" @@ -0,0 +1,35 @@ +/* + * @lc app=leetcode id=104 lang=javascript + * + * [104] Maximum Depth of Binary Tree + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +let maxDepth = function (root) { + let max = 0 + let helper = (node, depth) => { + if (!node) return + max = Math.max(max, depth) + if (node.left) { + helper(node.left, depth + 1) + } + if (node.right) { + helper(node.right, depth + 1) + } + } + helper(root, 1) + return max +} +// @lc code=end diff --git "a/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246-111.js" "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246-111.js" new file mode 100644 index 0000000..58ee699 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246-111.js" @@ -0,0 +1,27 @@ +let minDepth = function (root) { + if (!root) return 0 + + let depth = 0 + let queue = [root] + + while (queue.length) { + depth++ + let len = queue.length + while (len--) { + let node = queue.shift() + + let left = node.left + let right = node.right + if (!left && !right) { + return depth + } + + if (left) { + queue.push(left) + } + if (right) { + queue.push(right) + } + } + } +} diff --git "a/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.js" "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.js" new file mode 100644 index 0000000..5067d3c --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.js" @@ -0,0 +1,57 @@ +let T = require("../工具/二叉树") + +let lowestCommonAncestor = function (root, p, q) { + let findAndCreate = (node, target, depth) => { + if (node !== target) { + let findInLeft + if (node.left) { + node.left.parent = node + findInLeft = findAndCreate(node.left, target, depth + 1) + } + + if (findInLeft) { + return findInLeft + } else { + if (node.right) { + node.right.parent = node + return findAndCreate(node.right, target, depth + 1) + } + } + } else { + return { + depth, + node, + } + } + } + + let findP = findAndCreate(root, p, 0) || {} + let findQ = findAndCreate(root, q, 0) || {} + + let cur = findP.depth > findQ.depth ? findQ.node : findP.node + + while (!(isAncestor(cur, p) && isAncestor(cur, q))) { + cur = cur.parent + } + + return cur +} + +function isAncestor(node, target) { + if (!node) { + return false + } + if (node !== target) { + return !!(isAncestor(node.left, target) || isAncestor(node.right, target)) + } else { + return true + } +} + +let l +let r +let t = new T(3) +t.left = l = new T(5) +t.right = r = new T(1) + +console.log(lowestCommonAncestor(t, l, r)) diff --git "a/\344\272\214\345\217\211\346\240\221/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271-450.js" "b/\344\272\214\345\217\211\346\240\221/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271-450.js" new file mode 100644 index 0000000..8f96629 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\345\210\240\351\231\244\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\344\270\255\347\232\204\350\212\202\347\202\271-450.js" @@ -0,0 +1,52 @@ +let deleteNode = function (root, key) { + let findNodePos = (node, key) => { + if (!node) { + return false + } + if (node.left && node.left.val === key) { + return { + parent: node, + pos: "left", + } + } else if (node.right && node.right.val === key) { + return { + parent: node, + pos: "right", + } + } else { + return findNodePos(node.left, key) || findNodePos(node.right, key) + } + } + + let findLastLeft = (node) => { + if (!node.left) { + return node + } + return findLastLeft(node.left) + } + + let virtual = new TreeNode() + virtual.left = root + + let finded = findNodePos(virtual, key) + if (finded) { + let { parent, pos } = finded + let target = parent[pos] + let targetLeft = target.left + let targetRight = target.right + + if (!targetLeft && !targetRight) { + parent[pos] = null + } else if (!targetRight) { + parent[pos] = targetLeft + } else if (!targetLeft) { + parent[pos] = targetRight + } else { + parent[pos] = targetRight + let lastLeft = findLastLeft(targetRight) + lastLeft.left = targetLeft + } + } + + return virtual.left +} \ No newline at end of file diff --git "a/\344\272\214\345\217\211\346\240\221/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221-101.js" "b/\344\272\214\345\217\211\346\240\221/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221-101.js" new file mode 100644 index 0000000..cfef11c --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\345\257\271\347\247\260\344\272\214\345\217\211\346\240\221-101.js" @@ -0,0 +1,28 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {boolean} + */ +var isSymmetric = function (root) { + if (!root) return true + let helper = (left, right) => { + if (!left && !right) { + return true + } + if (!left || !right) { + return false + } + if (left.val === right.val) { + return helper(left.left, right.right) && helper(left.right, right.left) + } else { + return false + } + } + return helper(root, root) +} diff --git "a/\344\272\214\345\217\211\346\240\221/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.js" "b/\344\272\214\345\217\211\346\240\221/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.js" new file mode 100644 index 0000000..8f717c4 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\345\260\206\346\234\211\345\272\217\346\225\260\347\273\204\350\275\254\344\270\272\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.js" @@ -0,0 +1,13 @@ +let sortedArrayToBST = function (nums) { + let n = nums.length + if (!n) { + return null + } + let mid = Math.floor(n / 2) + let root = new TreeNode(nums[mid]) + + root.left = sortedArrayToBST(nums.slice(0, mid)) + root.right = sortedArrayToBST(nums.slice(mid + 1, n)) + + return root +}; \ No newline at end of file diff --git "a/\344\272\214\345\217\211\346\240\221/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214-404.js" "b/\344\272\214\345\217\211\346\240\221/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214-404.js" new file mode 100644 index 0000000..72f1a56 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\345\267\246\345\217\266\345\255\220\344\271\213\345\222\214-404.js" @@ -0,0 +1,22 @@ +let sumOfLeftLeaves = function (root) { + let sum = 0 + + let dfs = (node) => { + if (!node) return + + if (isLeaf(node.left)) { + sum += node.left.val + } + + dfs(node.left) + dfs(node.right) + } + + dfs(root) + + return sum +} + +function isLeaf(node) { + return !!node && !node.left && !node.right +} diff --git "a/\344\272\214\345\217\211\346\240\221/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221-110.js" "b/\344\272\214\345\217\211\346\240\221/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221-110.js" new file mode 100644 index 0000000..9fb5be1 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221-110.js" @@ -0,0 +1,15 @@ +let isBalanced = function (root) { + if (!root) { + return true + } + + let isSonBalnaced = + Math.abs(getHeight(root.left) - getHeight(root.right)) <= 1 + + return isSonBalnaced && isBalanced(root.left) && isBalanced(root.right) +} + +function getHeight(node) { + if (!node) return 0 + return Math.max(getHeight(node.left), getHeight(node.right)) + 1 +} diff --git "a/\344\272\214\345\217\211\346\240\221/\346\261\202\346\240\271\345\210\260\345\217\266\345\255\220\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214-129.js" "b/\344\272\214\345\217\211\346\240\221/\346\261\202\346\240\271\345\210\260\345\217\266\345\255\220\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214-129.js" new file mode 100644 index 0000000..9695144 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\346\261\202\346\240\271\345\210\260\345\217\266\345\255\220\350\212\202\347\202\271\346\225\260\345\255\227\344\271\213\345\222\214-129.js" @@ -0,0 +1,23 @@ +let sumNumbers = function (root) { + let paths = [] + + let dfs = (node, path) => { + if (!node) { + return + } + + let newPath = `${path}${node.val}` + if (!node.left && !node.right) { + paths.push(newPath) + return + } + + dfs(node.left, newPath) + dfs(node.right, newPath) + } + + dfs(root, "") + return paths.reduce((total, val) => { + return total + Number(val) + }, 0) +} diff --git "a/\344\272\214\345\217\211\346\240\221/\350\267\257\345\276\204\346\200\273\345\222\214 II-113.js" "b/\344\272\214\345\217\211\346\240\221/\350\267\257\345\276\204\346\200\273\345\222\214 II-113.js" new file mode 100644 index 0000000..5055984 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\350\267\257\345\276\204\346\200\273\345\222\214 II-113.js" @@ -0,0 +1,45 @@ +let TreeNode = require('../工具/二叉树.js') + +var pathSum = function (root, sum) { + let res = []; + let search = function (node, paths) { + if (!node.val) return + paths.push(node.val); + if (node.left) { + search(node.left, paths); + } + if (node.right) { + search(node.right, paths); + } + if (!node.left && !node.right) { + if (sumVals(paths) === sum) { + res.push(paths.slice()); + } + } + paths.pop(); + }; + search(root, []); + return res; +}; + +function sumVals(nodes) { + return nodes.reduce((prev, val) => { + prev += val; + return prev; + }, 0); +} + + +var t = new TreeNode(5) +t.left = new TreeNode(4) +t.left.left = new TreeNode(11) +t.left.left.left = new TreeNode(7) +t.left.left.right = new TreeNode(2) + +t.right = new TreeNode(8) +t.right.left = new TreeNode(13) +t.right.right = new TreeNode(4) +t.right.right.left = new TreeNode(5) +t.right.right.right = new TreeNode(1) + +console.log(pathSum(new TreeNode(), 22)) diff --git "a/\344\272\214\345\217\211\346\240\221/\350\267\257\345\276\204\346\200\273\345\222\214 III-437.js" "b/\344\272\214\345\217\211\346\240\221/\350\267\257\345\276\204\346\200\273\345\222\214 III-437.js" new file mode 100644 index 0000000..40faec2 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\350\267\257\345\276\204\346\200\273\345\222\214 III-437.js" @@ -0,0 +1,22 @@ +let pathSum = function (root, sum) { + if (!root) return 0 + return ( + countSum(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum) + ) +} + +let countSum = (node, sum) => { + let count = 0 + let dfs = (node, target) => { + if (!node) return + + if (node.val === target) { + count += 1 + } + + dfs(node.left, target - node.val) + dfs(node.right, target - node.val) + } + dfs(node, sum) + return count +} diff --git "a/\344\272\214\345\217\211\346\240\221/\350\267\257\345\276\204\346\200\273\345\222\214-112.js" "b/\344\272\214\345\217\211\346\240\221/\350\267\257\345\276\204\346\200\273\345\222\214-112.js" new file mode 100644 index 0000000..753b265 --- /dev/null +++ "b/\344\272\214\345\217\211\346\240\221/\350\267\257\345\276\204\346\200\273\345\222\214-112.js" @@ -0,0 +1,14 @@ +let hasPathSum = function (root, sum) { + if (!root) { + return false + } + // 叶子节点 判断当前的值是否等于 sum 即可 + if (!root.left && !root.right) { + return root.val === sum + } + + return ( + hasPathSum(root.left, sum - root.val) || + hasPathSum(root.right, sum - root.val) + ) +} diff --git "a/\344\275\215\350\277\220\347\256\227/\346\211\276\344\270\215\345\220\214-389.js" "b/\344\275\215\350\277\220\347\256\227/\346\211\276\344\270\215\345\220\214-389.js" new file mode 100644 index 0000000..f21e453 --- /dev/null +++ "b/\344\275\215\350\277\220\347\256\227/\346\211\276\344\270\215\345\220\214-389.js" @@ -0,0 +1,15 @@ +/** + * @param {string} s + * @param {string} t + * @return {character} + */ +let findTheDifference = function (s, t) { + let rest = t.charCodeAt(t.length - 1) + for (let i = 0; i < s.length; i++) { + let charS = s[i] + let charT = t[i] + rest ^= charS.charCodeAt(0) + rest ^= charT.charCodeAt(0) + } + return String.fromCharCode(rest) +} diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\344\270\200\345\222\214\351\233\266-474.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\344\270\200\345\222\214\351\233\266-474.js" new file mode 100644 index 0000000..69f703a --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\344\270\200\345\222\214\351\233\266-474.js" @@ -0,0 +1,49 @@ +/** + * @param {string[]} strs + * @param {number} m + * @param {number} n + * @return {number} + */ +let findMaxForm = function (strs, m, n) { + let sl = strs.length + if (!sl) { + return 0 + } + + let dp = [] + + for (let i = 0; i <= m; i++) { + dp[i] = [] + for (let j = 0; j <= n; j++) { + dp[i][j] = [] + for (let s = 0; s < sl; s++) { + let str = strs[s] + let [strM, strN] = countMAndN(str) + + let pickOnlyPrev = dp[i][j][s - 1] || 0 + let pickCurAndPrev = 0 + if (i >= strM && j >= strN) { + pickCurAndPrev = 1 + (dp[i - strM][j - strN][s - 1] || 0) + } + + dp[i][j][s] = Math.max(pickCurAndPrev, pickOnlyPrev) + } + } + } + return dp[m][n][sl - 1] +} + +function countMAndN(str) { + let m = 0 + let n = 0 + for (let i = 0; i < str.length; i++) { + if (str[i] === "0") { + m++ + } else { + n++ + } + } + return [m, n] +} + +console.log(findMaxForm(["10", "0", "1"], 1, 1)) diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\344\270\211\350\247\222\345\275\242\347\232\204\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214-120.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\344\270\211\350\247\222\345\275\242\347\232\204\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214-120.js" new file mode 100644 index 0000000..b802d89 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\344\270\211\350\247\222\345\275\242\347\232\204\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214-120.js" @@ -0,0 +1,28 @@ +/** + * @param {number[][]} triangle + * @return {number} + */ +let minimumTotal = function (triangle) { + let tryMin = (level, lastIndex, prevSum) => { + if (level === triangle.length) { + return prevSum + } + + let row = triangle[level] + let cur = row[lastIndex] + let curNext = row[lastIndex + 1] + + let selected = tryMin(level + 1, lastIndex, prevSum + cur) + if (curNext !== undefined) { + selected = Math.min( + selected, + tryMin(level + 1, lastIndex + 1, prevSum + curNext) + ) + } + return selected + } + + return tryMin(0, 0, 0) +} + +minimumTotal([[2], [3, 4], [6, 5, 7], [4, 1, 8, 3]]) diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214-931.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214-931.js" new file mode 100644 index 0000000..30ef633 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\344\270\213\351\231\215\350\267\257\345\276\204\346\234\200\345\260\217\345\222\214-931.js" @@ -0,0 +1,34 @@ +/** + * @param {number[][]} A + * @return {number} + */ +let minFallingPathSum = function (A) { + let n = A.length + + let dp = [] + for (let i = 0; i < n; i++) { + dp[i] = [] + } + + for (let j = 0; j < n; j++) { + dp[n - 1][j] = A[n - 1][j] + } + + for (let i = n - 2; i >= 0; i--) { + for (let j = 0; j < n; j++) { + dp[i][j] = Infinity + let left = j - 1 + let right = j + 1 + let mid = j + let nextRowIndexes = [left, mid, right] + for (let nextRowIndex of nextRowIndexes) { + if (nextRowIndex >= 0 && nextRowIndex < n) { + dp[i][j] = Math.min(dp[i][j], A[i][j] + dp[i + 1][nextRowIndex]) + } + } + } + } + + // 第一行的最小值 可以确定整体的最小路径 + return Math.min(...dp[0]) +} diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\345\215\225\350\257\215\346\213\206\345\210\206 II.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\345\215\225\350\257\215\346\213\206\345\210\206 II.js" new file mode 100644 index 0000000..06c432a --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\345\215\225\350\257\215\346\213\206\345\210\206 II.js" @@ -0,0 +1,37 @@ +let wordBreak = function (s, wordDict) { + let uniqSChars = uniq(s.split("")) + let uniqWordDictChars = uniq(wordDict.join("")) + if (uniqSChars.length !== uniqWordDictChars.length) { + return false + } + + let n = s.length + if (!n) { + return [] + } + + let wordSet = new Set(wordDict) + let dp = [] + dp[0] = [""] + + for (let i = 1; i <= n; i++) { + let res = [] + for (let j = i; j >= 0; j--) { + let word = s.slice(j, i) + if (wordSet.has(word)) { + if (dp[j] && dp[j].length) { + for (let prev of dp[j]) { + res.push(prev ? prev + " " + word : word) + } + } + } + } + dp[i] = res + } + + return dp[n] +} + +function uniq(arr) { + return Array.from(new Set(arr)) +} diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\345\215\225\350\257\215\346\213\206\345\210\206-139.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\345\215\225\350\257\215\346\213\206\345\210\206-139.js" new file mode 100644 index 0000000..dbb4672 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\345\215\225\350\257\215\346\213\206\345\210\206-139.js" @@ -0,0 +1,25 @@ +/** + * @param {string} s + * @param {string[]} wordDict + * @return {boolean} + */ +let wordBreak = function (s, wordDict) { + let n = s.length + if (!n) return true + + let wordSet = new Set(wordDict) + let dp = [] + dp[0] = true + + for (let i = 0; i <= n; i++) { + for (let j = i; j >= 0; j--) { + let word = s.slice(j, i) + if (wordSet.has(word) && dp[j]) { + dp[i] = true + break + } + } + } + + return !!dp[n] +} diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260-1423.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260-1423.js" new file mode 100644 index 0000000..12a63d3 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260-1423.js" @@ -0,0 +1,45 @@ +// 力扣超时 卡在第26个用例 +let maxScore = function (cardPoints, k) { + let n = cardPoints.length + + let prevTimeChunk = [] + for (let i = 0; i < n; i++) { + for (let j = i; j < n; j++) { + if (!prevTimeChunk[i]) { + prevTimeChunk[i] = [] + } + prevTimeChunk[i][j] = 0 + } + } + + let currentTimeChunk = [] + + for (let time = 1; time <= k; time++) { + for (let i = n - 1; i >= 0; i--) { + for (let j = i; j < n; j++) { + if (!currentTimeChunk[i]) { + currentTimeChunk[i] = [] + } + + // 只剩一个可选 有次数的情况下就选这一项 否则为0 + if (i === j) { + currentTimeChunk[i][j] = time > 0 ? cardPoints[i] : 0 + } + + let pickHead = cardPoints[i] + let pickTail = cardPoints[j] + + currentTimeChunk[i][j] = Math.max( + pickHead + (prevTimeChunk[i + 1] ? prevTimeChunk[i + 1][j] || 0 : 0), + pickTail + (prevTimeChunk[i][j - 1] || 0) + ) + } + } + prevTimeChunk = currentTimeChunk + currentTimeChunk = [] + } + + return prevTimeChunk[0][n - 1] +} + +console.log(maxScore([1,79,80,1,1,1,200,1], 3)) diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\201\242\345\244\215\347\251\272\346\240\274-\351\235\242\350\257\225\351\242\230 17.13.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\201\242\345\244\215\347\251\272\346\240\274-\351\235\242\350\257\225\351\242\230 17.13.js" new file mode 100644 index 0000000..676d151 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\201\242\345\244\215\347\251\272\346\240\274-\351\235\242\350\257\225\351\242\230 17.13.js" @@ -0,0 +1,19 @@ +/** + * @param {string[]} dictionary + * @param {string} sentence + * @return {number} + */ +let respace = function (dictionary, sentence) { + let n = sentence.length + let dp = [0] + for (let i = 1; i <= n; i++) { + let min = dp[i - 1] + 1 + for (let word of dictionary) { + if (sentence.substring(i - word.length, i) === word) { + min = Math.min(min, dp[i - word.length]) + } + } + dp[i] = min + } + return dp[n] +} diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\213\254\345\217\267\347\224\237\346\210\220-22.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\213\254\345\217\267\347\224\237\346\210\220-22.js" new file mode 100644 index 0000000..07735c1 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\213\254\345\217\267\347\224\237\346\210\220-22.js" @@ -0,0 +1,23 @@ +let generateParenthesis = function (n) { + let dp = [] + dp[0] = [''] + dp[1] = ['()'] + + for (let i = 2; i <= n; i++) { + let res = [] + for (let j = 0; j <= i - 1; j++) { + let inners = dp[j] + let outers = dp[i - 1 - j] + + for (let inner of inners) { + for (let outer of outers) { + res.push(`(${inner})${outer}`) + } + } + } + dp[i] = res + } + return dp[n] +}; + +console.log(generateParenthesis(4)) \ No newline at end of file diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\227\240\351\207\215\345\217\240\345\214\272\351\227\264-435.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\227\240\351\207\215\345\217\240\345\214\272\351\227\264-435.js" new file mode 100644 index 0000000..c95bbf1 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\227\240\351\207\215\345\217\240\345\214\272\351\227\264-435.js" @@ -0,0 +1,31 @@ +/** + * @param {number[][]} intervals + * @return {number} + */ +let eraseOverlapIntervals = function (intervals) { + let n = intervals.length + if (!n) { + return 0 + } + + // 按照起始点排序 + intervals.sort((a, b) => a[0] - b[0]) + + // dp[i] 表示从 [0, i] 能构成的最长的无重叠区间的个数 + let dp = [] + dp[0] = 1 + + for (let i = 1; i < n; i++) { + let max = 1 + let [curStart] = intervals[i] + for (let j = 0; j < i; j++) { + let [prevStart, prevEnd] = intervals[j] + if (prevEnd <= curStart) { + max = Math.max(max, dp[j] + 1) + } + } + dp[i] = max + } + + return n - Math.max(...dp) +}; \ No newline at end of file diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242-221.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242-221.js" new file mode 100644 index 0000000..26c4815 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242-221.js" @@ -0,0 +1,44 @@ +/** + * @param {character[][]} matrix + * @return {number} + */ +let maximalSquare = function (matrix) { + let maxY = matrix.length + if (!maxY) return 0 + let maxX = matrix[0].length + + let dp = [] + let max = 0 + + let dpBasic = (y, x) => { + if (matrix[y][x] === "1") { + max = 1 + dp[y][x] = 1 + } else { + dp[y][x] = 0 + } + } + for (let y = 0; y < maxY; y++) { + dp[y] = [] + dpBasic(y, 0) + } + for (let x = 1; x < maxX; x++) { + dpBasic(0, x) + } + + for (let y = 1; y < maxY; y++) { + for (let x = 1; x < maxX; x++) { + let val = matrix[y][x] + if (val === "0") { + dp[y][x] = 0 + } else { + let left = dp[y][x - 1] + let top = dp[y - 1][x] + let leftTop = dp[y - 1][x - 1] + dp[y][x] = Math.min(left, top, leftTop) + 1 + max = Math.max(max, dp[y][x]) + } + } + } + return max * max +} diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214-64.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214-64.js" new file mode 100644 index 0000000..8380b9f --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214-64.js" @@ -0,0 +1,43 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +let minPathSum = function (grid) { + let y = grid.length + if (!y) { + return 0 + } + let x = grid[0].length + + let dp = [] + for (let i = 0; i < y; i++) { + dp[i] = [] + } + + dp[0][0] = grid[0][0] + + // 第一行的基础状态 记得加上左边格子的值 + for (let j = 1; j < x; j++) { + dp[0][j] = grid[0][j] + dp[0][j - 1] + } + + // 第一列的基础状态 加上上方格子的最优解即可 + for (let i = 1; i < y; i++) { + dp[i][0] = grid[i][0] + dp[i - 1][0] + } + + // 开始求左上往右下求解 + for (let i = 1; i < grid.length; i++) { + for (let j = 1; j < grid[i].length; j++) { + let cur = grid[i][j] + let fromUp = cur + (dp[i - 1][j] !== undefined ? dp[i - 1][j]: Infinity) + let fromLeft = cur + (dp[i][j - 1] !== undefined ? dp[i][j - 1]: Infinity) + + dp[i][j] = Math.min( + fromUp, + fromLeft + ) + } + } + return dp[y - 1][x - 1] +}; \ No newline at end of file diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227-300.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227-300.js" new file mode 100644 index 0000000..622c453 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\344\270\212\345\215\207\345\255\220\345\272\217\345\210\227-300.js" @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums + * @return {number} + */ +let lengthOfLIS = function (nums) { + let dp = [] + let n = nums.length + if (!n) { + return 0 + } + + dp[0] = 1 + for (let i = 1; i < n; i++) { + let num = nums[i] + let max = 1 + // j 从 [0, i) 依次求出可以和 i 组成的最长上升子序列 + for (let j = 0; j < i; j++) { + let prevNum = nums[j] + if (num > prevNum) { + // 循环中不断更新 max 值 + max = Math.max(max, dp[j] + 1) + } + } + dp[i] = max + } + + return Math.max(...dp) +} diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227-1143.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227-1143.js" new file mode 100644 index 0000000..71c8e51 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\345\205\254\345\205\261\345\255\220\345\272\217\345\210\227-1143.js" @@ -0,0 +1,32 @@ +/** + * @param {string} text1 + * @param {string} text2 + * @return {number} + */ +let longestCommonSubsequence = function (text1, text2) { + let n1 = text1.length + let n2 = text2.length + + let dp = [] + + for (let i1 = 0; i1 <= n1; i1++) { + dp[i1] = [] + dp[i1][0] = 0 + } + dp[0] = Array(n2 + 1).fill(0) + + for (let i1 = 1; i1 <= n1; i1++) { + for (let i2 = 1; i2 <= n2; i2++) { + let str1 = text1[i1 - 1] + let str2 = text2[i2 - 1] + + if (str1 === str2) { + dp[i1][i2] = 1 + dp[i1 - 1][i2 - 1] + }else { + dp[i1][i2] = Math.max(dp[i1 - 1][i2], dp[i1][i2 - 1]) + } + } + } + + return dp[n1][n2] +}; \ No newline at end of file diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\345\215\225\350\257\215-\351\235\242\350\257\225\351\242\230 17.15.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\345\215\225\350\257\215-\351\235\242\350\257\225\351\242\230 17.15.js" new file mode 100644 index 0000000..fe82f42 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\345\215\225\350\257\215-\351\235\242\350\257\225\351\242\230 17.15.js" @@ -0,0 +1,49 @@ +/** + * @param {string} s + * @param {string[]} wordDict + * @return {boolean} + */ +let wordBreak = function (s, wordDict) { + let n = s.length + if (!n) return true + + let wordSet = new Set(wordDict) + let dp = [] + dp[0] = true + + for (let i = 0; i <= n; i++) { + for (let j = i; j >= 0; j--) { + let word = s.slice(j, i) + if (wordSet.has(word) && dp[j]) { + dp[i] = true + break + } + } + } + + return !!dp[n] +} +/** + * @param {string[]} words + * @return {string} + */ +let longestWord = function (words) { + // 先长度降序 后字典序升序 排序 + words.sort((a, b) => { + let diff = b.length - a.length + if (diff !== 0) { + return diff + } else { + return a < b ? -1 : 1 + } + }) + words = Array.from(new Set(words)) + for (let i = 0; i < words.length; i++) { + let word = words[i] + let rest = words.slice(0, i).concat(words.slice(i + 1)) + if (wordBreak(word, rest)) { + return word + } + } + return "" +} \ No newline at end of file diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262-5.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262-5.js" new file mode 100644 index 0000000..9876ba0 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\344\270\262-5.js" @@ -0,0 +1,77 @@ +/** + * 动态规划 + * @param {string} s + * @return {string} + */ +// let longestPalindrome = function (s) { +// let n = s.length +// if (n < 2) { +// return s +// } + +// let dp = [] +// for (let i = 0; i < n; i++) { +// dp[i] = [] +// dp[i][i] = true +// } + +// let max = 0 +// let begin = 0 +// for (let j = 1; j < n; j++) { +// for (let i = 0; i < j; i++) { +// if (s[j] !== s[i]) { +// dp[i][j] = false +// } else { +// let indent = dp[i + 1][j - 1] +// if (indent === undefined || indent === true) { +// dp[i][j] = true +// }else { +// dp[i][j] = false +// } +// } + +// if (dp[i][j] === true && j - i > max) { +// max = j - i +// begin = i +// } +// } +// } +// console.log('dp', dp) +// return s.substr(begin, max + 1) +// } + +/** + * 中心扩散法 + * @param {string} s + * @return {string} + */ +let longestPalindrome = function (s) { + let n = s.length + if (n < 2) { + return s + } + + let begin = 0 + let max = 1 + + let spread = (start, end) => { + while (s[start] === s[end] && start >= 0 && end < n) { + let len = end - start + 1 + if (len > max) { + max = len + begin = start + } + start-- + end++ + } + } + + for (let mid = 0; mid < n; mid++) { + spread(mid, mid) + spread(mid, mid + 1) + } + + return s.substr(begin, max) +} + +console.log(longestPalindrome("babad")) diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\351\207\215\345\244\215\345\255\220\346\225\260\347\273\204-718.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\351\207\215\345\244\215\345\255\220\346\225\260\347\273\204-718.js" new file mode 100644 index 0000000..a4dfc61 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\346\234\200\351\225\277\351\207\215\345\244\215\345\255\220\346\225\260\347\273\204-718.js" @@ -0,0 +1,33 @@ +/** + * @param {number[]} A + * @param {number[]} B + * @return {number} + */ +let findLength = function (A, B) { + let dp = [] + let al = A.length + let bl = B.length + + for (let i = 0; i <= al; i++) { + dp[i] = [] + for (let j = 0; j <= bl; j++) { + dp[i][j] = 0 + } + } + + let max = 0 + for (let i = al - 1; i >= 0; i--) { + for (let j = bl - 1; j >= 0; j--) { + let a = A[i] + let b = B[j] + + if (a === b) { + dp[i][j] = dp[i + 1][j + 1] + 1 + max = Math.max(max, dp[i][j]) + } else { + dp[i][j] = 0 + } + } + } + return max +} diff --git "a/\345\212\250\346\200\201\350\247\204\345\210\222/\347\233\256\346\240\207\345\222\214-494.js" "b/\345\212\250\346\200\201\350\247\204\345\210\222/\347\233\256\346\240\207\345\222\214-494.js" new file mode 100644 index 0000000..d0b0687 --- /dev/null +++ "b/\345\212\250\346\200\201\350\247\204\345\210\222/\347\233\256\346\240\207\345\222\214-494.js" @@ -0,0 +1,39 @@ +/** + * @param {number[]} nums + * @param {number} S + * @return {number} + */ +let findTargetSumWays = function (nums, S) { + let ns = nums.length + if (!ns) { + return 0 + } + let min = nums.reduce((sum, cur) => sum - cur, 0) + let max = nums.reduce((sum, cur) => sum + cur, 0) + + let dp = [] + for (let n = 0; n < ns; n++) { + dp[n] = [] + } + + // 基础状态 + for (let s = min; s <= max; s++) { + let num = nums[0] + let pickPositive = s === num ? 1 : 0 + // 选负数形态 + let pickNegative = -s === num ? 1 : 0 + dp[0][s] = pickPositive + pickNegative + } + + for (let n = 1; n < ns; n++) { + for (let s = min; s <= max; s++) { + let num = nums[n] + // 选正数形态 + let pickPositive = dp[n - 1][s - num] || 0 + // 选负数形态 + let pickNegative = dp[n - 1][s + num] || 0 + dp[n][s] = pickNegative + pickPositive + } + } + return dp[ns - 1][S] || 0 +} diff --git "a/\345\217\214\346\214\207\351\222\210/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271-26.js" "b/\345\217\214\346\214\207\351\222\210/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271-26.js" index bb6ed6f..94e13aa 100644 --- "a/\345\217\214\346\214\207\351\222\210/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271-26.js" +++ "b/\345\217\214\346\214\207\351\222\210/\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271-26.js" @@ -16,7 +16,7 @@ let removeDuplicates = function (nums) { // 把慢指针的位置更新,并且赋值成新的值,继续等待下一个新值。 if (fast !== slot) { j++; - nums[j] = num; + nums[j] = fast; } i++; } diff --git "a/\345\217\214\346\214\207\351\222\210/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204-88.js" "b/\345\217\214\346\214\207\351\222\210/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204-88.js" new file mode 100644 index 0000000..2117c9e --- /dev/null +++ "b/\345\217\214\346\214\207\351\222\210/\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\346\225\260\347\273\204-88.js" @@ -0,0 +1,42 @@ +/* + * @lc app=leetcode.cn id=88 lang=javascript + * + * [88] 合并两个有序数组 + */ + +// @lc code=start +/** + * @param {number[]} nums1 + * @param {number} m + * @param {number[]} nums2 + * @param {number} n + * @return {void} Do not return anything, modify nums1 in-place instead. + */ +let merge = function (arr1, m, arr2, n) { + // 两个指针指向数组非空位置的末尾 + let i = m - 1; + let j = n - 1; + // 第三个指针指向第一个数组的末尾 填充数据 + let k = arr1.length - 1; + + while (i >= 0 && j >= 0) { + let num1 = arr1[i]; + let num2 = arr2[j]; + + if (num1 > num2) { + arr1[k] = num1; + i--; + } else { + arr1[k] = num2; + j--; + } + k--; + } + + while (j >= 0) { + arr1[k] = arr2[j]; + j--; + k--; + } +}; +// @lc code=end diff --git "a/\345\217\214\346\214\207\351\222\210/\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265 II-240.js" "b/\345\217\214\346\214\207\351\222\210/\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265 II-240.js" new file mode 100644 index 0000000..54f7a34 --- /dev/null +++ "b/\345\217\214\346\214\207\351\222\210/\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265 II-240.js" @@ -0,0 +1,24 @@ +/** + * @param {number[][]} matrix + * @param {number} target + * @return {boolean} + */ +let searchMatrix = function (matrix, target) { + let y = matrix.length + if (!y) return false + let x = matrix[0].length + + let row = y - 1 + let column = 0 + while (row >= 0 && column < x) { + let val = matrix[row][column] + if (val > target) { + row-- + } else if (val < target) { + column++ + } else if (val === target) { + return true + } + } + return false +}; \ No newline at end of file diff --git "a/\345\217\214\346\214\207\351\222\210/\346\234\200\346\216\245\350\277\221\347\232\204\344\270\211\346\225\260\344\271\213\345\222\214-16.js" "b/\345\217\214\346\214\207\351\222\210/\346\234\200\346\216\245\350\277\221\347\232\204\344\270\211\346\225\260\344\271\213\345\222\214-16.js" new file mode 100644 index 0000000..70d7631 --- /dev/null +++ "b/\345\217\214\346\214\207\351\222\210/\346\234\200\346\216\245\350\277\221\347\232\204\344\270\211\346\225\260\344\271\213\345\222\214-16.js" @@ -0,0 +1,49 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +let threeSumClosest = function (nums, target) { + let n = nums.length + if (n === 3) { + return getSum(nums) + } + // 先升序排序 此为解题的前置条件 + nums.sort((a, b) => a - b) + + let min = Infinity // 和 target 的最小差 + let res + + // 从左往右依次尝试定一个基础指针 右边至少再保留两位 否则无法凑成3个 + for (let i = 0; i <= nums.length - 3; i++) { + let basic = nums[i] + let left = i + 1 // 左指针先从 i 右侧的第一位开始尝试 + let right = n - 1 // 右指针先从数组最后一项开始尝试 + + while (left < right) { + let sum = basic + nums[left] + nums[right] // 三数求和 + // 更新最小差 + let diff = Math.abs(sum - target) + if (diff < min) { + min = diff + res = sum + } + if (sum < target) { + // 求出的和如果小于目标值的话 可以尝试把左指针右移 扩大值 + left++ + } else if (sum > target) { + // 反之则右指针左移 + right-- + } else { + // 相等的话 差就为0 一定是答案 + return sum + } + } + } + + return res +} + +function getSum(nums) { + return nums.reduce((total, cur) => total + cur, 0) +} diff --git "a/\345\217\214\346\214\207\351\222\210/\351\200\232\350\277\207\345\210\240\351\231\244\345\255\227\346\257\215\345\214\271\351\205\215\345\210\260\345\255\227\345\205\270\351\207\214\346\234\200\351\225\277\345\215\225\350\257\215-524.js" "b/\345\217\214\346\214\207\351\222\210/\351\200\232\350\277\207\345\210\240\351\231\244\345\255\227\346\257\215\345\214\271\351\205\215\345\210\260\345\255\227\345\205\270\351\207\214\346\234\200\351\225\277\345\215\225\350\257\215-524.js" new file mode 100644 index 0000000..1da6eb0 --- /dev/null +++ "b/\345\217\214\346\214\207\351\222\210/\351\200\232\350\277\207\345\210\240\351\231\244\345\255\227\346\257\215\345\214\271\351\205\215\345\210\260\345\255\227\345\205\270\351\207\214\346\234\200\351\225\277\345\215\225\350\257\215-524.js" @@ -0,0 +1,30 @@ +/** + * @param {string} s + * @param {string[]} d + * @return {string} + */ +let findLongestWord = function (s, d) { + let n = d.length + let points = Array(n).fill(-1) + + let find = "" + for (let i = 0; i < s.length; i++) { + let char = s[i] + for (let j = 0; j < n; j++) { + let targetChar = d[j][points[j] + 1] + if (char === targetChar) { + points[j]++ + let word = d[j] + let wl = d[j].length + if (points[j] === wl - 1) { + let fl = find.length + if (wl > fl || (wl === fl && word < find)) { + find = word + } + } + } + } + } + + return find +} \ No newline at end of file diff --git "a/\345\217\257\350\242\253K\346\225\264\351\231\244\347\232\204\345\255\220\346\225\260\347\273\204.js" "b/\345\217\257\350\242\253K\346\225\264\351\231\244\347\232\204\345\255\220\346\225\260\347\273\204.js" new file mode 100644 index 0000000..8349671 --- /dev/null +++ "b/\345\217\257\350\242\253K\346\225\264\351\231\244\347\232\204\345\255\220\346\225\260\347\273\204.js" @@ -0,0 +1,32 @@ +/** + * 暴力解 超时了 + * @param {number[]} A + * @param {number} K + * @return {number} + */ +var subarraysDivByK = function (A, K) { + let prevPrefix = [] + let currentPrefix = [] + let count = 0 + for (let i = A.length - 1; i >= 0; i--) { + let num = A[i] + judge(num) + for (let prev of prevPrefix) { + let sum = prev + num + judge(sum) + } + prevPrefix = currentPrefix + currentPrefix = [] + } + + function judge(num) { + if (num % K === 0 || num === 0) { + count++ + } + currentPrefix.push(num) + } + + return count +} + +console.log(subarraysDivByK([4, 5, 0, -2, -3, 1], 5)) diff --git "a/\345\233\236\346\226\207\345\255\220\344\270\262-647.js" "b/\345\233\236\346\226\207\345\255\220\344\270\262-647.js" new file mode 100644 index 0000000..3a9c237 --- /dev/null +++ "b/\345\233\236\346\226\207\345\255\220\344\270\262-647.js" @@ -0,0 +1,29 @@ +/** + * @param {string} s + * @return {number} + */ +let countSubstrings = function (s) { + let n = s.length + if (n < 2) { + return n + } + + let count = 0 + + let spread = (start, end) => { + while (s[start] === s[end] && start >= 0 && end < n) { + start-- + end++ + count++ + } + } + + for (let mid = 0; mid < n; mid++) { + spread(mid, mid) + spread(mid, mid + 1) + } + + return count +} + +console.log(countSubstrings("a")) diff --git "a/\345\267\245\345\205\267/\344\272\214\345\217\211\346\240\221.js" "b/\345\267\245\345\205\267/\344\272\214\345\217\211\346\240\221.js" index adf1c96..6664215 100644 --- "a/\345\267\245\345\205\267/\344\272\214\345\217\211\346\240\221.js" +++ "b/\345\267\245\345\205\267/\344\272\214\345\217\211\346\240\221.js" @@ -1,9 +1,9 @@ class TreeNode { - constructor(val) { - this.val = val - this.left = null - this.right = null - } + constructor(val) { + this.val = val + this.left = null + this.right = null + } } module.exports = TreeNode \ No newline at end of file diff --git "a/\345\267\245\345\205\267/\344\272\244\346\215\242.js" "b/\345\267\245\345\205\267/\344\272\244\346\215\242.js" new file mode 100644 index 0000000..62e4e9a --- /dev/null +++ "b/\345\267\245\345\205\267/\344\272\244\346\215\242.js" @@ -0,0 +1,7 @@ +function swap(arr, i, j) { + let temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; +}; + +module.exports = swap \ No newline at end of file diff --git "a/\345\267\245\345\205\267/\346\216\222\345\272\217\351\200\237\345\272\246.js" "b/\345\267\245\345\205\267/\346\216\222\345\272\217\351\200\237\345\272\246.js" new file mode 100644 index 0000000..9fc27af --- /dev/null +++ "b/\345\267\245\345\205\267/\346\216\222\345\272\217\351\200\237\345\272\246.js" @@ -0,0 +1,91 @@ +const glob = require("glob") +const path = require("path") +const swap = require("./交换") +const random = require("./随机值") + +function sortTest(sortFns, source, desc) { + console.log(desc) + const table = {} + + if (typeof source === "function") { + source = source() + } + + sortFns.forEach((fn) => { + const copy = source.slice() + const start = new Date().getTime() + + try { + fn(copy) + } catch (e) { + return (table[fn.sortName] = { + 结果: "程序异常", + 原因: e.message, + }) + } + + const end = new Date().getTime() + const time = end - start + const timeStr = `${time}ms` + const success = isSorted(copy, source) + + table[fn.sortName] = { + 耗时: timeStr, + 数据长度: source.length, + 结果: success ? "成功" : "失败", + } + }) + + console.table(table) +} + +function getRandomArray(count) { + const arr = [] + for (let i = 0; i < count; i++) { + arr.push(Math.floor(i * Math.random() * 10)) + } + return arr +} + +function getNearlyArray(count, swapTime) { + const arr = [] + for (let i = 0; i < count; i++) { + arr.push(i) + } + + for (let i = 0; i < swapTime; i++) { + const x = Math.floor(Math.random() * count) + const y = Math.floor(Math.random() * count) + swap(arr, x, y) + } + + return arr +} + +function getRangedArray(count, min, max) { + const arr = [] + for (let i = 0; i < count; i++) { + arr.push(random(min, max)) + } + return arr +} + +function isSorted(target, source) { + return ( + target.toString() === + source + .slice() + .sort((a, b) => a - b) + .toString() + ) +} + +glob("排序/*.js", (err, result) => { + if (err) throw err + const sortFunctions = result + .map((p) => require(path.resolve(p))) + .filter(Boolean) + sortTest(sortFunctions, () => getRandomArray(10000), "普通数组排序") + sortTest(sortFunctions, () => getNearlyArray(10000), "近似数组排序") + sortTest(sortFunctions, () => getRangedArray(500), "大量重复值元素排序") +}) diff --git "a/\345\267\245\345\205\267/\351\223\276\350\241\250.js" "b/\345\267\245\345\205\267/\351\223\276\350\241\250.js" new file mode 100644 index 0000000..7479607 --- /dev/null +++ "b/\345\267\245\345\205\267/\351\223\276\350\241\250.js" @@ -0,0 +1,25 @@ +function ListNode(val) { + this.val = val + this.next = null +} + +/** + * 数组 -> 链表 + * @param {number[]} vals + */ +function makeListNode(vals) { + let head = new ListNode(vals[0]) + let i = 1 + let cur = head + while (i < vals.length) { + let val = vals[i] + cur.next = new ListNode(val) + cur = cur.next + i++ + } + return head +} + +module.exports = ListNode + +module.exports.makeListNode = makeListNode diff --git "a/\345\267\245\345\205\267/\351\232\217\346\234\272\345\200\274.js" "b/\345\267\245\345\205\267/\351\232\217\346\234\272\345\200\274.js" new file mode 100644 index 0000000..afd8643 --- /dev/null +++ "b/\345\267\245\345\205\267/\351\232\217\346\234\272\345\200\274.js" @@ -0,0 +1,5 @@ +function random(low, high) { + return Math.round(Math.random() * (high - low)) + low +} + +module.exports = random diff --git "a/\346\216\222\345\272\217/\345\206\222\346\263\241\346\216\222\345\272\217.js" "b/\346\216\222\345\272\217/\345\206\222\346\263\241\346\216\222\345\272\217.js" new file mode 100644 index 0000000..11e1213 --- /dev/null +++ "b/\346\216\222\345\272\217/\345\206\222\346\263\241\346\216\222\345\272\217.js" @@ -0,0 +1,29 @@ +const swap = require("../工具/交换") +/** + * 冒泡排序 + * @param {number[]} arr + */ +function bubbleSort(arr) { + let n = arr.length + if (n <= 1) return arr + + for (let i = 0; i < n; i++) { + let flag = false + // 从前往后冒泡 所以已经处理过的就不用再访问了 + // 并且由于每次遍历会访问j+1项,等于提前遍历了后一项 + // 所以这里的终止条件可以是n - i再减去1 + for (let j = 0; j < n - 1 - i; j++) { + if (arr[j] > arr[j + 1]) { + swap(arr, j, j + 1) + flag = true + } + } + // 如果这次循环都没有数字被交换 说明已经是排序好的数组 + if (!flag) return arr + } + return arr +} + +bubbleSort.sortName = "冒泡排序" + +// module.exports = bubbleSort diff --git "a/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\217-\344\270\211\350\267\257.js" "b/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\217-\344\270\211\350\267\257.js" new file mode 100644 index 0000000..cab4058 --- /dev/null +++ "b/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\217-\344\270\211\350\267\257.js" @@ -0,0 +1,68 @@ +const swap = require("../工具/交换") +const random = require("../工具/随机值") + +/** + * 三路快速排序 + * 将 arr[l...r] 分为 < v, === v, > v三部分 + * 之后递归的对 < v, > v 两部分三路快排 + * @param {number[]} arr + */ +function quickSort(arr) { + _quickSort(arr, 0, arr.length - 1) + return arr +} + +/** + * 对 arr[l...r] 部分进行快速排序 + * @param {number[]} arr + * @param {number} l 左边界 + * @param {number} r 右边界 + */ +function _quickSort(arr, l, r) { + if (l >= r) { + return + } + let [p, q] = partition(arr, l, r) + _quickSort(arr, l, p) + _quickSort(arr, q, r) +} + +/** + * 对 arr[l...r] 部分进行快速排序 + * @param {number[]} arr + * @param {number} l 左边界 + * @param {number} r 右边界 + * @returns {number} 返回索引值p,使得arr[l...p-1] < arr[p] < arr[p+1...r] + */ +function partition(arr, left, right) { + // 取一个基准值 取随机值 + let rand = random(left, right) + swap(arr, left, rand) + let pivot = arr[left] + + // 三路 注意看注释里的区间 + let lt = left // arr[left + 1...lt] < v + let gt = right + 1 // arr[gt...r] > v + let index = left + 1 // arr[lt + 1...index) === v + + while (index < gt) { + let num = arr[index] + if (num < pivot) { + swap(arr, index, lt + 1) + lt++ + index++ + } else if (num > pivot) { + swap(arr, index, gt - 1) + gt-- + } else if (num === pivot) { + index++ + } + } + swap(arr, left, lt) + + return [lt - 1, gt] +} + +quickSort.sortName = "快速排序(三路)" + +module.exports = quickSort diff --git "a/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\217-\347\251\272\351\227\264.js" "b/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\217-\347\251\272\351\227\264.js" new file mode 100644 index 0000000..6777d4a --- /dev/null +++ "b/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\217-\347\251\272\351\227\264.js" @@ -0,0 +1,24 @@ +function quickSort(arr) { + if (arr.length === 1 || arr.length === 0) { + return arr + } + const left = [] + + const right = [] + const ref = arr[0] + + for (let i = 1; i < arr.length; i++) { + let num = arr[i] + if (num < ref) { + left.push(num) + } else { + right.push(num) + } + } + + return [...quickSort(left), ref, ...quickSort(right)] +} + +quickSort.sortName = "快速排序(空间版)" + +// module.exports = quickSort diff --git "a/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\217.js" "b/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\217.js" new file mode 100644 index 0000000..a6bd467 --- /dev/null +++ "b/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\217.js" @@ -0,0 +1,59 @@ +const swap = require("../工具/交换") +const random = require("../工具/随机值") + +/** + * + * @param {number[]} arr + */ +function quickSort(arr) { + _quickSort(arr, 0, arr.length - 1) + return arr +} + +/** + * 对 arr[l...r] 部分进行快速排序 + * @param {number[]} arr + * @param {number} l 左边界 + * @param {number} r 右边界 + */ +function _quickSort(arr, l, r) { + if (l >= r) { + return + } + let p = partition(arr, l, r) + _quickSort(arr, l, p - 1) + _quickSort(arr, p + 1, r) +} + +/** + * 对 arr[l...r] 部分进行快速排序 + * @param {number[]} arr + * @param {number} l 左边界 + * @param {number} r 右边界 + * @returns {number} 返回索引值p,使得arr[l...p-1] < arr[p] < arr[p+1...r] + */ +function partition(arr, left, right) { + // 取一个基准值 取随机值 + let rand = random(left, right) + swap(arr, left, rand) + let pivot = arr[left] + + // arr[left+1...index] < pivot, arr[index+1...i) > pivot + let index = left + for (let i = left + 1; i <= right; i++) { + let num = arr[i] + if (num < pivot) { + // 如果当前值小于基准值的话,就交换到index + 1的位置去。 + // 扩充了index的范围 [index...], pivot, [...right] + swap(arr, index + 1, i) + index++ + } + } + + swap(arr, left, index) + return index +} + +quickSort.sortName = "快速排序" + +// module.exports = quickSort diff --git "a/\346\216\222\345\272\217/\351\200\211\346\213\251\346\216\222\345\272\217.js" "b/\346\216\222\345\272\217/\351\200\211\346\213\251\346\216\222\345\272\217.js" new file mode 100644 index 0000000..54e1ce7 --- /dev/null +++ "b/\346\216\222\345\272\217/\351\200\211\346\213\251\346\216\222\345\272\217.js" @@ -0,0 +1,18 @@ +const swap = require("../工具/交换") + +function selectSort(arr) { + for (let i = 0; i < arr.length; i++) { + let min = i + for (let j = i + 1; j < arr.length; j++) { + if (arr[j] < arr[min]) { + min = j + } + } + swap(arr, i, min) + } + return arr +} + +selectSort.sortName = "选择排序" + +// module.exports = selectSort diff --git "a/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262\357\274\210\346\273\221\345\212\250\347\252\227\345\217\243\357\274\211.js" "b/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262\357\274\210\346\273\221\345\212\250\347\252\227\345\217\243\357\274\211.js" deleted file mode 100644 index eeb11e8..0000000 --- "a/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262\357\274\210\346\273\221\345\212\250\347\252\227\345\217\243\357\274\211.js" +++ /dev/null @@ -1,72 +0,0 @@ -/** - * 3. 无重复字符的最长子串 - * 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 - - 示例 1: - - 输入: "abcabcbb" - 输出: 3 - 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 - 示例 2: - - 输入: "bbbbb" - 输出: 1 - 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 - 示例 3: - - 输入: "pwwkew" - 输出: 3 - 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 -   请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 - - 来源:力扣(LeetCode) - 链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters - 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 -*/ -let lengthOfLongestSubstring = function(str) { - if (str.length === 1) { - return 1 - } - // 滑动窗口 - let windows = [0, 0] - let max = 0 - - for (let i = 0; i < str.length; i++) { - let char = str[i] - - // 当前窗口中的文字 - let windowsStr = str.substring(windows[0], windows[1]) - - // 窗口中如果已经出现了这个文字 就需要把窗口左侧移动到「上一次出现这个文字」的右边位置 - let windowsCharIdx = windowsStr.indexOf(char) - if (windowsCharIdx !== -1) { - // 注意要加上窗口左侧已经移动的距离 - windows[0] += windowsCharIdx + 1 - } - - // 右边界始终后移 - windows[1]++ - - let windowsLength = windows[1] - windows[0] - if (windowsLength > max) { - max = windowsLength - } - } - - return max -} -console.log(lengthOfLongestSubstring("abcabcbb")) - -/** - * 参考 - * 什么是「滑动窗口算法」(sliding window algorithm),有哪些应用场景? - 程序员吴师兄的回答 - 知乎 - https://www.zhihu.com/question/314669016/answer/663930108 - - 注意边界情况很坑,比如'pwwkew'这种,在i = 2遇到第二个w的时候,窗口中的文字是pw, - - 要把左边界移动到第一个w的右边一位,也就是[2, 2]再继续开始匹配,此时会从第二个w继续向右滑动。 - - 再比如'abcdbacd'这种,在i = 4遇到第二个b的时候,窗口中是[a, b, c, d],此时也不能只单纯向后移动一位,而是需要后移到第一个b的右边 - - 也就是[2, 4]再开始匹配, 也就是从[c, d, b] 再继续往后查找最大的子串。 - */ \ No newline at end of file diff --git "a/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240-378.js" "b/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240-378.js" new file mode 100644 index 0000000..6ce08fc --- /dev/null +++ "b/\346\234\211\345\272\217\347\237\251\351\230\265\344\270\255\347\254\254K\345\260\217\347\232\204\345\205\203\347\264\240-378.js" @@ -0,0 +1,31 @@ +/** + * @param {number[][]} matrix + * @param {number} k + * @return {number} + */ +let kthSmallest = function (matrix, k) { + let maxY = matrix.length + let sorted = [] + let points = [] + for (let i = 0; i < maxY; i++) { + points[i] = 0 + } + + while (sorted.length < k) { + let min = Infinity + let minY + for (let y = 0; y < maxY; y++) { + let point = points[y] + let num = matrix[y][point] + if (num < min) { + min = num + minY = y + } + } + sorted.push(min) + // 选中最小项的x指针右移 + points[minY]++ + } + + return sorted[sorted.length - 1] +}; \ No newline at end of file diff --git "a/\346\240\210\345\222\214\351\230\237\345\210\227/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206-144.js" "b/\346\240\210\345\222\214\351\230\237\345\210\227/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206-144.js" new file mode 100644 index 0000000..ee7bca5 --- /dev/null +++ "b/\346\240\210\345\222\214\351\230\237\345\210\227/\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206-144.js" @@ -0,0 +1,47 @@ +const TreeNode = require("../工具/二叉树") + +/** + * @param {TreeNode} root + * @return {number[]} + */ +let preorderTraversal = function (root) { + let res = [] + let stack = [ + { + type: "go", + node: root, + }, + ] + + while (stack.length) { + let { type, node } = stack.pop() + + if (!node) continue + + if (type === "print") { + res.push(node.val) + } + + if (type === "go") { + stack.push({ type: "print", node }) + + if (node.right) { + stack.push({ type: "go", node: node.right }) + } + + if (node.left) { + stack.push({ type: "go", node: node.left }) + } + } + } + + return res +} + +const tree = new TreeNode(1) +tree.left = new TreeNode(4) +tree.left.left = new TreeNode(5) +tree.right = new TreeNode(6) +tree.right.right = new TreeNode(7) + +console.log(preorderTraversal(tree)) diff --git "a/\346\240\210\345\222\214\351\230\237\345\210\227/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221III-\351\235\242\350\257\225\351\242\23032.js" "b/\346\240\210\345\222\214\351\230\237\345\210\227/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221III-\351\235\242\350\257\225\351\242\23032.js" new file mode 100644 index 0000000..62b4b41 --- /dev/null +++ "b/\346\240\210\345\222\214\351\230\237\345\210\227/\344\273\216\344\270\212\345\210\260\344\270\213\346\211\223\345\215\260\344\272\214\345\217\211\346\240\221III-\351\235\242\350\257\225\351\242\23032.js" @@ -0,0 +1,39 @@ +const TreeNode = require("../工具/二叉树") + +let levelOrder = function (root) { + let queue = [root] + let res = [] + if (!root) return res + let level = 0 + while (queue.length) { + level++ + let subRes = [] + let len = queue.length + let shouldReverse = level % 2 === 0 + + for (let i = 0; i < len; i++) { + let node = queue.shift() + subRes.push(node.val) + if (node.left) { + queue.push(node.left) + } + if (node.right) { + queue.push(node.right) + } + } + // 偶数行 把结果子数组reverse即可 + if (shouldReverse) { + subRes.reverse() + } + res.push(subRes) + } + return res +} + +let tree = new TreeNode(1) +tree.left = new TreeNode(2) +tree.left.left = new TreeNode(4) +tree.right = new TreeNode(3) +tree.right.right = new TreeNode(5) + +console.log(levelOrder(tree)) diff --git "a/\346\240\210\345\222\214\351\230\237\345\210\227/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267-20.js" "b/\346\240\210\345\222\214\351\230\237\345\210\227/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267-20.js" new file mode 100644 index 0000000..b02a587 --- /dev/null +++ "b/\346\240\210\345\222\214\351\230\237\345\210\227/\346\234\211\346\225\210\347\232\204\346\213\254\345\217\267-20.js" @@ -0,0 +1,52 @@ +/** + * @param {string} s + * @return {boolean} + */ +let isValid = function (s) { + let sl = s.length + if (sl % 2 !== 0) return false + let leftToRight = { + "{": "}", + "[": "]", + "(": ")", + } + // 建立一个反向的 value -> key 映射表 + let rightToLeft = createReversedMap(leftToRight) + // 用来匹配左右括号的栈 + let stack = [] + + for (let i = 0; i < s.length; i++) { + let bracket = s[i] + // 左括号 放进栈中 + if (leftToRight[bracket]) { + stack.push(bracket) + } else { + let needLeftBracket = rightToLeft[bracket] + // 左右括号都不是 直接失败 + if (!needLeftBracket) { + return false + } + + // 栈中取出最后一个括号 如果不是需要的那个左括号 就失败 + let lastBracket = stack.pop() + if (needLeftBracket !== lastBracket) { + return false + } + } + } + + if (stack.length) { + return false + } + return true +} + +function createReversedMap(map) { + return Object.keys(map).reduce((prev, key) => { + const value = map[key] + prev[value] = key + return prev + }, {}) +} + +console.log(isValid('({})[()]')) \ No newline at end of file diff --git "a/\346\240\210\345\222\214\351\230\237\345\210\227/\347\256\200\345\214\226\350\267\257\345\276\204-71.js" "b/\346\240\210\345\222\214\351\230\237\345\210\227/\347\256\200\345\214\226\350\267\257\345\276\204-71.js" new file mode 100644 index 0000000..caed5c7 --- /dev/null +++ "b/\346\240\210\345\222\214\351\230\237\345\210\227/\347\256\200\345\214\226\350\267\257\345\276\204-71.js" @@ -0,0 +1,33 @@ +/** + * @param {string} path + * @return {string} + */ +let simplifyPath = function (path) { + let tokens = path.split("/") + let stack = [] + + for (let index = 0; index < tokens.length; index++) { + let token = tokens[index] + if (token === "..") { + if (stack.length > 0) { + stack.pop() + } + } else if (!(token === '') && !(token === '.')) { + stack.push(token) + } + } + + let res = '/' + + for (let token of stack) { + res += `${token}/` + } + + if (res !== '/') { + res = res.substr(0, res.length - 1) + } + + return res +} + +console.log(simplifyPath("/home/")) diff --git "a/\346\240\210\345\222\214\351\230\237\345\210\227/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274-150.js" "b/\346\240\210\345\222\214\351\230\237\345\210\227/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274-150.js" new file mode 100644 index 0000000..5b9fcec --- /dev/null +++ "b/\346\240\210\345\222\214\351\230\237\345\210\227/\351\200\206\346\263\242\345\205\260\350\241\250\350\276\276\345\274\217\346\261\202\345\200\274-150.js" @@ -0,0 +1,28 @@ +/** + * @param {string[]} tokens + * @return {number} + */ +let opMap = { + "+": (a, b) => b + a, + "-": (a, b) => b - a, + "*": (a, b) => b * a, + "/": (a, b) => parseInt(b / a, 10), +} + +let evalRPN = function (tokens) { + let stack = [] + for (let token of tokens) { + let op = opMap[token] + if (op) { + let a = parseInt(stack.pop()) + let b = parseInt(stack.pop()) + let res = op(a, b) + stack.push(res) + } else { + stack.push(token) + } + } + return stack[0] +} + +console.log(evalRPN(["-8","23","8","-","9","23","-","-","*","33","-8","/","+","38","-14","-","-","-7","32","-19","-","11","+","+","+","14","22","-","-","27","-9","-","+","31","+","-12","-11","-","-","14","+","30","+","37","30","-","+","-9","+","7","-","37","+","-5","13","/","-","19","-2","-19","12","+","-","23","+","-","-19","-","+","6","+","-17","+","17","+","5","36","+","-10","+","+","23","-8","-","-","18","-","31","-16","-","+","34","+","-6","+","24","-","22","-","-8","-","28","+","-12","+","39","28","-7","+","+","-14","5","+","5","+","10","+","+","+","-18","*","10","+","-5","11","-","6","+","-","-12","31","+","+","30","29","-","-","39","+","13","-8","-5","+","-","26","19","-","*","-","10","-","-20","5","+","+","0","-","28","-","19","/","28","+","-18","-","28","20","+","-5","-19","+","+","-","-12","-","3","-","6","-15","+","4","-","-","38","+","-9","-","38","-","12","-20","-","10","5","-15","-","-","-","+","-11","+","5","+","2","-","28","+","-9","-11","-","+","37","-","-17","31","-","2","+","+","-16","-12","-","-","12","+","34","-","15","+","8","+","17","-","2","-","33","+","-5","+","14","+","29","-","33","23","+","26","30","-","+","+","39","+","9","24","-","-","20","15","+","-","24","+","37","-","30","-1","-","+","34","+","-13","-","23","15","-","-","-5","-8","8","30","35","-9","22","+","-","-","36","-1","+","5","-","-","+","25","-","+","27","-","16","+","+","+","39","-","15","-","-3","+","5","-6","-","+","-6","-15","-7","-","+","/","13","-","18","+","4","+","29","+","-17","0","-6","-20","-17","+","12","-","+","-","+","+","-10","22","+","+","-11","-","-2","38","-","-","-6","+","0","-","-10","+","-4","-10","+","-","0","-","31","30","-","37","5","+","+","+","-15","+","38","4","-","-16","-17","+","+","+","38","-","27","-19","/","12","+","/"])) diff --git "a/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215-438.js" "b/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215-438.js" new file mode 100644 index 0000000..d1b1485 --- /dev/null +++ "b/\346\273\221\345\212\250\347\252\227\345\217\243/\346\211\276\345\210\260\345\255\227\347\254\246\344\270\262\344\270\255\346\211\200\346\234\211\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215-438.js" @@ -0,0 +1,59 @@ +/** + * @param {string} s + * @param {string} p + * @return {number[]} + */ +let findAnagrams = function (s, p) { + let targetMap = makeCountMap(p) + let sl = s.length + let pl = p.length + // [left,...right] 滑动窗口 + let left = 0 + let right = pl - 1 + let windowMap = makeCountMap(s.substring(left, right + 1)) + let res = [] + + while (left <= sl - pl && right < sl) { + if (isAnagrams(windowMap, targetMap)) { + res.push(left) + } + windowMap[s[left]]-- + right++ + left++ + addCountToMap(windowMap, s[right]) + } + + return res +} + +let isAnagrams = function (windowMap, targetMap) { + let targetKeys = Object.keys(targetMap) + for (let targetKey of targetKeys) { + if ( + !windowMap[targetKey] || + windowMap[targetKey] !== targetMap[targetKey] + ) { + return false + } + } + return true +} + +function addCountToMap(map, str) { + if (!map[str]) { + map[str] = 1 + } else { + map[str]++ + } +} + +function makeCountMap(strs) { + let map = {} + for (let i = 0; i < strs.length; i++) { + let letter = strs[i] + addCountToMap(map, letter) + } + return map +} + +console.log(findAnagrams("abab", "ab")) diff --git "a/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262-3.js" "b/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262-3.js" new file mode 100644 index 0000000..84cbb59 --- /dev/null +++ "b/\346\273\221\345\212\250\347\252\227\345\217\243/\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\347\232\204\346\234\200\351\225\277\345\255\220\344\270\262-3.js" @@ -0,0 +1,28 @@ +/** + * @param {string} s + * @return {number} + */ +let lengthOfLongestSubstring = function (str) { + let n = str.length + // 滑动窗口为s[left...right] + let left = 0 + let right = -1 + let freqMap = {} // 记录当前子串中下标对应的出现频率 + let max = 0 // 找到的满足条件子串的最长长度 + + while (left < n) { + let nextLetter = str[right + 1] + if (!freqMap[nextLetter] && nextLetter !== undefined) { + freqMap[nextLetter] = 1 + right++ + } else { + freqMap[str[left]] = 0 + left++ + } + max = Math.max(max, right - left + 1) + } + + return max +} + +console.log(lengthOfLongestSubstring("pwwkew")) \ No newline at end of file diff --git "a/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.js" "b/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.js" new file mode 100644 index 0000000..e855d8e --- /dev/null +++ "b/\346\273\221\345\212\250\347\252\227\345\217\243/\346\234\200\345\260\217\350\246\206\347\233\226\345\255\220\344\270\262.js" @@ -0,0 +1,65 @@ +/** + * @param {string} s + * @param {string} t + * @return {string} + */ +let minWindow = function (s, t) { + // 先制定目标 根据t字符串统计出每个字符应该出现的个数 + let targetMap = makeCountMap(t) + + let sl = s.length + let tl = t.length + let left = 0 // 左边界 + let right = -1 // 右边界 + let countMap = {} // 当前窗口子串中 每个字符出现的次数 + let min = "" // 当前计算出的最小子串 + + // 循环终止条件是两者有一者超出边界 + while (left <= sl - tl && right <= sl) { + // 和 targetMap 对比出现次数 确定是否满足条件 + let isValid = true + Object.keys(targetMap).forEach((key) => { + let targetCount = targetMap[key] + let count = countMap[key] + if (!count || count < targetCount) { + isValid = false + } + }) + + if (isValid) { + // 如果满足 记录当前的子串 并且左边界右移 + let currentValidLength = right - left + 1 + if (currentValidLength < min.length || min === "") { + min = s.substring(left, right + 1) + } + // 也要把map里对应的项去掉 + countMap[s[left]]-- + left++ + } else { + // 否则右边界右移 + addCountToMap(countMap, s[right + 1]) + right++ + } + } + + return min +} + +function addCountToMap(map, str) { + if (!map[str]) { + map[str] = 1 + } else { + map[str]++ + } +} + +function makeCountMap(strs) { + let map = {} + for (let i = 0; i < strs.length; i++) { + let letter = strs[i] + addCountToMap(map, letter) + } + return map +} + +console.log(minWindow("aa", "a")) diff --git "a/\346\273\221\345\212\250\347\252\227\345\217\243/\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274-\351\235\242\350\257\225\351\242\23059 - I.js" "b/\346\273\221\345\212\250\347\252\227\345\217\243/\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274-\351\235\242\350\257\225\351\242\23059 - I.js" new file mode 100644 index 0000000..f2c51cf --- /dev/null +++ "b/\346\273\221\345\212\250\347\252\227\345\217\243/\346\273\221\345\212\250\347\252\227\345\217\243\347\232\204\346\234\200\345\244\247\345\200\274-\351\235\242\350\257\225\351\242\23059 - I.js" @@ -0,0 +1,24 @@ +let maxSlidingWindow = function (nums, k) { + if (k === 0 || !nums.length) { + return [] + } + let left = 0 + let right = k - 1 + let res = [findMax(nums, left, right)] + + while (right < nums.length - 1) { + right++ + left++ + res.push(findMax(nums, left, right)) + } + + return res +} + +function findMax(nums, left, right) { + let max = -Infinity + for (let i = left; i <= right; i++) { + max = Math.max(max, nums[i]) + } + return max +} \ No newline at end of file diff --git "a/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204-209.js" "b/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204-209.js" new file mode 100644 index 0000000..bd05c78 --- /dev/null +++ "b/\346\273\221\345\212\250\347\252\227\345\217\243/\351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204-209.js" @@ -0,0 +1,30 @@ +/** + * @param {number} s + * @param {number[]} nums + * @return {number} + */ +let minSubArrayLen = function (s, nums) { + let n = nums.length + // 定义[i,...j]滑动窗口 取这个窗口里的和 + let i = 0 + let j = -1 + + let sum = 0 + let res = Infinity + + while (i < n) { + if (sum < s) { + sum += nums[++j] + } else { + sum -= nums[i] + i++ + } + + if (sum >= s) { + res = Math.min(res, j - i + 1) + } + } + return res === Infinity ? 0 : res +} + +console.log(minSubArrayLen(7, [2, 3, 1, 2, 4, 3])) diff --git "a/\350\264\252\345\277\203\347\256\227\346\263\225/\345\210\206\345\217\221\351\245\274\345\271\262-455.js" "b/\350\264\252\345\277\203\347\256\227\346\263\225/\345\210\206\345\217\221\351\245\274\345\271\262-455.js" new file mode 100644 index 0000000..8af19cb --- /dev/null +++ "b/\350\264\252\345\277\203\347\256\227\346\263\225/\345\210\206\345\217\221\351\245\274\345\271\262-455.js" @@ -0,0 +1,28 @@ +/** + * @param {number[]} g + * @param {number[]} s + * @return {number} + */ +let findContentChildren = function (g, s) { + g.sort((a, b) => a - b) + s.sort((a, b) => a - b) + + let i = 0 + let j = 0 + + let count = 0 + while (j < s.length && i < g.length) { + let need = g[i] + let cookie = s[j] + + if (cookie >= need) { + count++ + i++ + j++ + } else { + j++ + } + } + + return count +} diff --git "a/\350\264\252\345\277\203\347\256\227\346\263\225/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227-392.js" "b/\350\264\252\345\277\203\347\256\227\346\263\225/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227-392.js" new file mode 100644 index 0000000..bf9f8f1 --- /dev/null +++ "b/\350\264\252\345\277\203\347\256\227\346\263\225/\345\210\244\346\226\255\345\255\220\345\272\217\345\210\227-392.js" @@ -0,0 +1,50 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +let isSubsequence = function (s, t) { + let i = 0 + let sl = s.length + if (!sl) { + return true + } + + for (let j = 0; j < t.length; j++) { + let target = s[i] + let cur = t[j] + if (cur === target) { + i++ + if (i === sl) { + return true + } + } + } + + return false +} +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +let isSubsequence = function (s, t) { + let sl = s.length + if (!sl) { + return true + } + + let i = 0 + for (let j = 0; j < t.length; j++) { + let target = s[i] + let cur = t[j] + if (cur === target) { + i++ + if (i === sl) { + return true + } + } + } + + return false +} diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/N \347\232\207\345\220\216-51.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/N \347\232\207\345\220\216-51.js" new file mode 100644 index 0000000..f3d623b --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/N \347\232\207\345\220\216-51.js" @@ -0,0 +1,70 @@ +/** + * @param {number} n + * @return {string[][]} + */ +let solveNQueens = function (n) { + let res = [] + + // 已摆放皇后的的列下标 + let columns = [] + // 已摆放皇后的对角线1下标 左下 -> 右上 + // 计算某个坐标是否在这个对角线的方式是「行下标 + 列下标」是否相等 + let dia1 = [] + // 已摆放皇后的对角线2下标 左上 -> 右下 + // 计算某个坐标是否在这个对角线的方式是「行下标 - 列下标」是否相等 + let dia2 = [] + + // 尝试在一个n皇后问题中 摆放第index行内的皇后位置 + let putQueen = (rowIndex, row) => { + if (rowIndex === n) { + res.push(generateBoard(row)) + return + } + + // 尝试摆第index行的皇后 尝试[0, n-1]列 + for (let columnIndex = 0; columnIndex < n; columnIndex++) { + // 在列上不冲突 + let columnNotConflict = !columns[columnIndex] + // 在对角线1上不冲突 + let dia1NotConflict = !dia1[rowIndex + columnIndex] + // 在对角线2上不冲突 + let dia2NotConflict = !dia2[rowIndex - columnIndex] + + if (columnNotConflict && dia1NotConflict && dia2NotConflict) { + + columns[columnIndex] = true + dia1[rowIndex + columnIndex] = true + dia2[rowIndex - columnIndex] = true + + putQueen(rowIndex + 1, row.concat(columnIndex)) + + columns[columnIndex] = false + dia1[rowIndex + columnIndex] = false + dia2[rowIndex - columnIndex] = false + } + } + } + + putQueen(0, []) + + return res +} + +function generateBoard(row) { + let n = row.length + let res = [] + for(let y = 0; y < n; y++) { + let cur = '' + for (let x = 0; x < n; x++) { + if (x === row[y]) { + cur += 'Q' + }else { + cur += '.' + } + } + res.push(cur) + } + return res +} + +console.log(solveNQueens(4)) diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\344\270\215\345\220\214\350\267\257\345\276\204 III-980.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\344\270\215\345\220\214\350\267\257\345\276\204 III-980.js" new file mode 100644 index 0000000..1213047 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\344\270\215\345\220\214\350\267\257\345\276\204 III-980.js" @@ -0,0 +1,72 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +let uniquePathsIII = function (grid) { + let maxY = grid.length + if (!maxY) return 0 + let maxX = grid[0].length + + let validCellsCount = 0 + let entry + let visited = [] + for (let y = 0; y < maxY; y++) { + visited[y] = [] + for (let x = 0; x < maxX; x++) { + let val = grid[y][x] + if (val === 0) { + validCellsCount++ + } + if (val === 1) { + entry = [y, x] + } + } + } + + let isValid = (y, x) => { + return ( + y >= 0 && + y < maxY && + x >= 0 && + x < maxX && + !visited[y][x] && + grid[y][x] !== -1 + ) + } + + let dirs = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ] + let res = 0 + + let dfs = (y, x, passCount) => { + let val = grid[y][x] + if (val === 2) { + if (passCount === validCellsCount) { + res++ + } + return + } else if (val === 0) { + passCount += 1 + } + + for (let [diffY, diffX] of dirs) { + let nextY = y + diffY + let nextX = x + diffX + if (isValid(nextY, nextX)) { + visited[nextY][nextX] = true + dfs(nextY, nextX, passCount) + visited[nextY][nextX] = false + } + } + } + + let [entryY, entryX] = entry + visited[entryY][entryX] = true + dfs(entryY, entryX, 0) + + return res +} diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250-401.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250-401.js" new file mode 100644 index 0000000..0a9ce85 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\344\272\214\350\277\233\345\210\266\346\211\213\350\241\250-401.js" @@ -0,0 +1,54 @@ +/** + * @param {number} num + * @return {string[]} + */ +let HOURS = [1, 2, 4, 8] +let MINUTES = [1, 2, 4, 8, 16, 32] + +let readBinaryWatch = function (num) { + let res = [] + + let combine = (arr, num) => { + if (num === 0) { + return [0] + } + let res = [] + let helper = (start, prevCount, prevSum) => { + if (prevCount === num) { + res.push(prevSum) + return + } + + for (let i = start; i < arr.length; i++) { + let cur = arr[i] + helper(i + 1, prevCount + 1, prevSum + cur) + } + } + helper(0, 0, 0) + return res + } + + for (let i = 0; i <= num; i++) { + let hours = combine(HOURS, i) + let minutes = combine(MINUTES, num - i) + + for (let hour of hours) { + if (hour > 11) continue + for (let minute of minutes) { + if (minute > 59) { + continue + } + res.push(`${hour}:${padLeft(minute)}`) + } + } + } + return res +} + +function padLeft(num) { + let str = num.toString() + if (str.length === 1) { + str = `0${str}` + } + return str +} \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\205\250\346\216\222\345\210\227 II-47.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\205\250\346\216\222\345\210\227 II-47.js" new file mode 100644 index 0000000..96278c2 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\205\250\346\216\222\345\210\227 II-47.js" @@ -0,0 +1,39 @@ + +let uniqSymbol = 'X' + +let permuteUnique = function (nums) { + let n = nums.length + if (n === 1) { + return [nums] + } + let permuteSet = (nums) => { + let n = nums.length + if (n === 0) { + return new Set() + } + if (n === 1) { + return new Set(nums) + } + + let res = new Set() + for (let i = 0; i < n; i++) { + let use = nums[i] + if (use === undefined) { + continue + } + let rest = nums.slice(0, i).concat(nums.slice(i + 1, n)) + let restPermuteds = permuteSet(rest) + restPermuteds.forEach((restPermuted) => { + res.add(`${use}${uniqSymbol}${restPermuted}`) + }) + } + + return res + } + + let permuted = permuteSet(nums) + + return Array.from(permuted).map((val) => val.split(uniqSymbol).map(Number)) +} + +console.log(permuteUnique([-1,2,-1,2,1,-1,2,1])) diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\205\250\346\216\222\345\210\227-46.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\205\250\346\216\222\345\210\227-46.js" new file mode 100644 index 0000000..59bc751 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\205\250\346\216\222\345\210\227-46.js" @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @return {number[][]} + */ +let permute = function (nums) { + let n = nums.length + if (n === 1) { + return [nums] + } + + let res = [] + for (let i = 0; i < n; i++) { + let use = nums[i] + let rest = nums.slice(0, i).concat(nums.slice(i + 1, n)) + let restPermuteds = permute(rest) + for (let restPermuted of restPermuteds) { + res.push(restPermuted.concat(use)) + } + } + + return res +} + +console.log(permute([1, 2, 3])) diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262-131.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262-131.js" new file mode 100644 index 0000000..c973e26 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\210\206\345\211\262\345\233\236\346\226\207\344\270\262-131.js" @@ -0,0 +1,51 @@ +/** + * @param {string} s + * @return {string[][]} + */ + +let partition = function (s) { + let n = s.length + let ret = [] + let find = function (start, prev) { + // 最少分割一个字符 最多分割到末尾前一位 + for (let i = 1; i <= n; i++) { + let end = start + i + let cur = s.substring(start, end) + if (cur) { + let res = prev.concat(cur) + if (isPalindrome(cur)) { + if (end === n) { + ret.push(res) + } else { + find(start + i, res) + } + } + } + } + } + find(0, []) + return ret +} + +function isPalindrome(s) { + if (!s) { + return false + } + let i = 0 + let j = s.length - 1 + + while (i < j) { + let head = s[i] + let tail = s[j] + + if (head !== tail) { + return false + } else { + i++ + j-- + } + } + return true +} + +console.log(partition("aab")) diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\215\225\350\257\215\346\220\234\347\264\242 II-212.Trie\347\211\210\346\234\254.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\215\225\350\257\215\346\220\234\347\264\242 II-212.Trie\347\211\210\346\234\254.js" new file mode 100644 index 0000000..9032686 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\215\225\350\257\215\346\220\234\347\264\242 II-212.Trie\347\211\210\346\234\254.js" @@ -0,0 +1,112 @@ +/** + * Initialize your data structure here. + */ +var Trie = function () { + this.root = new TrieNode() +} + +var TrieNode = function () { + this.children = new Map() + this.isEnd = false +} + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function (word) { + let node = this.root + + for (let i = 0; i < word.length; i++) { + let { children } = node + let trieNode = children.get(word[i]) + if (!trieNode) { + trieNode = new TrieNode() + children.set(word[i], trieNode) + } + node = trieNode + + if (i === word.length - 1) { + node.isEnd = true + node.word = word + } + } +} + +let dirs = [ + [0, 1], + [0, -1], + [-1, 0], + [1, 0], +] +/** + * @param {character[][]} board + * @param {string[]} words + * @return {string[]} + */ +let findWords = function (board, words) { + let maxY = board.length + if (!maxY) return [] + let maxX = board[0].length + + let rootTrie = new Trie() + for (let word of words) { + rootTrie.insert(word) + } + + // 记录已访问过的二维下标 + let visited = [] + for (let y = 0; y < maxY; y++) { + visited[y] = [] + } + + let isValid = (x, y) => { + return x >= 0 && x < maxX && y >= 0 && y < maxY && !visited[y][x] + } + + // 返回结果 + let res = [] + + let dfs = (x, y, trie) => { + let char = board[y][x] + let children = trie.children + let nextTrie = children && children.get(char) + if (nextTrie) { + if (nextTrie.word) { + res.push(nextTrie.word) + nextTrie.word = null + } else { + visited[y][x] = true + for (let dir of dirs) { + let [offsetY, offsetX] = dir + let nextY = y + offsetY + let nextX = x + offsetX + if (isValid(nextX, nextY)) { + dfs(nextX, nextY, nextTrie) + } + } + visited[y][x] = false + } + } + } + + for (let y = 0; y < maxY; y++) { + for (let x = 0; x < maxX; x++) { + if (y === 1 && x === 0) debugger + dfs(x, y, rootTrie.root) + } + } + + return Array.from(new Set(res)) +} + +console.log( + findWords( + [ + ["a", "b"], + ["a", "a"], + ], + ["aaba"] + ) +) diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\215\225\350\257\215\346\220\234\347\264\242 II-212.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\215\225\350\257\215\346\220\234\347\264\242 II-212.js" new file mode 100644 index 0000000..66d2f3d --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\215\225\350\257\215\346\220\234\347\264\242 II-212.js" @@ -0,0 +1,87 @@ +let dirs = [ + [0, 1], + [0, -1], + [-1, 0], + [1, 0], +] +/** + * @param {character[][]} board + * @param {string[]} words + * @return {string[]} + */ +let findWords = function (board, words) { + let maxY = board.length + if (!maxY) return [] + let maxX = board[0].length + + // 记录已访问过的二维下标 + let visited = [] + for (let y = 0; y < maxY; y++) { + visited[y] = [] + } + + let isValid = (x, y) => { + return x >= 0 && x < maxX && y >= 0 && y < maxY && !visited[y][x] + } + + // 返回结果 + let res = [] + + let dfs = (x, y, word, index) => { + let char = board[y][x] + let targetChar = word[index] + if (char === targetChar) { + if (index === word.length - 1) { + res.push(word) + } else { + visited[y][x] = true + for (let dir of dirs) { + let [offsetY, offsetX] = dir + let nextY = y + offsetY + let nextX = x + offsetX + if (isValid(nextX, nextY)) { + dfs(nextX, nextY, word, index + 1) + } + } + visited[y][x] = false + } + } + } + + let prefixMap = new Map() + for (let y = 0; y < maxY; y++) { + for (let x = 0; x < maxX; x++) { + let prefix = board[y][x] + let pos = prefixMap.get(prefix) + if (!pos) { + prefixMap.set(prefix, [[y, x]]) + } else { + prefixMap.set(prefix, [...pos, [y, x]]) + } + } + } + + let find = (word) => { + let head = word[0] + let pos = prefixMap.get(head) + if (pos) { + pos.forEach(([y, x]) => { + dfs(x, y, word, 0) + }) + } + } + + words.forEach(find) + + return Array.from(new Set(res)) +} + +console.log( + findWords( + [ + ["a", "b"], + ["a", "a"], + ], + ["aba", "baa", "bab", "aaab", "aaa", "aaaa", "aaba"] + ) +) diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\215\225\350\257\215\346\220\234\347\264\242-79.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\215\225\350\257\215\346\220\234\347\264\242-79.js" new file mode 100644 index 0000000..c9306df --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\215\225\350\257\215\346\220\234\347\264\242-79.js" @@ -0,0 +1,64 @@ +/** + * @param {character[][]} board + * @param {string} word + * @return {boolean} + */ +let directions = [[-1, 0], [1, 0], [0, -1], [0, 1]] // 左 右 上 下 + +let exist = function (board, word) { + let maxY = board.length + if (!maxY) return false + let maxX = board[0].length + + // 二维数组记录已访问过的元素 + let visited = new Array(maxY) + for (let y = 0; y < visited.length; y++) { + visited[y] = new Array(maxX) + } + + let inArea = (x, y) => { + return x >= 0 && x < maxX && y >= 0 && y < maxY + } + + let search = (startX, startY, wordIndex) => { + // 当前起始字符不匹配 直接失败 + let curCell = board[startY][startX] + let curChar = word[wordIndex] + if (curCell !== curChar) { + return false + } + + // 如果递归到最后一位字符 就直接返回最后一位字符是否匹配成功 + if (wordIndex === word.length - 1) { + return curChar === curChar + } + + // 进一步递归 先记录为已访问元素 防止递归的时候重复访问 + visited[startY][startX] = true + + for (let direction of directions) { + let [x, y] = direction + let nextX = startX + x + let nextY = startY + y + + // 需要保证未越界且未被访问过 + if (inArea(nextX, nextY) && !visited[nextY][nextX]) { + if (search(nextX, nextY, wordIndex + 1)) { + return true + } + } + } + // 重置已访问标记位 + visited[startY][startX] = false + } + + for (let y = 0; y < maxY; y++) { + for (let x = 0; x < maxX; x++) { + if (search(x, y, 0)) { + return true + } + } + } + + return false +}; \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204-560.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204-560.js" new file mode 100644 index 0000000..25582b5 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\222\214\344\270\272K\347\232\204\345\255\220\346\225\260\347\273\204-560.js" @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +let subarraySum = function (nums, k) { + let n = nums.length + if (!n) { + return 0 + } + + let res = 0 + for (let i = 0; i < n; i++) { + let total = 0 + for (let j = i; j < n; j++) { + total += nums[j] + if (total === k) { + res += 1 + } + } + } + return res +}; \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\244\215\345\216\237ip\345\234\260\345\235\200-93.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\244\215\345\216\237ip\345\234\260\345\235\200-93.js" new file mode 100644 index 0000000..c1ffaa6 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\244\215\345\216\237ip\345\234\260\345\235\200-93.js" @@ -0,0 +1,43 @@ +/** + * @param {string} s + * @return {string[]} + */ +let restoreIpAddresses = function (s) { + let res = [] + let findPos = (start, prev, used) => { + if (used === 3) { + let rest = s.substr(start) + // 点全部用光后 剩余字符依然是一个合格的ip chunk + // 就视为一个答案 放入数组 + if (isValidChunk(rest)) { + res.push(prev.concat(rest).join(".")) + } + return + } + + for (let i = 1; i <= 3; i++) { + let end = start + i + let cur = s.substring(start, end) + if (isValidChunk(cur)) { + findPos(end, prev.concat(cur), used + 1) + } + } + } + + findPos(0, [], 0) + + return res +} + +function isValidChunk(str) { + let strLen = str.length + if (strLen === 0) { + return false + } + // 开头是0的话 只能整个字符串只有一位0才行 + if (str[0] === "0") { + return strLen === 1 + } + let num = Number(str) + return num <= 255 +} diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\220\351\233\206 II-90.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\220\351\233\206 II-90.js" new file mode 100644 index 0000000..d5eb09e --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\220\351\233\206 II-90.js" @@ -0,0 +1,45 @@ +/** + * @param {number[]} nums + * @return {number[][]} + */ +var subsetsWithDup = function (nums) { + let n = nums.length + let res = [] + if (!n) { + return res + } + + nums.sort() + + let used = {} + + let helper = (start, prev, target) => { + if (prev.length === target) { + let key = genKey(prev) + if (!used[key]) { + res.push(prev) + used[key] = true + } + return + } + + for (let i = start; i < n; i++) { + let rest = n - i + let need = target - prev.length + if (rest < need) { + continue + } + helper(i + 1, prev.concat(nums[i]), target) + } + } + + for (let i = 1; i <= n; i++) { + helper(0, [], i) + } + + return [[], ...res] +}; + +function genKey(arr) { + return arr.join('~') +} \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\220\351\233\206-78.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\220\351\233\206-78.js" new file mode 100644 index 0000000..ca951d4 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\220\351\233\206-78.js" @@ -0,0 +1,32 @@ +/** + * @param {number[]} nums + * @return {number[][]} + */ +let subsets = function (nums) { + let res = [] + let n = nums.length + if (n === 0) { + return res + } + + let helper = (start, prev, targetLength) => { + if (start > n) { + return + } + if (prev.length === targetLength) { + res.push(prev) + return + } + + for (let i = start; i < n; i++) { + let cur = nums[i] + helper(i + 1, prev.concat(cur), targetLength) + } + } + + for (let j = 1; j <= nums.length; j++) { + helper(0, [], j) + } + + return [[], ...res] +} diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\227\346\257\215\345\244\247\345\260\217\345\206\231\345\205\250\346\216\222\345\210\227-784.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\227\346\257\215\345\244\247\345\260\217\345\206\231\345\205\250\346\216\222\345\210\227-784.js" new file mode 100644 index 0000000..91ba7b7 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\227\346\257\215\345\244\247\345\260\217\345\206\231\345\205\250\346\216\222\345\210\227-784.js" @@ -0,0 +1,34 @@ +/** + * @param {string} S + * @return {string[]} + */ +let letterCasePermutation = function (S) { + let res = [] + + let helper = (prev, rest) => { + if (prev.length === S.length) { + res.push(prev) + return + } + + let char = rest[0] + let word1 = prev + char + let nextRest = rest.substring(1) + + if (!isNaN(Number(char))) { + helper(word1, nextRest) + return + } else { + let upperChar = char.toUpperCase() + let char2 = upperChar === char ? char.toLowerCase() : upperChar + let word2 = prev + char2 + + helper(word1, nextRest) + helper(word2, nextRest) + } + } + + helper('', S) + + return res +}; \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\227\346\257\215\350\277\255\344\273\243\347\273\204\345\220\210\345\231\250-1286.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\227\346\257\215\350\277\255\344\273\243\347\273\204\345\220\210\345\231\250-1286.js" new file mode 100644 index 0000000..709bae1 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\345\255\227\346\257\215\350\277\255\344\273\243\347\273\204\345\220\210\345\231\250-1286.js" @@ -0,0 +1,52 @@ +/** + * @param {string} characters + * @param {number} combinationLength + */ +let CombinationIterator = function (characters, combinationLength) { + let cl = characters.length + let res = [] + let helper = (start, prev) => { + let pl = prev.length + for (let i = start; i < cl; i++) { + let rest = cl - i + let diff = combinationLength - pl + if (diff > rest) { + return + } + let next = prev + characters[i] + if (next.length == combinationLength) { + res.push(next) + } else { + helper(i + 1, next) + } + } + } + helper(0, "") + this.res = res.sort((a, b) => (a > b ? 1 : -1)) + this.point = 0 +} + +/** + * @return {string} + */ +CombinationIterator.prototype.next = function () { + if (!this.hasNext()) { + return undefined + } + let val = this.res[this.point++] + return val +} + +/** + * @return {boolean} + */ +CombinationIterator.prototype.hasNext = function () { + return this.point !== this.res.length +} + +/** + * Your CombinationIterator object will be instantiated and called as such: + * var obj = new CombinationIterator(characters, combinationLength) + * var param_1 = obj.next() + * var param_2 = obj.hasNext() + */ diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\346\213\254\345\217\267-\351\235\242\350\257\225\351\242\230 08.09.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\346\213\254\345\217\267-\351\235\242\350\257\225\351\242\230 08.09.js" new file mode 100644 index 0000000..604f5c4 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\346\213\254\345\217\267-\351\235\242\350\257\225\351\242\230 08.09.js" @@ -0,0 +1,23 @@ +/** + * @param {number} n + * @return {string[]} + */ +let generateParenthesis = function (n) { + let res = [] + + let helper = (left, right, prev) => { + if (left < 0 || right < 0 || right < left) { + return + } + if (left === 0 && right === 0) { + res.push(prev) + return + } + + helper(left - 1, right, prev + "(") + helper(left, right - 1, prev + ")") + } + + helper(n, n, '') + return res +}; \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\346\264\273\345\255\227\345\215\260\345\210\267-1079.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\346\264\273\345\255\227\345\215\260\345\210\267-1079.js" new file mode 100644 index 0000000..40ff332 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\346\264\273\345\255\227\345\215\260\345\210\267-1079.js" @@ -0,0 +1,23 @@ +/** + * @param {string} tiles + * @return {number} + */ +let numTilePossibilities = function (tiles) { + let res = new Set() + + let helper = (prev, rest) => { + if (prev.length > 0) { + res.add(prev) + } + + for (let i = 0; i < rest.length; i++) { + let char = rest[i] + let cur = prev + char + helper(cur, rest.substring(0, i) + rest.substring(i + 1)) + } + } + + helper('', tiles) + + return res.size +}; \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210-17.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210-17.js" new file mode 100644 index 0000000..57bda1a --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\224\265\350\257\235\345\217\267\347\240\201\347\232\204\345\255\227\346\257\215\347\273\204\345\220\210-17.js" @@ -0,0 +1,48 @@ +/** + * @param {string} digits + * @return {string[]} + */ +let letterMap = [ + " ", //0 + "", //1 + "abc", //2 + "def", //3 + "ghi", //4 + "jkl", //5 + "mno", //6 + "pqrs", //7 + "tuv", //8 + "wxyz", //9 +] + +let letterCombinations = function (digits) { + let res = [] + + if (digits === "") { + return res + } + + /** + * + * @param {number} index 当前处理到的下标位置 + * @param {string} str 当前已经凑成的字符串 + */ + let findCombinations = (index, str) => { + if (digits.length === index) { + res.push(str) + return + } + + let char = digits[index] // 数字 + let letters = letterMap[Number(char)] // 数字对应的字母 + + for (let i = 0; i < letters.length; i++) { + let letter = letters[i] + findCombinations(index + 1, `${str}${letter}`) + } + } + + findCombinations(0, "") + + return res +} diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\237\251\351\230\265\347\275\256\351\233\266-73.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\237\251\351\230\265\347\275\256\351\233\266-73.js" new file mode 100644 index 0000000..fff9854 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\237\251\351\230\265\347\275\256\351\233\266-73.js" @@ -0,0 +1,37 @@ +/** + * @param {number[][]} matrix + * @return {void} Do not return anything, modify matrix in-place instead. + */ +let setZeroes = function (matrix) { + let maxY = matrix.length + if (!maxY) return + let maxX = matrix[0].length + + let handledRows = [] + let handledColumns = [] + + let zeros = [] + for (let y = 0; y < maxY; y++) { + for (let x = 0; x < maxX; x++) { + let val = matrix[y][x] + if (val === 0) { + zeros.push([y, x]) + } + } + } + + for (let [y, x] of zeros) { + if (!handledRows[x]) { + for (let i = 0; i < maxY; i++) { + matrix[i][x] = 0 + } + handledRows[x] = true + } + if (!handledColumns[y]) { + for (let i = 0; i < maxX; i++) { + matrix[y][i] = 0 + } + handledColumns[y] = true + } + } +}; \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\273\204\345\220\210-77.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\273\204\345\220\210-77.js" new file mode 100644 index 0000000..8f3ccf1 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\273\204\345\220\210-77.js" @@ -0,0 +1,33 @@ +/** + * @param {number} n + * @param {number} k + * @return {number[][]} + */ +let combine = function (n, k) { + let ret = [] + + let helper = (start, prev) => { + let len = prev.length + if (len === k) { + ret.push(prev) + return + } + + if (start > n) { + return + } + + // 还有 rest 个位置待填补 + let rest = k - prev.length + for (let i = start; i <= n; i++) { + if (n - i + 1 < rest) { + continue + } + helper(i + 1, prev.concat(i)) + } + } + helper(1, []) + return ret +} + +console.log(combine(4, 2)) diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\273\204\345\220\210\346\200\273\345\222\214-39.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\273\204\345\220\210\346\200\273\345\222\214-39.js" new file mode 100644 index 0000000..f55dc03 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\273\204\345\220\210\346\200\273\345\222\214-39.js" @@ -0,0 +1,32 @@ +/** + * @param {number[]} candidates + * @param {number} target + * @return {number[][]} + */ +let combinationSum = function (candidates, target) { + let res = [] + + let helper = (start, prevSum, prevArr) => { + // 由于全是正整数 所以一旦和大于目标值了 直接结束本次递归即可。 + if (prevSum > target) { + return + } + // 目标值达成 + if (prevSum === target) { + res.push(prevArr) + return + } + + for (let i = start; i < candidates.length; i++) { + // 这里还是继续从start本身开始 因为多个重复值是允许的 + let cur = candidates[i] + let sum = prevSum + cur + let arr = prevArr.concat(cur) + helper(i, sum, arr) + } + } + + helper(0, 0, []) + + return res +} \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\273\204\345\220\210\346\200\273\345\222\214-40.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\273\204\345\220\210\346\200\273\345\222\214-40.js" new file mode 100644 index 0000000..84a3750 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\347\273\204\345\220\210\346\200\273\345\222\214-40.js" @@ -0,0 +1,47 @@ +let genKey = (arr) => arr.join("~") +/** + * @param {number[]} candidates + * @param {number} target + * @return {number[][]} + */ +let combinationSum2 = function (candidates, target) { + let res = [] + + if (!candidates.length) { + return res + } + + candidates.sort() + + let used = {} + + let helper = (start, prevSum, prevArr) => { + // 由于全是正整数 所以一旦和大于目标值了 直接结束本次递归即可。 + if (prevSum > target) { + return + } + // 目标值达成 + if (prevSum === target) { + let key = genKey(prevArr) + if (!used[key]) { + res.push(prevArr) + used[key] = true + } + return + } + + for (let i = start; i < candidates.length; i++) { + // 这里还是继续从start本身开始 因为多个重复值是允许的 + let cur = candidates[i] + let sum = prevSum + cur + let arr = prevArr.concat(cur) + helper(i + 1, sum, arr) + } + } + + helper(0, 0, []) + + return res +} + +console.log(combinationSum2([2, 1, 2, 1, 3], 6)) diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\350\236\272\346\227\213\347\237\251\351\230\265-54.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\350\236\272\346\227\213\347\237\251\351\230\265-54.js" new file mode 100644 index 0000000..5b64a29 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\350\236\272\346\227\213\347\237\251\351\230\265-54.js" @@ -0,0 +1,56 @@ +/** + * @param {number[][]} matrix + * @return {number[]} + */ +let spiralOrder = function (matrix) { + let maxY = matrix.length + if (!maxY) return [] + let maxX = matrix[0].length + + // 记录一个 visited 数组 + // 按照 右 -> 下 -> 左 -> 上 的方向不断前进 + // 直到遇到边界或者已经访问过的元素 则切换成下一个方向 + let dirs = [ + [0, 1], // 右 + [1, 0], // 下 + [0, -1], // 左 + [-1, 0], // 上 + ] + + let currentDirIndex = 0 + + let visited = [] + for (let y = 0; y < maxY; y++) { + visited[y] = [] + } + let isValid = (y, x) => { + return y >= 0 && y < maxY && x >= 0 && x < maxX && !visited[y][x] + } + + let targetLength = maxY * maxX + let res = [] + + let helper = (y, x) => { + let val = matrix[y][x] + res.push(val) + + if (res.length === targetLength) { + return res + } + + visited[y][x] = true + let [diffY, diffX] = dirs[currentDirIndex % 4] + let nextY = y + diffY + let nextX = x + diffX + if (!isValid(nextY, nextX)) { + [diffY, diffX] = dirs[++currentDirIndex % 4] + nextY = y + diffY + nextX = x + diffX + } + helper(nextY, nextX) + } + + helper(0, 0) + + return res +}; \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\350\247\243\346\225\260\347\213\254-37.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\350\247\243\346\225\260\347\213\254-37.js" new file mode 100644 index 0000000..9bcf69e --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\350\247\243\346\225\260\347\213\254-37.js" @@ -0,0 +1,87 @@ +/** + * @param {character[][]} board + * @return {void} Do not return anything, modify board in-place instead. + */ +let solveSudoku = function (board) { + let rows = initTwoDimensionalArray(9) + let columns = initTwoDimensionalArray(9) + let grids = initTwoDimensionalArray(3) + + // 待处理下标队列 第一次扫描的时候记录下来 + let pending = [] + + for (let y = 0; y < 9; y++) { + for (let x = 0; x < 9; x++) { + let cell = board[y][x] + if (cell === ".") { + // 待填充的数独格子 记录在队列中 + pending.push([x, y]) + continue + } + // 记录下当前下标 + recordCell(x, y, cell) + } + } + + let helper = (startPendingIndex) => { + if (startPendingIndex === pending.length) { + return true + } + + let [x, y] = pending[startPendingIndex] + + for (let i = 1; i <= 9; i++) { + let cur = i.toString() + if (isValid(x, y, cur)) { + board[y][x] = cur + recordCell(x, y, cur) + if (helper(startPendingIndex + 1)) { + return true + } else { + board[y][x] = "." + restoreCell(x, y, cur) + } + } + } + } + + helper(0) + + function recordCell(x, y, cell) { + rows[y][cell] = true + columns[x][cell] = true + let [gridX, gridY] = findGridIndex(x, y) + if (!grids[gridY][gridX]) { + grids[gridY][gridX] = new Map() + } + grids[gridY][gridX].set(cell, true) + } + + function restoreCell(x, y, cell) { + rows[y][cell] = false + columns[x][cell] = false + let [gridX, gridY] = findGridIndex(x, y) + grids[gridY][gridX].set(cell, false) + } + + function isValid(x, y, cell) { + let isYConflict = rows[y][cell] + let isXConflict = columns[x][cell] + let [gridX, gridY] = findGridIndex(x, y) + let grid = grids[gridY][gridX] + let isGridConflict = grid && grid.get(cell) + return !isYConflict && !isXConflict && !isGridConflict + } +} + +function initTwoDimensionalArray(length) { + let ret = [] + for (let i = 0; i < length; i++) { + ret.push([]) + } + return ret +} + +function findGridIndex(x, y) { + return [Math.floor(x / 3), Math.floor(y / 3)] +} diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\350\267\263\346\260\264\346\235\277-\351\235\242\350\257\225\351\242\230 16.11.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\350\267\263\346\260\264\346\235\277-\351\235\242\350\257\225\351\242\230 16.11.js" new file mode 100644 index 0000000..fb26019 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\350\267\263\346\260\264\346\235\277-\351\235\242\350\257\225\351\242\230 16.11.js" @@ -0,0 +1,23 @@ +/** + * @param {number} shorter + * @param {number} longer + * @param {number} k + * @return {number[]} + */ +let divingBoard = function (shorter, longer, k) { + if (k === 0) { + return [] + } + if (shorter === longer) { + return [k * shorter] + } + + let res = [] + for (let i = 0; i <= k; i++) { + let longCount = i + let shortCount = k - i + res.push(shortCount * shorter + longCount * longer) + } + + return res +}; \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\351\200\222\345\275\222\347\237\251\351\230\265-59.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\351\200\222\345\275\222\347\237\251\351\230\265-59.js" new file mode 100644 index 0000000..0be2940 --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\351\200\222\345\275\222\347\237\251\351\230\265-59.js" @@ -0,0 +1,54 @@ +/** + * @param {number} n + * @return {number[][]} + */ +let generateMatrix = function (n) { + // 记录一个 visited 数组 + // 按照 右 -> 下 -> 左 -> 上 的方向不断前进 + // 直到遇到边界或者已经访问过的元素 则切换成下一个方向 + let dirs = [ + [0, 1], // 右 + [1, 0], // 下 + [0, -1], // 左 + [-1, 0], // 上 + ] + + let currentDirIndex = 0 + + let visited = [] + for (let y = 0; y < n; y++) { + visited[y] = [] + } + let isValid = (y, x) => { + return y >= 0 && y < n && x >= 0 && x < n && !visited[y][x] + } + + let targetLength = n * n + let res = [] + for (let y = 0; y < n; y++) { + res[y] = [] + } + + let helper = (y, x, num) => { + res[y][x] = num + + if (num === targetLength) { + return res + } + + visited[y][x] = true + let [diffY, diffX] = dirs[currentDirIndex % 4] + let nextY = y + diffY + let nextX = x + diffX + if (!isValid(nextY, nextX)) { + ;[diffY, diffX] = dirs[++currentDirIndex % 4] + nextY = y + diffY + nextX = x + diffX + } + helper(nextY, nextX, num + 1) + } + + helper(0, 0, 1) + + return res +} diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\351\241\272\346\254\241\346\225\260-1291.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\351\241\272\346\254\241\346\225\260-1291.js" new file mode 100644 index 0000000..13f8a5c --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\351\241\272\346\254\241\346\225\260-1291.js" @@ -0,0 +1,30 @@ +/** + * @param {number} low + * @param {number} high + * @return {number[]} + */ +let sequentialDigits = function (low, high) { + let lowLen = low.toString().length + let highLen = high.toString().length + let lens = [] + for (let i = lowLen; i <= highLen; i++) { + lens.push(i) + } + + let res = [] + for (let i = 0; i < lens.length; i++) { + let len = lens[i] + for (let start = 1; start <= 10 - len; start++) { + let num = start + + for (let n = start + 1; n < start + len; n++) { + num = 10 * num + n + } + if (num <= high && num >= low) { + res.push(num) + } + } + } + + return res +} \ No newline at end of file diff --git "a/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\351\273\204\351\207\221\347\237\277\345\267\245-1219.js" "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\351\273\204\351\207\221\347\237\277\345\267\245-1219.js" new file mode 100644 index 0000000..0d8d53c --- /dev/null +++ "b/\351\200\222\345\275\222\344\270\216\345\233\236\346\272\257/\351\273\204\351\207\221\347\237\277\345\267\245-1219.js" @@ -0,0 +1,69 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +let getMaximumGold = function (grid) { + let maxY = grid.length + if (maxY === 0) { + return 0 + } + let maxX = grid[0].length + + let visited = [] + for (let y = 0; y < maxY; y++) { + visited[y] = [] + } + + let dirs = [ + [1, 0], + [-1, 0], + [0, -1], + [0, 1], + ] + + // 验证是否能走入这个格子 + // 1. 范围不能越界 + // 2. 本轮递归中未访问过 + // 3. 格子的值不能为 0 + let isValid = (y, x) => { + return ( + y >= 0 && + y < maxY && + x >= 0 && + x < maxX && + grid[y][x] !== 0 && + !visited[y][x] + ) + } + + let maxGold = 0 + let helper = (y, x, prevGold) => { + let val = grid[y][x] + let curGold = prevGold + val + if (curGold === 0) { + return + } + + for (let dir of dirs) { + let [diffY, diffX] = dir + let nextY = y + diffY + let nextX = x + diffX + if (isValid(nextY, nextX)) { + visited[y][x] = true + helper(nextY, nextX, curGold) + visited[y][x] = false + } else { + // 走到尽头或者不符合条件的了 + maxGold = Math.max(maxGold, curGold) + } + } + } + + for (let y = 0; y < maxY; y++) { + for (let x = 0; x < maxX; x++) { + helper(y, x, 0) + } + } + + return maxGold +} diff --git "a/\351\223\276\350\241\250/\344\270\244\344\270\244\344\272\244\346\215\242\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271-24.js" "b/\351\223\276\350\241\250/\344\270\244\344\270\244\344\272\244\346\215\242\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271-24.js" new file mode 100644 index 0000000..527b48a --- /dev/null +++ "b/\351\223\276\350\241\250/\344\270\244\344\270\244\344\272\244\346\215\242\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271-24.js" @@ -0,0 +1,28 @@ +const ListNode = require("../工具/链表") + +let swapPairs = function (head) { + let helper = function (node) { + let tempNext = node.next + if (tempNext) { + let tempNextNext = node.next.next + node.next.next = node + if (tempNextNext) { + node.next = helper(tempNextNext) + }else { + node.next = null + } + } + return tempNext + } + + let res = helper(head) + + return res +} + +let node = new ListNode(1) +node.next = new ListNode(2) +node.next.next = new ListNode(3) +node.next.next.next = new ListNode(4) + +console.log(swapPairs(node)) diff --git "a/\351\223\276\350\241\250/\344\270\244\346\225\260\347\233\270\345\212\240 II-445.js" "b/\351\223\276\350\241\250/\344\270\244\346\225\260\347\233\270\345\212\240 II-445.js" new file mode 100644 index 0000000..477c5a7 --- /dev/null +++ "b/\351\223\276\350\241\250/\344\270\244\346\225\260\347\233\270\345\212\240 II-445.js" @@ -0,0 +1,69 @@ +var reverseList = function (head) { + if (!head) return null + let res = null + let dfs = function (node) { + if (node.next) { + dfs(node.next) + node.next.next = node + } else { + res = node + } + } + + dfs(head) + + head.next = null + + return res +}; + +var addTwoNumbers = function (l1, l2) { + l1 = reverseList(l1) + l2 = reverseList(l2) + + let i = 0 + let root = new ListNode() + let cur = root + let plus = false + + let traverse = (node1, node2) => { + let isDouble = !!node2 + while (isDouble ? (node1 && node2) : node1) { + cur.next = new ListNode() + cur = cur.next + + let sum = node1.val + (plus ? 1 : 0) + if (isDouble) { + sum += node2.val + } + + if (sum >= 10) { + sum %= 10 + plus = true + } else { + plus = false + } + cur.val = sum + + node1 = node1.next + if (isDouble) { + node2 = node2.next + } + } + + if (node1) { + traverse(node1) + } + if (node2) { + traverse(node2) + } + } + + traverse(l1, l2) + + if (plus) { + cur.next = new ListNode(1) + } + + return reverseList(root.next) +}; diff --git "a/\351\223\276\350\241\250/\344\270\244\346\225\260\347\233\270\345\212\240-3.js" "b/\351\223\276\350\241\250/\344\270\244\346\225\260\347\233\270\345\212\240-3.js" new file mode 100644 index 0000000..9eec915 --- /dev/null +++ "b/\351\223\276\350\241\250/\344\270\244\346\225\260\347\233\270\345\212\240-3.js" @@ -0,0 +1,59 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +let addTwoNumbers = function (l1, l2) { + let i = 0 + let root = new ListNode() + let cur = root + let plus = false + + let traverse = (node1, node2) => { + let isDouble = !!node2 + while (isDouble ? node1 && node2 : node1) { + cur.next = new ListNode() + cur = cur.next + + let sum = node1.val + (plus ? 1 : 0) + if (isDouble) { + sum += node2.val + } + + if (sum >= 10) { + sum %= 10 + plus = true + } else { + plus = false + } + cur.val = sum + + node1 = node1.next + if (isDouble) { + node2 = node2.next + } + } + + if (node1) { + traverse(node1) + } + if (node2) { + traverse(node2) + } + } + + traverse(l1, l2) + + if (plus) { + cur.next = new ListNode(1) + } + + return root.next +} diff --git "a/\351\223\276\350\241\250/\345\210\240\351\231\244\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271-\351\235\242\350\257\225\351\242\23018.js" "b/\351\223\276\350\241\250/\345\210\240\351\231\244\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271-\351\235\242\350\257\225\351\242\23018.js" new file mode 100644 index 0000000..611cb98 --- /dev/null +++ "b/\351\223\276\350\241\250/\345\210\240\351\231\244\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271-\351\235\242\350\257\225\351\242\23018.js" @@ -0,0 +1,15 @@ +var deleteNode = function (head, val) { + let virtual = { + next: head, + } + let cur = virtual + while (cur) { + if (cur.next) { + if (cur.next.val === val) { + cur.next = cur.next.next + } + } + cur = cur.next + } + return virtual.next +} diff --git "a/\351\223\276\350\241\250/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\350\212\202\347\202\271-19.js" "b/\351\223\276\350\241\250/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\350\212\202\347\202\271-19.js" new file mode 100644 index 0000000..3fa6ae6 --- /dev/null +++ "b/\351\223\276\350\241\250/\345\210\240\351\231\244\351\223\276\350\241\250\347\232\204\345\200\222\346\225\260\347\254\254N\344\270\252\350\212\202\347\202\271-19.js" @@ -0,0 +1,41 @@ +const { makeListNode } = require('../工具/链表') +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @param {number} n + * @return {ListNode} + */ +let removeNthFromEnd = function (head, n) { + let node = head + let nodes = [] + do { + nodes.push(node) + node = node.next + } while (node) + + const l = nodes.length + const index = l - n + const targetNode = nodes[index] + const prevNode = nodes[index - 1] + if (prevNode) { + prevNode.next = targetNode.next + } + + const tempNext = targetNode.next + targetNode.next = null + + + if (targetNode === head) { + return tempNext + } + return head +}; + +const node = makeListNode([1, 2, 3, 4, 5]) +console.log(removeNthFromEnd(node, 5)) \ No newline at end of file diff --git "a/\351\223\276\350\241\250/\345\217\215\350\275\254\351\223\276\350\241\250-206.js" "b/\351\223\276\350\241\250/\345\217\215\350\275\254\351\223\276\350\241\250-206.js" new file mode 100644 index 0000000..32097f9 --- /dev/null +++ "b/\351\223\276\350\241\250/\345\217\215\350\275\254\351\223\276\350\241\250-206.js" @@ -0,0 +1,13 @@ +function reverse(head) { + let prev = null + let cur = head + while (cur) { + let next = cur.next + cur.next = prev + + prev = cur + cur = next + } + // 返回反转后的头节点 + return prev +} diff --git "a/\351\223\276\350\241\250/\345\217\215\350\275\254\351\223\276\350\241\250II-92.js" "b/\351\223\276\350\241\250/\345\217\215\350\275\254\351\223\276\350\241\250II-92.js" new file mode 100644 index 0000000..ab69981 --- /dev/null +++ "b/\351\223\276\350\241\250/\345\217\215\350\275\254\351\223\276\350\241\250II-92.js" @@ -0,0 +1,74 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ + +const ListNode = require("../工具/链表") +/** + * @param {ListNode} head + * @param {number} m + * @param {number} n + * @return {ListNode} + */ + +let reverseBetween = function (head, m, n) { + let i = 1 + let sliceStartPrev = null + let sliceStart = null + let sliceEnd = null + let cur = head + + // 记录切分起点的前一个节点,和切分终点的后一个节点 + while (i <= n) { + if (i === m - 1) { + sliceStartPrev = cur + } + if (i === m) { + sliceStart = cur + } + if (i === n) { + sliceEnd = cur + } + cur = cur.next + i++ + } + + let sliceEndNext = sliceEnd.next + // 切断切分终点的next 防止反转的时候反转过头 + sliceEnd.next = null + + const { head: slicedHead, tail: slicedTail } = reverse(sliceStart) + if (sliceStartPrev) { + // 如果需要反转的部分有前一个节点 那么只需要在中间动手脚 原样返回head节点即可 + sliceStartPrev.next = slicedHead + } else { + // 这里需要注意的是 如果没有sliceStartPrev 说明是从第一个节点就开始反转的 + // 那么我们需要手动调整head为反转后的head + head = slicedHead + } + slicedTail.next = sliceEndNext + + return head +} + +function reverse(head) { + let prev = null + let cur = head + while (cur) { + let next = cur.next + cur.next = prev + + prev = cur + cur = next + } + // 返回反转后的头尾节点 + return { head: prev, tail: head } +} + +let node = new ListNode(3) +node.next = new ListNode(5) + +console.log(JSON.stringify(reverseBetween(node, 1, 1))) diff --git "a/\351\223\276\350\241\250/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240-203.js" "b/\351\223\276\350\241\250/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240-203.js" new file mode 100644 index 0000000..bd16019 --- /dev/null +++ "b/\351\223\276\350\241\250/\347\247\273\351\231\244\351\223\276\350\241\250\345\205\203\347\264\240-203.js" @@ -0,0 +1,18 @@ +let removeElements = function (head, val) { + let root = new ListNode() + root.next = head + let cur = root + while (cur) { + let next = cur.next + if (!next) { + break + } + let nextVal = next.val + if (nextVal === val) { + cur.next = cur.next.next + } else { + cur = cur.next + } + } + return root.next +} diff --git "a/\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\2622.js" "b/\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\2622.js" index 8a4bd17..2f1b015 100644 --- "a/\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\2622.js" +++ "b/\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\2622.js" @@ -2,36 +2,36 @@ * @param {string} s * @return {boolean} */ -let validPalindrome = function(s) { +let validPalindrome = function (s) { let i = 0; - let j = s.length - 1 - + let j = s.length - 1; + // 两个指针往中间缩进 while (i < j && s[i] === s[j]) { - i++ - j-- + i++; + j--; } // 遇到相对位置不相等了 判断删除一位后的情况 if (isPalindrome(i + 1, j)) { - return true + return true; } if (isPalindrome(i, j - 1)) { - return true + return true; } // 工具方法,用于判断字符串是否回文 function isPalindrome(st, ed) { - while(st