├── src ├── 02-jianzhi-offer-81 │ └── 01-reverse-link-list.ts ├── 01-nowcoder-top-101 │ └── 01-reverse-link-list.ts ├── index.css ├── index.ts ├── 00-codetop-fontend-100 │ ├── 31-.ts │ ├── 32-.ts │ ├── 33-.ts │ ├── 34-.ts │ ├── 35-.ts │ ├── 38-.ts │ ├── 39-.ts │ ├── 37-.ts │ ├── 40-.ts │ ├── 30-.ts │ ├── 36-.ts │ ├── 28-max-area-of-island.ts │ ├── 04-compare-version.ts │ ├── 22-generate-parenthesis.ts │ ├── 29-lru-cache.ts │ ├── 16-sort-an-array.ts │ ├── 13-kth-largest-element-in-an-array.ts │ ├── 07-climb-stairs.ts │ ├── 03-add-strings.ts │ ├── 10-reverse-linked-list.ts │ ├── 08-permutations.ts │ ├── 14-three-sum.ts │ ├── 24-spiral-matrix.ts │ ├── 21-number-of-islands.ts │ ├── 27-maximum-depth-of-binary-tree.ts │ ├── 17-linked-list-cycle.ts │ ├── 05-is-valid-brackets.ts │ ├── 26-binary-tree-inorder-traversal.ts │ ├── 25-longest-increasing-subsequence.ts │ ├── 06-two-sum.ts │ ├── 23-merge-two-sorted-linked-lists.ts │ ├── 02-merge-sorted-arr.ts │ ├── 11-path-sum.ts │ ├── 09-max-sub-array.ts │ ├── 20-binary-search.ts │ ├── 19-sum-root-to-leaf-numbers.ts │ ├── 15-best-time-to-buy-and-sell-stock.ts │ ├── 01-length-of-longest-substring.ts │ ├── 18-longest-palindromic-substring.ts │ └── 12-binary-tree-level-order-traversal.ts └── index.html ├── .gitignore ├── tsconfig.json ├── package.json ├── webpack.config.js ├── LICENSE └── README.md /src/02-jianzhi-offer-81/01-reverse-link-list.ts: -------------------------------------------------------------------------------- 1 | // 待更新 -------------------------------------------------------------------------------- /src/01-nowcoder-top-101/01-reverse-link-list.ts: -------------------------------------------------------------------------------- 1 | // 待更新,敬请期待…… -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: rgb(43, 116, 226); 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Log file 2 | *.log 3 | 4 | # Package Files # 5 | *.zip 6 | *.tar.gz 7 | *.rar 8 | 9 | # Font End Files 10 | /node_modules 11 | /dist 12 | 13 | # Mac OS 14 | .DS_Store 15 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import './index.css' 2 | // import func from './01-nowcoder-top-101/01-reverse-link-list.js' 3 | 4 | // if (module.hot) { 5 | // module.hot.accept('./01-nowcoder-top-101/01-reverse-link-list', function() { 6 | // func() 7 | // }) 8 | // } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "noImplicitAny": true, 5 | "module": "es6", 6 | "target": "es5", 7 | "jsx": "react", 8 | "allowJs": true, 9 | "moduleResolution": "node" 10 | } 11 | } -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/31-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/32-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/33-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/34-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/35-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/38-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/39-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/37-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/40-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/30-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/36-.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称: 4 | * leetcode 题目: 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 14 | * 时间复杂度: 15 | * 空间复杂度: 16 | */ 17 | function numIslands(grid: string[][]): number { 18 | 19 | }; -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 前端算法 8 | 9 | 10 | 请打开 Chrome Console 面板调试 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/28-max-area-of-island.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:岛屿的最大面积 4 | * leetcode 题目: https://leetcode.cn/problems/max-area-of-island/ 5 | * leetcode 题解: 6 | * 牛客网 题目: https://www.nowcoder.com/practice/5568943d3a08403f932a5e54ec3ece71 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * 时间复杂度: 14 | * 空间复杂度: 15 | */ 16 | function numIslands(grid: string[][]): number { 17 | 18 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "cross-env NODE_ENV=dev webpack serve --mode development --hot", 4 | "test": "cross-env NODE_ENV=test webpack --mode production", 5 | "build": "cross-env NODE_ENV=prod webpack --mode production" 6 | }, 7 | "devDependencies": { 8 | "clean-webpack-plugin": "^4.0.0", 9 | "cross-env": "^7.0.3", 10 | "css-loader": "^6.7.1", 11 | "html-webpack-plugin": "^5.5.0", 12 | "style-loader": "^3.3.1", 13 | "ts-loader": "^9.2.8", 14 | "typescript": "^4.6.3", 15 | "webpack": "^5.72.0", 16 | "webpack-cli": "^4.9.2", 17 | "webpack-dev-server": "^4.8.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/04-compare-version.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:比较版本号 4 | * leetcode 题目: https://leetcode-cn.com/problems/compare-version-numbers/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/compare-version-numbers/solution/by-hovinghuang-rmlf/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/2b317e02f14247a49ffdbdba315459e7 7 | * 牛客网 题解: https://blog.nowcoder.net/n/5569dbf30e3e45ea977152a629d86439 8 | */ 9 | 10 | /** 11 | * 解法一:分割截取 12 | * 思路: 13 | *(1)先根据.号分割成字符串数组,获取两个数组中的最大长度值, 14 | *(2)按顺序遍历比较,详细过程看以下代码 15 | * 时间复杂度:O(max(n, m)) 16 | * 空间复杂度:O(max(n, m)) 17 | */ 18 | function compareVersion(version1: string, version2: string): number { 19 | const arr1: any[] = version1.split('.') 20 | const arr2: any[] = version2.split('.') 21 | const maxLen = Math.max(arr1.length, arr2.length) 22 | 23 | for (let i = 0; i < maxLen; i++) { 24 | // arr1[i] - '0' ,js 会强制转换成 number 然后相减 25 | // 例如:('01' - '0'), 结果是 1 (number 类型) 26 | // @ts-ignore 27 | const num1 = arr1[i] ? arr1[i] - '0' : 0 28 | // @ts-ignore 29 | const num2 = arr2[i] ? arr2[i] - '0' : 0 30 | if (num1 > num2) return 1 31 | if (num1 < num2) return -1 32 | } 33 | 34 | return 0 35 | }; 36 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/22-generate-parenthesis.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:括号生成 4 | * leetcode 题目: https://leetcode-cn.com/problems/generate-parentheses/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/generate-parentheses/solution/by-hovinghuang-ueaq/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/c9addb265cdf4cdd92c092c655d164ca 7 | * 牛客网 题解: https://blog.nowcoder.net/n/14c439288cc944d397206965bcc2d0bc 8 | */ 9 | 10 | /** 11 | * 解法一:递归 12 | * 思路: 13 | * (1)如果使用了一个左括号以后,那么还剩下n-1个左括号和n个右括号,也是将这些括号连接成-一个字符串,就相当于是原问题的子问题,因此我们使用递归。 14 | * (2)但是这样递归不能保证括号一 定合法,我们需要保证左括号出现的次数比右括号多时我们再使用右括号就一定能保证括号合法了, 15 | * 因此每次需要检查左括号和右括号的使用次数。 16 | * 时间复杂度:复杂度取决于有多少个合法括号组合 17 | * 空间复杂度:O(n),递归栈最大空间,其中res数组是返回时必须要的,不算额外空间 18 | */ 19 | function generateParenthesis(n: number): string[] { 20 | const res: string[] = [] 21 | resursion(0, 0, '', res, n) 22 | return res 23 | }; 24 | function resursion(left: number, right: number, temp: string, res: string[], n: number): string[] { 25 | if (left === n && right === n) { 26 | res.push(temp) 27 | return 28 | } 29 | if (left < n) { 30 | resursion(left + 1, right, temp + '(', res, n) 31 | } 32 | if (right < n && left > right) { 33 | resursion(left, right + 1, temp + ')', res, n) 34 | } 35 | } -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/29-lru-cache.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:LRU 缓存 4 | * leetcode 题目: https://leetcode-cn.com/problems/lru-cache/ 5 | * leetcode 题解: 6 | * 牛客网 题目: 7 | * 牛客网 题解: 8 | */ 9 | 10 | /** 11 | * 解法一: 12 | * 思路: 13 | * (1) 14 | * 时间复杂度: 15 | * 空间复杂度: 16 | */ 17 | class LRUCache { 18 | private caches: Map; 19 | constructor(private capacity: number = 0) { 20 | this.caches = new Map() 21 | } 22 | 23 | get(key: number): number { 24 | const val = this.caches.get(key); 25 | if (val !== undefined) { // 新鲜度提高,重新排序到栈顶 26 | this.caches.delete(key) 27 | this.caches.set(key, val) 28 | return val 29 | } else { 30 | return -1 31 | } 32 | } 33 | 34 | put(key: number, value: number): void { 35 | const val = this.caches.get(key) 36 | if (val !== undefined) { 37 | this.caches.delete(key) 38 | this.caches.set(key, value) 39 | } else { 40 | if (this.caches.size >= this.capacity) { 41 | let oldKey = this.caches.keys().next().value // 最旧的key 42 | this.caches.delete(oldKey) 43 | } 44 | 45 | this.caches.set(key, value) 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require("webpack"); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin') 4 | 5 | // console.log('process.env.NODE_ENV=', process.env.NODE_ENV) // 打印环境变量 6 | 7 | const config = { 8 | entry: './src/index.ts', // 打包入口地址 9 | output: { 10 | filename: 'bundle.js', // 输出文件名 11 | path: path.join(__dirname, 'dist'), // 输出文件目录 12 | clean: true, 13 | }, 14 | target: 'web', 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.tsx?$/, 19 | use: 'ts-loader', 20 | exclude: /node_modules/, 21 | }, 22 | { 23 | test: /\.css$/, //匹配所有的 css 文件 24 | use: ['style-loader', 'css-loader'] // use: 对应的 Loader 名称 25 | } 26 | ] 27 | }, 28 | resolve: { 29 | extensions: ['.tsx', '.ts', '.js'], 30 | }, 31 | devServer: { 32 | static: './dist', 33 | hot: true, 34 | historyApiFallback: true, 35 | compress: true 36 | }, 37 | plugins:[ // 配置插件 38 | new HtmlWebpackPlugin({ 39 | template: './src/index.html' 40 | }), 41 | new webpack.HotModuleReplacementPlugin() 42 | ] 43 | } 44 | 45 | module.exports = (env, argv) => { 46 | console.log('argv.mode=',argv.mode) // 打印 mode(模式) 值 47 | // 这里可以通过不同的模式修改 config 配置 48 | return config; 49 | } 50 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/16-sort-an-array.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:排序数组(快速排序) 4 | * leetcode 题目: https://leetcode-cn.com/problems/sort-an-array/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/sort-an-array/solution/by-hovinghuang-4j3t/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/2baf799ea0594abd974d37139de27896 7 | * 牛客网 题解: https://blog.nowcoder.net/n/ed60ab35639e4289bf51b7253d3a5c45 8 | */ 9 | 10 | /** 11 | * 解法一:快速排序 12 | * 思路: 13 | * (1)快速排序的主要思想是通过划分将待排序的序列分成前后两部分,其中前一部分的数据都比后一部分的数据要小, 14 | * (2)然后再递归调用函数对两部分的序列分别进行快速排序,以此使整个序列达到有序。 15 | * 时间复杂度:O(nlogn) 16 | * 空间复杂度:O(h),其中 h 为快速排序递归调用的层数。我们需要额外的 O(h) 的递归调用的栈空间, 17 | * 由于划分的结果不同导致了快速排序递归调用的层数也会不同,最坏情况下需 O(n) 的空间,最优情况下每次都平衡, 18 | * 此时整个递归树高度为 logn,空间复杂度为 O(logn)。 19 | */ 20 | function sortArray(nums: number[]): number[] { 21 | const len = nums.length 22 | if (len === 0) return nums 23 | 24 | const midIndex = Math.floor(len / 2) 25 | const midValue = nums.splice(midIndex, 1)[0] 26 | 27 | const left: number[] = [] 28 | const right: number[] = [] 29 | 30 | // 注意: splice 会修改原数组,所以用 arr.length 31 | for (let i = 0; i < nums.length; i++) { 32 | const n = nums[i] 33 | if (n < midValue) { 34 | left.push(n) 35 | } else { 36 | right.push(n) 37 | } 38 | } 39 | return sortArray(left).concat([midValue], sortArray(right)) 40 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/13-kth-largest-element-in-an-array.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:数组中的第K个最大元素 4 | * leetcode 题目: https://leetcode-cn.com/problems/kth-largest-element-in-an-array/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/kth-largest-element-in-an-array/solution/by-hovinghuang-mes5/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/e016ad9b7f0b45048c58a9f27ba618bf 7 | * 牛客网 题解: https://blog.nowcoder.net/n/ea1b2f2bf02b48d38c75a4e684b5471e 8 | */ 9 | 10 | /** 11 | * 解法一:快速排序 12 | * 思路:快排,取得升序数组,然后取下标 nums.length - k + 1 对应的值 13 | * 时间复杂度:O(nlogn) 14 | * 空间复杂度:最优 O(logn), 最差 O(n) 15 | */ 16 | function findKthLargest(nums: number[], k: number): number { 17 | if (nums.length === 0) return 0 18 | return sortArray(nums)[nums.length - k + 1] 19 | }; 20 | function sortArray(nums: number[]): number[] { 21 | const len = nums.length 22 | if (len === 0) return nums 23 | 24 | const midIndex = Math.floor(len / 2) 25 | const midValue = nums.splice(midIndex, 1)[0] 26 | 27 | const left: number[] = [] 28 | const right: number[] = [] 29 | 30 | // 注意: splice 会修改原数组,所以用 arr.length 31 | for (let i = 0; i < nums.length; i++) { 32 | const n = nums[i] 33 | if (n < midValue) { 34 | left.push(n) 35 | } else { 36 | right.push(n) 37 | } 38 | } 39 | return sortArray(left).concat([midValue], sortArray(right)) 40 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/07-climb-stairs.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:爬楼梯(跳台阶) 4 | * leetcode 题目: https://leetcode-cn.com/problems/climbing-stairs/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/climbing-stairs/solution/by-hovinghuang-bl5r/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/8c82a5b80378478f9484d87d1c5f12a4 7 | * 牛客网 题解: https://blog.nowcoder.net/n/7057ccebe8fd452580442b74ffbb8d90 8 | */ 9 | 10 | /** 11 | * 解法一:递归(超时) 12 | * 思路:满足斐波那契数列公式,最简单的肯定是递归 13 | * 时间复杂度:O(2^n) 14 | * 空间复杂度: 15 | */ 16 | function climbStairs(n: number): number { 17 | if (n <= 2) return n 18 | return climbStairs(n - 1) + climbStairs(n - 2) 19 | }; 20 | 21 | /** 22 | * 解法二:循环(记忆化累加) 23 | * 思路:n1、n2 记录前面两位的结果,一个循环搞定 24 | * 时间复杂度:O(n) 25 | * 空间复杂度:O(1) 26 | */ 27 | function climbStairs(n: number): number { 28 | if (n <= 2) return n 29 | 30 | let n1 = 1 // 记录 n - 1 的结果 31 | let n2 = 1 // 记录 n - 2 的结果 32 | let res = 0 33 | 34 | for (let i = 2; i <= n; i++) { 35 | res = n1 + n2 36 | 37 | // 记录中间结果 38 | n2 = n1 39 | n1 = res 40 | } 41 | 42 | return res 43 | }; 44 | 45 | /** 46 | * 解法三:动态规划 47 | * 思路: 48 | * 时间复杂度:O(n) 49 | * 空间复杂度: 50 | */ 51 | function climbStairs(n: number): number { 52 | const dp = new Array(n + 1) 53 | dp[1] = 1 54 | dp[2] = 2 55 | for (let i = 3; i <= n; i++){ 56 | dp[i] = dp[i - 1] + dp[i - 2] 57 | } 58 | return dp[n] 59 | }; 60 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/03-add-strings.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:字符串相加(大数加法) 4 | * leetcode 题目: https://leetcode-cn.com/problems/add-strings/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/add-strings/solution/by-hovinghuang-l59r/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/11ae12e8c6fe48f883cad618c2e81475?tpId=295&tqId=1061819&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295 7 | * 牛客网 题解: https://blog.nowcoder.net/n/1027295c5c8d44f7bbfe2b276e5adf20 8 | */ 9 | 10 | /** 11 | * 解法一:模拟法(双尾指针法) 12 | * 思路:模拟我们日常加法进位过程,详细过程看代码 13 | * 时间复杂度:O(n),其中 n 为较长字符的长度,遍历字符串 14 | * 空间复杂度:O(1),常数级空间 15 | */ 16 | function addStrings(num1: string, num2: string): string { 17 | if (num1.length === 0) return num2 18 | if (num2.length === 0) return num1 19 | 20 | const res: string[] = [] 21 | let plus = 0 22 | let i = num1.length - 1 // i 指向num1尾部 23 | let j = num2.length - 1 // j 指向num2尾部 24 | 25 | while (i >= 0 || j >= 0 || plus !== 0) { 26 | const sVal = (i >= 0 ? parseInt(num1[i]) : 0) 27 | const tVal = (j >= 0 ? parseInt(num2[j]) : 0) 28 | const sum = sVal + tVal + plus 29 | const cur = sum % 10 // 计算当前位(求余) 30 | res.unshift(cur + '') // 将数字转字符串插入res头部 31 | plus = (sum >= 10 ? 1 : 0) // 暂存进位,下次循环用到 32 | i-- 33 | j-- 34 | } 35 | 36 | return res.join('') 37 | }; 38 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/10-reverse-linked-list.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:反转链表 4 | * leetcode 题目: https://leetcode-cn.com/problems/reverse-linked-list/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/reverse-linked-list/solution/by-hovinghuang-zhkh/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca 7 | * 牛客网 题解: https://blog.nowcoder.net/n/087ff0e6f04c4ff699596619f7b4adfd 8 | */ 9 | 10 | /** 11 | * 解法一:迭代(双指针) 12 | * 思路: 13 | * 我们可以设置两个指针,一个当前节点的指针,一个上一个节点的指针(初始为空)。 14 | * 遍历整个链表,每到一个节点,断开当前节点与后面节点的指针,并用临时变量记录后一个节点,然后当前节点指向上一个节点。 15 | * 再轮换当前指针与上-一个指针,让它们进入下一个节点及下一个节点的前序节点。 16 | * 时间复杂度: O(n),遍历链表一次 17 | * 空间复杂度: 0(1),无额外空间使用 18 | */ 19 | function reverseList(head: ListNode | null): ListNode | null { 20 | if (!head) return head 21 | let cur = head 22 | let pre = null 23 | 24 | while (cur != null) { 25 | const temp = cur.next // 把后序的记下来 26 | cur.next = pre 27 | pre = cur 28 | cur = temp 29 | } 30 | 31 | return pre 32 | }; 33 | 34 | /** 35 | * 解法二:递归 36 | * 思路: 37 | * 从上述方法一,我们可以看到每当我们反转链表的一个节点以后,要遍历进入下一个节点进入反转, 38 | * 相当于对后续的子链表进行反转,这就是一个子问题,因此我们也可以使用递归。 39 | * 时间复杂度:O(n),相当于递归遍历链表 40 | * 空间复杂度:O(n),递归栈深度为链表长度n 41 | */ 42 | function reverseList(head: ListNode | null): ListNode | null { 43 | if (!head || !head.next) return head 44 | let node = reverseList(head.next) 45 | head.next.next = head 46 | head.next = null 47 | return node 48 | }; 49 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/08-permutations.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:全排列 4 | * leetcode 题目: https://leetcode-cn.com/problems/permutations/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/permutations/solution/by-hovinghuang-ubrb/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/4bcf3081067a4d028f95acee3ddcd2b1 7 | * 牛客网 题解: https://blog.nowcoder.net/n/02102d26f1bb4026af9be0ec38984ec9 8 | */ 9 | 10 | /** 11 | * 解法一:回溯 + 递归 12 | * 思路: 13 | * 全排列就是对数组元素交换位置,使每--种排列都可能出现。因为题目要求按照字典序排 14 | * 列输出,那毫无疑问第-一个排列就是数组的升序排列,它的字典序最小,后续每个元素与 15 | * 它后面的元素交换一次位置就是一种排列情况,但是如果要保持原来的位置不变,那就不 16 | * 应该从它后面的元素开始交换而是从自己开始交换才能保证原来的位置不变,不会漏情况。 17 | * 时间复杂度: O(n!), n个元素的数组进行全排列 18 | * 空间复杂度: O(n), 递归栈的最大深度为数组长度n,res属于返回必要空间 19 | */ 20 | function permute(nums: number[]): number[][] { 21 | const res: number[][] = [] 22 | if (nums.length === 0) return res 23 | 24 | // nums.sort((a, b) => a - b) 25 | 26 | recursion(res, nums, 0) 27 | 28 | return res 29 | }; 30 | 31 | function recursion(res: number[][], nums: number[], index: number) { 32 | if (index === nums.length - 1) { // 分支进入结尾,找到一种排列 33 | res.push([...nums]) 34 | } else { 35 | for (let i = index; i < nums.length; i++) { 36 | swap(nums, i, index) // 交换二者 37 | recursion(res, nums, index + 1) // 继续往后找 38 | swap(nums, i, index) // 回溯 39 | } 40 | } 41 | } 42 | 43 | function swap(nums: number[], index1: number, index2: number) { 44 | const temp = nums[index1] 45 | nums[index1] = nums[index2] 46 | nums[index2] = temp 47 | } -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/14-three-sum.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:三数之和 4 | * leetcode 题目: https://leetcode-cn.com/problems/3sum/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/3sum/solution/by-hovinghuang-mo14/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/345e2ed5f81d4017bbb8cc6055b0b711 7 | * 牛客网 题解: https://blog.nowcoder.net/n/c9e6f346004f4aedaf087cbdb099b2e6 8 | */ 9 | 10 | /** 11 | * 解法一:双指针 12 | * 思路:待补充 13 | * 时间复杂度:O(n^2) 14 | * 空间复杂度:待补充 15 | */ 16 | function threeSum(nums: number[]): number[][] { 17 | const res: number[][] = [] 18 | const len = nums.length 19 | if (len < 3) return res 20 | 21 | nums.sort((a, b) => a - b) 22 | 23 | for (let i = 0; i < len - 2; i++) { 24 | // 避免重复元素 25 | if (nums[i] == nums[i - 1]) continue 26 | 27 | const target = -nums[i] 28 | let j = i + 1 29 | let k = len - 1 30 | while (j < k) { 31 | // 避免重复元素(为什么要j > i+1,因为下标i跟j可以相同) 32 | if (j > i + 1 && nums[j] == nums[j - 1]){ 33 | j++ 34 | continue 35 | } 36 | 37 | if (nums[k] == nums[k + 1]){ 38 | k-- 39 | continue 40 | } 41 | 42 | if (nums[j] + nums[k] == target) { 43 | res.push([nums[i], nums[j], nums[k]]) 44 | j++ 45 | k-- 46 | } else if (nums[j] + nums[k] < target) { 47 | j++ 48 | } else { 49 | k-- 50 | } 51 | } 52 | } 53 | 54 | return res 55 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/24-spiral-matrix.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:螺旋矩阵 4 | * leetcode 题目: https://leetcode-cn.com/problems/spiral-matrix/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-hovinghuang-i1if/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/7edf70f2d29c4b599693dc3aaeea1d31 7 | * 牛客网 题解: https://blog.nowcoder.net/n/de3f4f8d4f504bc2b3b55ecde6295257 8 | */ 9 | 10 | /** 11 | * 解法一:边界模拟法 12 | * 思路: 13 | * 我们想象有一一个矩阵,从第一- 个元素开始,往右到底后再往 14 | * 下到底后再往左到底后再往上,结束这一-圈,进入下一圈螺旋。 15 | * 时间复杂度: O(mn),相当于遍历整个矩阵. 16 | * 空间复杂度: 0(1),res属于必要空间,没有使用额外辅助空间 17 | */ 18 | function spiralOrder(matrix: number[][]): number[] { 19 | const res: number[] = [] 20 | if (matrix.length === 0) return res 21 | 22 | let left = 0 23 | let right = matrix[0].length - 1 24 | let up = 0 25 | let down = matrix.length - 1 26 | 27 | while (left <= right && up <= down) { 28 | for (let i = left; i <= right; i++) res.push(matrix[up][i]) 29 | 30 | // 收缩上边界 31 | up++ 32 | if (up > down) break 33 | 34 | for (let i = up; i <= down; i++) res.push(matrix[i][right]) 35 | 36 | // 收缩右边界 37 | right-- 38 | if (left > right) break 39 | 40 | for (let i = right; i >= left; i--) res.push(matrix[down][i]) 41 | 42 | // 收缩下边界 43 | down-- 44 | if (up > down) break 45 | 46 | for (let i = down; i >= up; i--) res.push(matrix[i][left]) 47 | 48 | // 收缩左边界 49 | left++ 50 | if (left > right) break 51 | } 52 | 53 | return res 54 | }; 55 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/21-number-of-islands.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:岛屿数量 4 | * leetcode 题目: https://leetcode-cn.com/problems/number-of-islands/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/number-of-islands/solution/by-hovinghuang-d8tz/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/0c9664d1554e466aa107d899418e814e 7 | * 牛客网 题解: https://blog.nowcoder.net/n/73610fd87bd94e9590a4d71b9a898f79 8 | */ 9 | 10 | /** 11 | * 解法一:深度优先(递归) 12 | * 思路: 13 | * (1)当我们遇到矩阵的某个元素为1时,首先将其置为了0 14 | * (2)然后查看与它相邻的上下左右四个方向,如果这四个方向相邻元素为1,则进入该元素 15 | * (3)进入该元素之后我们发现又回到了刚刚的子问题,又是把这一片相邻区域的 1 全部置为 0 ,因此可以用递归实现。 16 | * 时间复杂度:O(nm),其中m、n为矩阵的长和宽,需要遍历整个矩阵,每次dfs搜索需要经过每个值为1的元素, 17 | * 但是最坏情况下也只是将整个矩阵变成0,因此相当于最坏遍历矩阵2次 18 | * 空间复杂度:0(nm),最坏情况下整个矩阵都是1,递归栈深度为 19 | */ 20 | function numIslands(grid: string[][]): number { 21 | const n = grid.length 22 | if (n === 0) return 0 23 | 24 | const m = grid[0].length 25 | let count = 0 26 | 27 | for (let i = 0; i < n; i++) { 28 | for (let j = 0; j < m; j++) { 29 | if (grid[i][j] === '1') { // 遍历到 1 的情况 30 | count++ // 计数 31 | dfs(grid, i, j) // 将于这个 1 相邻的所有 1 置为 0 32 | } 33 | } 34 | } 35 | 36 | return count 37 | }; 38 | function dfs(grid: string[][], i: number, j: number) { 39 | const n = grid.length 40 | const m = grid[0].length 41 | grid[i][j] = '0' 42 | 43 | if (i - 1 >= 0 && grid[i - 1][j] === '1') dfs(grid, i - 1, j) 44 | if (i + 1 < n && grid[i + 1][j] === '1') dfs(grid, i + 1, j) 45 | if (j - 1 >= 0 && grid[i][j - 1] === '1') dfs(grid, i, j - 1) 46 | if (j + 1 < m && grid[i][j + 1] === '1') dfs(grid, i, j + 1) 47 | } -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/27-maximum-depth-of-binary-tree.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:二叉树的最大深度 4 | * leetcode 题目: https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/solution/by-hovinghuang-3sz3/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/8a2b2bf6c19b4f23a9bdb9b233eefa73 7 | * 牛客网 题解: https://blog.nowcoder.net/n/b3939da0dc6f4d7792b0551539892e72 8 | */ 9 | 10 | /** 11 | * 解法一:递归 12 | * 思路: 13 | * (1)最大深度是所有叶子节点的深度的最大值,深度是指树的根节点到任一-叶子节点路径上节点的数量, 14 | * (2)因此从根节点每次往下一层深度就会加1。 15 | * (3)因此二叉树的深度就等于根结点这个1层加上左子树和右子树深度的最大值 16 | * 时间复杂度: O(n),其中n为二叉树的节点数,遍历整棵二叉树 17 | * 空间复杂度: O(n),最坏情况下,二叉树化为链表,递归栈深度最大为n 18 | */ 19 | function maxDepth(root: TreeNode | null): number { 20 | if (root == null) return 0 21 | return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1 22 | }; 23 | 24 | /** 25 | * 解法二:层次遍历 26 | * 思路: 27 | * 既然是统计二叉树的最大深度,除了根据路径到达从根节点到达最远的叶子节点以外,我 28 | * 们还可以分层统计。对于一棵二叉树而言,必然是一层一层的,那一层就是一个深度,有 29 | * 的层可能会很多节点,有的层如根节点或者最远的叶子节点,只有一个节点,但是不管多 30 | * 少个节点,它们都是一层。因此我们可以使用层次遍历,二叉树的层次遍历就是从上到下 31 | * 按层遍历,每层从左到右,我们只要每层统计层数即是深度。 32 | * 时间复杂度: O(n),其中n为二叉树的节点数,遍历整棵二叉树 33 | * 空间复杂度: O(n),辅助队列的空间最坏为n 34 | */ 35 | function maxDepth(root: TreeNode | null): number { 36 | if(root == null) return 0 37 | 38 | const queue: TreeNode[] = [] 39 | queue.push(root) 40 | let maxDep = 0 41 | 42 | while (!queue.length) { 43 | for (let i = 0; i < queue.length; i++) { 44 | const node = queue.shift() 45 | if (node.left) queue.push(node.left) 46 | if (node.right) queue.push(node.right) 47 | } 48 | maxDep++ 49 | } 50 | 51 | return maxDep 52 | }; 53 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/17-linked-list-cycle.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:环形链表 4 | * leetcode 题目: https://leetcode-cn.com/problems/linked-list-cycle/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/linked-list-cycle/solution/by-hovinghuang-ktep/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/650474f313294468a4ded3ce0f7898b9 7 | * 牛客网 题解: https://blog.nowcoder.net/n/ab8ae19d162a46c38761246e67aaf06f 8 | */ 9 | 10 | /** 11 | * 解法一:双指针 12 | * 思路: 13 | * (1)设置快慢两个指针,初始都指向链表头。 14 | * (2)遍历链表,快指针每次走两步,慢指针每次走一步。 15 | * (3)如果快指针到了链表末尾,说明没有环,因为它每次走两步,所以要验证连续两步是否为 NULL。 16 | * (4)如果链表有环,那快慢双指针会在环内循环,因为快指针每次走两步,因此快指针会在环内追到慢指针,二者相遇就代表有环。 17 | * 时间复杂度: O(n),最坏情况下遍历链表n个节点 18 | * 空间复杂度: O(1),仅使用了两个指针,没有额外辅助空间 19 | */ 20 | function hasCycle(head: ListNode | null): boolean { 21 | if (head == null) return false 22 | 23 | // 快慢双指针 24 | let fast: ListNode = head 25 | let slow: ListNode = head 26 | 27 | while (fast != null && fast.next != null) { // 快指针移动两步 28 | fast = fast.next.next // 慢指针移动一步 29 | slow = slow.next // 相遇则有环 30 | if (fast === slow) return true 31 | 32 | } 33 | 34 | return false // 到末尾则没有环 35 | }; 36 | 37 | /** 38 | * 解法二:哈希 39 | * 思路: 40 | * (1)使用哈希表来存储所有已经访问过的节点。 41 | * (2)每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。 42 | * (3)重复这一过程,直到我们遍历完整个链表即可。 43 | * 时间复杂度: O(n),最坏情况下遍历链表 n 个节点 44 | * 空间复杂度: O(n),其中 n 是链表中的节点数。主要为哈希表的开销,最坏情况下我们需要将每个节点插入到哈希表中一次。 45 | */ 46 | function hasCycle(head: ListNode | null): boolean { 47 | if (head == null) return false 48 | 49 | const seenMap = new Map() 50 | 51 | while (head != null) { 52 | if (seenMap.has(head)) return true 53 | seenMap.set(head, 1) 54 | head = head.next 55 | } 56 | 57 | return false 58 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/05-is-valid-brackets.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:有效括号序列 4 | * leetcode 题目: https://leetcode-cn.com/problems/valid-parentheses/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/valid-parentheses/solution/by-hovinghuang-6gz1/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/37548e94a270412c8b9fb85643c8ccc2?tpId=295&tqId=726&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295 7 | * 牛客网 题解: https://blog.nowcoder.net/n/620e933e59534064a9722bfa6da0c3d0 8 | */ 9 | 10 | /** 11 | * 解法一:栈 12 | * 思路: 13 | *(1)左括号,压栈 14 | *(2)右括号,则判断栈顶是否匹配(是否出栈)否则直接 return false 15 | * (3) 最后 return stack.length === 0 16 | * 时间复杂度:O(n),其中 n 为字符串长度 17 | * 空间复杂度:O(n),最坏情况下栈空间记录整个字符串长度的右括号 18 | */ 19 | function isMatch(left: string, right: string): boolean { 20 | if ((left === '{' && right === '}') 21 | || (left === '[' && right === ']') 22 | || (left === '(' && right === ')')) return true 23 | 24 | return false 25 | } 26 | export function isValid(s: string): boolean { 27 | const len = s.length 28 | if (len === 0) return true 29 | 30 | const stack = [] 31 | const leftSymbols = '{[(' 32 | const rightSymbols = ')]}' 33 | 34 | for (let i = 0; i < len; i++) { 35 | const char = s[i] 36 | 37 | if (leftSymbols.includes(char)) { 38 | // 左括号,压栈 39 | stack.push(char) 40 | } else if (rightSymbols.includes(char)) { 41 | // 右括号,判断栈顶(是否出栈) 42 | const top = stack[stack.length - 1] 43 | 44 | if (isMatch(top, char)) { 45 | stack.pop() 46 | } else { 47 | return false 48 | } 49 | } 50 | } 51 | 52 | return stack.length === 0 53 | } 54 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/26-binary-tree-inorder-traversal.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:二叉树的中序遍历 4 | * leetcode 题目: https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/by-hovinghuang-nd38/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/0bf071c135e64ee2a027783b80bf781d 7 | * 牛客网 题解: https://blog.nowcoder.net/n/e37c5bf59db341dab53094e6b43892eb 8 | */ 9 | 10 | /** 11 | * 解法一:递归 12 | * 思路:略 13 | * 时间复杂度: O(n),其中n为二叉树的节点数,遍历二叉树所有节点 14 | * 空间复杂度: O(n),最坏情况下二叉树化为链表,递归栈深度为n 15 | */ 16 | function inorderTraversal(root: TreeNode | null): number[] { 17 | const resArr: number[] = [] 18 | if (root == null) return resArr 19 | inOrder(root, resArr) 20 | return resArr 21 | }; 22 | function inOrder(node: TreeNode, resArr: number[]) { 23 | if (node == null) return 24 | inOrder(node.left, resArr) 25 | resArr.push(node.val) 26 | inOrder(node.right, resArr) 27 | }; 28 | 29 | /** 30 | * 解法二:非递归 31 | * 思路: 32 | * (1)准备辅助栈,当二叉树节点为空了且栈中没有节点了,我们就停止访问。 33 | * (2)从根节点开始,每次优先进入每棵的子树的最左边一个节点,我们将其不断加入栈中,用来保存父问题。 34 | * (3)到达最左后,可以开始访问,如果它还有右节点,则将右边也加入栈中,之后右子树的访问也是优先到最左。 35 | * 时间复杂度: O(n),其中n为二叉树的节点数,遍历二叉树所有节点 36 | * 空间复杂度: O(n),辅助栈空间最大为链表所有节点数 37 | */ 38 | function inorderTraversal(root: TreeNode | null): number[] { 39 | const resArr: number[] = [] 40 | if (root == null) return resArr 41 | inOrder(root, resArr) 42 | return resArr 43 | }; 44 | function inOrder(root: TreeNode, resArr: number[]) { 45 | let node: TreeNode = root 46 | const stack: TreeNode[] = [] 47 | while (stack.length || node) { 48 | while (node) { 49 | stack.push(node) 50 | node = node.left 51 | } 52 | const top = stack.pop() 53 | resArr.push(top.val) 54 | node = top.right 55 | } 56 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/25-longest-increasing-subsequence.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:最长递增子序列 4 | * leetcode 题目: https://leetcode-cn.com/problems/longest-increasing-subsequence/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/by-hovinghuang-thvh/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/5164f38b67f846fb8699e9352695cd2f 7 | * 牛客网 题解: https://blog.nowcoder.net/n/df338bdebd0e4101b41b1978f6f3f98a 8 | */ 9 | 10 | /** 11 | * 解法一:动态规划 12 | * 思路: 13 | * 时间复杂度:O(n^2),其中 n 为数组 nums 的长度。 14 | * 空间复杂度:O(n),需要额外使用长度为 n 的 dp 数组。 15 | */ 16 | function lengthOfLIS(nums: number[]): number { 17 | if (nums.length == 0) return 0 18 | 19 | const dp: number[] = [] 20 | dp[0] = 1 21 | let maxans = 1 22 | 23 | for (let i = 1; i < nums.length; i++) { 24 | dp[i] = 1 25 | for (let j = 0; j < i; j++) { 26 | if (nums[i] > nums[j]) dp[i] = Math.max(dp[i], dp[j] + 1) 27 | } 28 | maxans = Math.max(maxans, dp[i]) 29 | } 30 | 31 | return maxans 32 | }; 33 | 34 | /** 35 | * 解法二:贪心 + 二分查找 36 | * 思路: 37 | * 时间复杂度:O(nlogn) 38 | * 空间复杂度:O(n) 39 | */ 40 | function lengthOfLIS(nums: number[]): number { 41 | if (nums.length == 0) return 0 42 | 43 | let len = 1 44 | let n = nums.length 45 | const d: number[] = [] 46 | d[len] = nums[0] 47 | for (let i = 1; i < n; ++i) { 48 | if (nums[i] > d[len]) { 49 | d[++len] = nums[i] 50 | } else { 51 | let l = 1 52 | let r = len 53 | let pos = 0 54 | while (l <= r) { 55 | let mid = (l + r) >> 1 56 | if (d[mid] < nums[i]) { 57 | pos = mid 58 | l = mid + 1 59 | } else { 60 | r = mid - 1 61 | } 62 | } 63 | d[pos + 1] = nums[i] 64 | } 65 | } 66 | 67 | return len 68 | }; 69 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/06-two-sum.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:两数之和 4 | * leetcode 题目: https://leetcode-cn.com/problems/two-sum/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/two-sum/solution/by-hovinghuang-8jqr/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/20ef0972485e41019e39543e8e895b7f?tpId=295&tqId=745&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295 7 | * 牛客网 题解: https://blog.nowcoder.net/n/61a9e5d2ac2f46db9f6f9e324faab016 8 | */ 9 | 10 | /** 11 | * 解法一:双层循环 12 | * 思路:详情看以下代码 13 | * 时间复杂度:O(n^2),双层循环 14 | * 空间复杂度:O(1) 15 | * 注意:如果这里的 nums 是有序的话,优化嵌套循环,可以考虑 “双指针” 16 | */ 17 | function twoSum(nums: number[], target: number): number[] { 18 | const res: number[] = [] 19 | const len = nums.length 20 | if (len === 0) return res 21 | 22 | for (let i = 0; i < len - 1; i++) { 23 | const n1 = nums[i] 24 | let flag = false // 是否得到结果 25 | 26 | for (let j = i + 1; j < len; j++) { 27 | const n2 = nums[j] 28 | if (n1 + n2 === target) { 29 | res.push(i) 30 | res.push(j) 31 | flag = true 32 | break 33 | } 34 | } 35 | 36 | if (flag) break 37 | } 38 | 39 | return res 40 | }; 41 | 42 | /** 43 | * 解法二:哈希 44 | * 思路:遍历的同时借助哈希表,记录值和下标 45 | * 时间复杂度:O(n),最多遍历数组一遍,每次查询哈希表都是O(1) 46 | * 空间复杂度:O(n),最坏情况下找到数组结尾才找到,其他都加入哈希表,哈希表最长 n - 1 47 | */ 48 | function twoSum(nums: number[], target: number): number[] { 49 | const res: number[] = [] 50 | const len = nums.length 51 | if (len === 0) return res 52 | 53 | const map = new Map() 54 | 55 | for (let i = 0; i < len; i++) { 56 | const temp = target - nums[i] 57 | if (!map.has(temp)) { 58 | map.set(nums[i], i) 59 | } else { 60 | res.push(map.get(temp)) 61 | res.push(i) 62 | return res 63 | } 64 | } 65 | 66 | return res 67 | }; 68 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/23-merge-two-sorted-linked-lists.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:合并两个有序链表 4 | * leetcode 题目: https://leetcode-cn.com/problems/merge-two-sorted-lists/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/by-hovinghuang-zg0e/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/d8b6b4358f774294a89de2a6ac4d9337 7 | * 牛客网 题解: https://blog.nowcoder.net/n/ac49c082300d434898511f8c26bdc26d 8 | */ 9 | 10 | /** 11 | * 解法一:迭代 12 | * 思路: 13 | * (1)新建一个空的表头后面连接两个链表排序后的结点。 14 | * (2)遍历两个链表都不为空的情况,取较小值添加在新的链表后面,每次只把被添加的链表的指针后移。 15 | * (3)遍历到最后肯定有一个链表还有剩余的结点,它们的值将大于前面所有的,直接连在新的链表后面即可。 16 | * 时间复杂度: O(n),最坏情况遍历2 * n个结点 17 | * 空间复杂度: 0(1),无额外空间使用,新建的链表属于返回必要空间 18 | */ 19 | function mergeTwoLists(list1: ListNode | null, list2: ListNode | null): ListNode | null { 20 | if (list1 == null) return list2 21 | if (list2 == null) return list1 22 | 23 | let head: ListNode = new ListNode() // 加一个表头 24 | let cur: ListNode = head 25 | 26 | while (list1 != null && list2 != null) { 27 | if (list1.val <= list2.val) { // 取较小值的节点 28 | cur.next = list1 29 | list1 = list1.next // 移动取值的指针 30 | } else { 31 | cur.next = list2 32 | list2 = list2.next 33 | } 34 | cur = cur.next // 指针后移 35 | } 36 | 37 | if (list1 != null) cur.next = list1 38 | if (list2 != null) cur.next = list2 39 | 40 | return head.next // 返回值去掉表头 41 | }; 42 | 43 | /** 44 | * 解法二:递归 45 | * 思路: 46 | * (1)每次比较两个链表当前结点的值,然后取较小值的链表指针往后,另一个不变送入递归中。 47 | * (2)递归回来的结果我们要加在当前较小值的结点后面,相当于不断在较小值后面添加结点。 48 | * (3)递归的终止是两个链表为空。 49 | * 时间复杂度: O(n),最坏相当于遍历两个链表每个结点一次 50 | * 空间复杂度: O(n), 递归栈长度最大为 n 51 | */ 52 | function mergeTwoLists(list1: ListNode | null, list2: ListNode | null): ListNode | null { 53 | if (list1 == null) return list2 54 | if (list2 == null) return list1 55 | 56 | if (list1.val <= list2.val) { // 先用较小的值的节点 57 | list1.next = mergeTwoLists(list1.next, list2) 58 | return list1 59 | } else { 60 | list2.next = mergeTwoLists(list1, list2.next) 61 | return list2 62 | } 63 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/02-merge-sorted-arr.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:合并两个有序的数组 4 | * leetcode 题目: https://leetcode-cn.com/problems/merge-sorted-array/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/merge-sorted-array/solution/by-hovinghuang-58f6/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/89865d4375634fc484f3a24b7fe65665?tpId=295&tqId=658&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295 7 | * 牛客网 题解: https://blog.nowcoder.net/n/950d8331e9004749adc1a3d98a5ec29f 8 | */ 9 | 10 | /** 11 | * 解法一:JS Sort 12 | * 思路: 13 | * (1)先判断 B 为空直接 return,A 为空则将 B shift 到 A 中 14 | * (2)将 B shift 填到 A 尾部的扩容区域,然后用 sort 排序 15 | * 时间复杂度:O(nlogn), JS sort 方法基于快速排序实现 16 | * 空间复杂度:O(1),常数级变量,无额外空间 17 | */ 18 | export function merge(A: number[], m: number, B: number[], n: number) { 19 | if (!B.length || !n) return 20 | 21 | for (let i = m; i < m + n; i++) { 22 | A[i] = B.shift() 23 | } 24 | 25 | // 升序排列 26 | A.sort((a, b) => a - b) 27 | } 28 | 29 | /** 30 | * 解法二:双指针 31 | * 思路: 32 | * (1)先判断 B 为空直接 return,A 为空则将 B shift 到 A 中 33 | * (2)使用三个指针,aIndex 指向数组 A 的最大元素,bIndex 指向数组B的最大元素,mIndex 指向数组A空间的结尾处。 34 | * (3)从两个数组最大的元素开始遍历,直到某一个结束,每次取出较大的一个值放入数组 A 空间的最后,然后指针依次往前。 35 | * (4)如果数组 B 先遍历结束,数组 A 前半部分已经存在了,不用管;但是如果数组 A 先遍历结束,则需要把数组 B 剩余的前半部分依次逆序加入数组 A 前半部分 36 | * 时间复杂度:O(m + n),最坏情况遍历整个数组 A 和 数组 B 37 | * 空间复杂度:O(1),常数级变量,无额外空间 38 | */ 39 | export function merge(A: number[], m: number, B: number[], n: number) { 40 | if (!B.length || !n) return 41 | if (!A.length || !m) { 42 | for (let i = 0; i < n; i++) { 43 | A[i] = B.shift() 44 | } 45 | } 46 | 47 | let aIndex: number = m - 1 // 指向数组 A 的结尾 48 | let bIndex: number = n - 1 // 指向数组 B 的结尾 49 | let mIndex: number = m + n - 1 // 指向数组 A 空间的结尾 50 | 51 | while (aIndex >= 0 && bIndex >= 0) { 52 | if (A[aIndex] >= B[bIndex]) { 53 | A[mIndex--] = A[aIndex--] 54 | } else { 55 | A[mIndex--] = B[bIndex--] 56 | } 57 | 58 | // 数组 A 遍历完,B 还有 59 | if (aIndex < 0) { 60 | while (bIndex >= 0) { 61 | A[mIndex--] = B[bIndex--] 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/11-path-sum.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:路径总和 4 | * leetcode 题目: https://leetcode-cn.com/problems/path-sum/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/path-sum/solution/by-hovinghuang-ax6m/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/508378c0823c423baa723ce448cbfd0c 7 | * 牛客网 题解: https://blog.nowcoder.net/n/b763226e0fd74c01a2a643a10db22c7b 8 | */ 9 | 10 | /** 11 | * 解法一:递归(先序遍历) 12 | * 思路: 13 | * 既然是检查从根到叶子有没有一-条等于目标值的路径,那肯定需要从根节点遍历到叶子, 14 | * 我们可以在根节点每次往下一层的时候,将sum减去节点值,最后检查是否完整等于0.而 15 | * 遍历的方法我们可以选取二叉树常用的递归先序遍历,因为每次进入一个子节点,更新 16 | * sum值以后,相当于对子树查找有没有等于新目标值的路径,因此这就是子问题 17 | * 时间复杂度:O(n),先序遍历二叉树所有结点 18 | * 空间复杂度:O(n),最坏情况二叉树化为链表,递归栈空间最大为n 19 | */ 20 | function hasPathSum(root: TreeNode | null, targetSum: number): boolean { 21 | if (root == null) return false 22 | if (root.left == null && root.right == null && root.val === targetSum) return true 23 | return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val) 24 | }; 25 | 26 | /** 27 | * 解法二:非递归(DFS) 28 | * 思路: 29 | * 在二叉树中能够用递归解决的问题,很多时候我们也可以用非递归来解决。这里遍历过程 30 | * 也可以使用栈辅助,进行dfs遍历,检查往下的路径中是否有等于sum的路径和。 31 | * 注意,这里仅是dfs,而不是先序遍历,左右节点的顺序没有关系,因为每次往下都是单 32 | * 独添加某个节点的值相加然后继续往下,因此左右节点谁先遍历不管用。 33 | * 时间复杂度:O(n),DFS遍历二叉树所有结点 34 | * 空间复杂度:O(n),最坏情况二叉树化为链表,递归栈空间最大为n 35 | */ 36 | function hasPathSum(root: TreeNode | null, targetSum: number): boolean { 37 | if (root == null) return false 38 | const treeNodeStack: TreeNode[] = [] 39 | const valueStack: number[] = [] 40 | treeNodeStack.push(root) 41 | valueStack.push(root.val) 42 | 43 | while (treeNodeStack.length) { 44 | const node = treeNodeStack.pop() // 弹出相应节点 45 | const valSum = valueStack.pop() // 获取到该节点为止的路径和 46 | 47 | // 是叶子结点且当前路径和等于 valSum 48 | if (node.left == null && node.right == null && valSum === targetSum) return true 49 | 50 | // 左节点&对应路径和入栈 51 | if (node.left != null) { 52 | treeNodeStack.push(node.left) 53 | valueStack.push(node.left.val + valSum) 54 | } 55 | 56 | // 右节点&对应路径和入栈 57 | if (node.right != null) { 58 | treeNodeStack.push(node.right) 59 | valueStack.push(node.right.val + valSum) 60 | } 61 | } 62 | 63 | return false 64 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/09-max-sub-array.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:大子数组和(连续子数组的最大和) 4 | * leetcode 题目: https://leetcode-cn.com/problems/maximum-subarray/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/maximum-subarray/solution/by-hovinghuang-exw9/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/459bd355da1549fa8a49e350bf3df484 7 | * 牛客网 题解: https://blog.nowcoder.net/n/8d36ffcdc332432197d9f44e6af0e78c 8 | */ 9 | 10 | /** 11 | * 解法一:暴力解法(双层循环) 12 | * 思路:求出所有可能,维护最大值 max 13 | * 时间复杂度:O(n^2) 超标不可用 14 | * 空间复杂度: 15 | */ 16 | function maxSubArray(nums: number[]): number { 17 | const len = nums.length 18 | if (len === 0) return 0 19 | if (len === 1) return nums[0] 20 | 21 | let i = 0 22 | let j = i 23 | let max = 0 24 | let temp = 0 25 | while (i < len) { 26 | if (j === len - 1) { 27 | i++ 28 | j = i + 1 29 | temp = 0 30 | } else { 31 | temp = temp + nums[j] 32 | max = Math.max(max, temp) 33 | j++ 34 | } 35 | } 36 | 37 | return max 38 | }; 39 | 40 | /** 41 | * 解法二:动态规划 42 | * 思路: 43 | * 可以用dp数组表示以下标i为终点的最大连续子数组和。 44 | * 每次遇到一个新的数组元素,连续的子数组要么加,上变得更大,要么它本 45 | * 身就更大,因此状态转移为dp[i] = max(dp[i - 1] + array[i], array[i])。 46 | * 遍历数组,每次只要比较取最大值即可。 47 | * 时间复杂度:O(n),遍历一遍。 48 | * 空间复杂度:O(n),动态规划辅助数组长度为n 49 | */ 50 | function maxSubArray(nums: number[]): number { 51 | const len = nums.length 52 | if (len === 0) return 0 53 | 54 | const dp: number[] = [] 55 | dp[0] = nums[0] 56 | let maxSum = dp[0] 57 | 58 | for (let i = 1; i < len; i++) { 59 | dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]) 60 | maxSum = Math.max(maxSum, dp[i]) 61 | } 62 | 63 | return maxSum 64 | }; 65 | 66 | /** 67 | * 解法三:动态规划空间优化 68 | * 思路: 69 | * 我们注意到方法一的动态规划在状态转移的时候只用到了i一1的信息,没有使用整个数组的信息。 70 | * 我们可以使用两个变量迭代来代替数组。 71 | * 状态转移的时候更新变量y,该轮循环结束的再更新x为y即可做到每次迭代都是上一轮的dp。 72 | * 遍历数组,每次只要比较取最大值即可。 73 | * 时间复杂度:O(n),遍历一遍。 74 | * 空间复杂度:O(1),常数变量 75 | */ 76 | function maxSubArray(nums: number[]): number { 77 | const len = nums.length 78 | if (len === 0) return 0 79 | 80 | let x = nums[0] 81 | let y = 0 82 | let maxSum = x 83 | 84 | for (let i = 1; i < len; i++) { 85 | y = Math.max(nums[i], x + nums[i]) 86 | maxSum = Math.max(maxSum, y) 87 | x = y 88 | } 89 | 90 | return maxSum 91 | }; 92 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/20-binary-search.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:二分搜索 4 | * leetcode 题目: https://leetcode-cn.com/problems/binary-search/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/binary-search/solution/by-hovinghuang-ks00/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/d3df40bd23594118b57554129cadf47b? 7 | * 牛客网 题解: https://blog.nowcoder.net/n/18779274e55745b682ab9be9bb9f438d 8 | */ 9 | 10 | /** 11 | * 解法一:循环 12 | * 思路: 13 | * (1)从数组首尾开始,每次取中点值。 14 | * (2)如果中间值等于目标即找到了,可返回下标,如果中点值大于目标, 15 | * 说明中点以后的都大于目标,因此目标在中点左半区间,如果中点值小于目标,则相反。 16 | * (3)根据比较进入对应的区间,直到区间左右端相遇,意味着没有找到。 17 | * 时间复杂度:O(log2n),对长度为n的数组进行二分,最坏情况就是取 2 的对数 18 | * 空间复杂度:0(1),无额外空间 19 | */ 20 | function search(nums: number[], target: number): number { 21 | const len = nums.length 22 | if (len === 0) return -1 23 | 24 | let startIndex = 0 25 | let endIndex = len - 1 26 | 27 | while (startIndex <= endIndex) { 28 | const midIndex = Math.floor((startIndex + endIndex) / 2) // 将数字向下舍入到最接近的整数 29 | const midValue = nums[midIndex] 30 | 31 | if (target < midValue) { 32 | // 目标值较少,则继续在左侧查找 33 | endIndex = midIndex - 1 34 | } else if (target > midValue) { 35 | // 目标值较大,则继续在右侧查找 36 | startIndex = midIndex + 1 37 | } else { 38 | return midIndex 39 | } 40 | } 41 | 42 | return -1 43 | }; 44 | 45 | /** 46 | * 解法二:递归 47 | * 思路: 48 | * (1)从数组首尾开始,每次取中点值。 49 | * (2)如果中间值等于目标即找到了,可返回下标,如果中点值大于目标,说明中点以后的都大于目标, 50 | * 因此目标在中点左半区间,如果中点值小于目标,则相反。 51 | * (3)根据比较进入对应的区间,直到区间左右端相遇,意味着没有找到。 52 | * 时间复杂度:O(log2n),对长度为n的数组进行二分,最坏情况就是取2的对数 53 | * 空间复杂度:0(1) 54 | */ 55 | function search(nums: number[], target: number, startIndex?: number, endIndex?: number): number { 56 | const len = nums.length; 57 | if (len === 0) return -1; 58 | 59 | // 开始和结束的范围 60 | if (startIndex == null) startIndex = 0 61 | if (endIndex == null) endIndex = len - 1 62 | 63 | // 如果 start 和 end 相遇则结束 64 | if (startIndex > endIndex) return -1 65 | 66 | // 中间位置 67 | const midIndex = Math.floor((startIndex + endIndex) / 2) 68 | const midValue = nums[midIndex] 69 | 70 | if (target < midValue) { 71 | // 目标值较小,则继续在左侧查找 72 | return search(nums, target, startIndex, midIndex - 1) 73 | } else if (target > midValue) { 74 | // 目标值较大,则继续在右侧查找 75 | return search(nums, target, midIndex + 1, endIndex) 76 | } else { 77 | // 相等,返回 78 | return midIndex 79 | } 80 | }; -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/19-sum-root-to-leaf-numbers.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:求根节点到叶节点数字之和 4 | * leetcode 题目: https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/solution/by-hovinghuang-fq9e/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/185a87cd29eb42049132aed873273e83 7 | * 牛客网 题解: https://blog.nowcoder.net/n/08dbb5d39ecb4776889e7d8a7f31f736 8 | */ 9 | 10 | /** 11 | * 解法一:深度优先搜索 12 | * 思路: 13 | * (1)从根节点开始,遍历每个节点,如果遇到叶子节点,则将叶子节点对应的数字加到数字之和。 14 | * (2)如果当前节点不是叶子节点,则计算其子节点对应的数字,然后对子节点递归遍历。 15 | * 时间复杂度:O(n),其中 n 是二叉树的节点个数。对每个节点访问一次。 16 | * 空间复杂度:O(n),其中 n 是二叉树的节点个数。空间复杂度主要取决于递归调用的栈空间,递归栈的深度等于二叉树的高度, 17 | * 最坏情况下,二叉树的高度等于节点个数,空间复杂度为 O(n)。 18 | */ 19 | function sumNumbers(root: TreeNode | null): number { 20 | return dfs(root, 0) 21 | } 22 | function dfs(root: TreeNode | null, prevSum: number): number { 23 | if (root === null) return 0 24 | 25 | const sum = prevSum * 10 + root.val 26 | 27 | if (root.left === null && root.right === null) { 28 | return sum 29 | } else { 30 | return dfs(root.left, sum) + dfs(root.right, sum) 31 | } 32 | 33 | } 34 | 35 | /** 36 | * 解法二:BFS 37 | * 思路: 38 | * 使用广度优先搜索,需要维护两个队列,分别存储节点和节点对应的数字。 39 | * 初始时,将根节点和根节点的值分别加入两个队列。每次从两个队列分别取出一个节点和一个数字,进行如下操作: 40 | * (1)如果当前节点是叶子节点,则将该节点对应的数字加到数字之和; 41 | * (2)如果当前节点不是叶子节点,则获得当前节点的非空子节点,并根据当前节点对应的数字和子节点的值计算子节点对应的数字, 42 | * 然后将子节点和子节点对应的数字分别加入两个队列。 43 | * 时间复杂度:O(n),其中 n 是二叉树的节点个数。对每个节点访问一次。 44 | * 空间复杂度:O(n),其中 n 是二叉树的节点个数。空间复杂度主要取决于递归调用的栈空间,递归栈的深度等于二叉树的高度, 45 | * 最坏情况下,二叉树的高度等于节点个数,空间复杂度为 O(n)。 46 | */ 47 | function sumNumbers(root: TreeNode | null): number { 48 | if (root === null) return 0 49 | 50 | let sum = 0 51 | const nodeQueue: TreeNode[] = [] 52 | const numQueue: number[] = [] 53 | nodeQueue.push(root) 54 | numQueue.push(root.val) 55 | while (nodeQueue.length) { 56 | const node = nodeQueue.shift() 57 | const num = numQueue.shift() 58 | const left = node.left 59 | const right = node.right 60 | if (left === null && right === null) { 61 | sum += num 62 | } else { 63 | if (left !== null) { 64 | nodeQueue.push(left) 65 | numQueue.push(num * 10 + left.val) 66 | } 67 | if (right !== null) { 68 | nodeQueue.push(right) 69 | numQueue.push(num * 10 + right.val) 70 | } 71 | } 72 | } 73 | 74 | return sum 75 | } -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/15-best-time-to-buy-and-sell-stock.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:买卖股票的最佳时机 4 | * leetcode 题目: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/by-hovinghuang-6qhi/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/64b4262d4e6d4f6181cd45446a5821ec 7 | * 牛客网 题解: https://blog.nowcoder.net/n/4430ac0f65294e019d48345423b7e62f 8 | */ 9 | 10 | /** 11 | * 解法一:暴力法(嵌套循环) 12 | * 思路: 13 | * (1)我们需要找出给定数组中两个数字之间的最大差值(即,最大利润)。 14 | * (2)此外,第二个数字(卖出价格)必须大于第一个数字(买入价格)。 15 | * 时间复杂度:O(n^2)。 16 | * 空间复杂度:0(1),只使用了一个常数变量。 17 | */ 18 | function maxProfit(prices: number[]): number { 19 | let maxprofit = 0 20 | 21 | for (let i = 0; i < prices.length - 1; i++) { 22 | for (let j = i + 1; j < prices.length; j++) { 23 | let profit = prices[j] - prices[i] 24 | maxprofit = Math.max(maxprofit, profit) 25 | } 26 | } 27 | 28 | return maxprofit 29 | }; 30 | 31 | /** 32 | * 解法二:贪心 33 | * 思路: 34 | * (1)将第一天看成价格最低,后续遍历的时候遇到价格更低则更新价格最低, 35 | * (2)每次都比较最大收益与当日价格减去价格最低的值,选取最大值作为最大收益 36 | * 时间复杂度:O(n)。 37 | * 空间复杂度:0(1),只使用了常数变量。 38 | */ 39 | function maxProfit(prices: number[]): number { 40 | let maxprofit = 0 41 | if (prices.length === 0) return maxprofit 42 | 43 | let minprice = prices[0] // 维护最低股票价格 44 | 45 | for (let i = 0; i < prices.length; i++) { 46 | minprice = Math.min(minprice, prices[i]) 47 | maxprofit = Math.max(maxprofit, prices[i] - minprice) 48 | } 49 | 50 | return maxprofit 51 | }; 52 | 53 | /** 54 | * 解法三:动态规划 55 | * 思路: 56 | * (1)用dp[i[0]表示 第i天不持股到该天为止的最大收益,dp[i][1]表 示第i天持股,到该天为止的最大收益。 57 | * (2)(初始状态) 第一 天不持股,则总收益为0,dp[0][0]=0; 第- -天持股,则总收益为买股票的花费,此时为负数,dp[0][1] = - prices[0]。 58 | * (3)(状态转移) 对于之后的每一天,如果当天不持股,有可能是前面的若干天中卖掉了或是还没买,因此到此为止的总收益和前一天相同,也有可能是当天才 59 | * 卖掉,我们选择较大的状态dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]) 60 | * (4) 如果当天持股,有可能是前面若千天中买了股票,当天还没卖,因此收益与前一天相同,也有可能是当天买入,此时收益为负的股价,同样是选取最大值:dp[i][1] = max(dp[i - 1][1], -prices[i])。 61 | * 时间复杂度:O(n),遍历一次数组 62 | * 空间复杂度:0(n),动态规划富足数组的空间。 63 | */ 64 | function maxProfit(prices: number[]): number { 65 | const len = prices.length 66 | if (len === 0) return 0 67 | 68 | const dp: number[][] = [] // dp[i][0]表示某一天不持股到该天为止的最大收益,dp[i] [1]表示某天持股,到该天为止的最大收益 69 | for (let i = 0; i < len; i++) { 70 | dp[i]= [] 71 | } 72 | dp[0][0] = 0 // 第一天不持股,总收益为0 73 | dp[0][1] = - prices[0] // 第一天持股,总收益为减去该天的股价 74 | 75 | for (let i = 1; i < len; i++) { // 遍历后续每天,状态转移 76 | dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]) 77 | dp[i][1] = Math.max(dp[i - 1][1], - prices[i]) 78 | } 79 | 80 | return dp[len - 1][0] // 最后一天不持股,到该天为止的最大收益 81 | }; 82 | 83 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/01-length-of-longest-substring.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:无重复字符的最长子串(类似题目:最长无重复子数组) 4 | * leetcode 题目: https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/by-hovinghuang-qugo/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/b56799ebfd684fb394bd315e89324fb4?tpId=295&tqId=1008889&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295 7 | * 牛客网 题解: https://blog.nowcoder.net/n/fce41b44190449f18c605a0a41db9c78 8 | */ 9 | 10 | /** 11 | * 解法一:滑动窗口(reduce累加器) 12 | * 思路: 13 | * (1)先判断字符串 s 的长度,如果 s.length <= 1 直接返回 s.length 14 | * (2)将字符串 s 转成数组,这样就可以用数组的 reduce 累加器 15 | * (3)reduce 滑动窗口过程处理(详细过程看以下代码),返回最长子串的长度 maxLen 16 | * 时间复杂度:O(n),n 代表字符串长度,reduce 会将字符串的每一个字符都遍历一遍 17 | * 空间复杂度:O(n),n 代表字符串长度,将字符串转成了数组(额外空间) 18 | */ 19 | function lengthOfLongestSubstring(s: string): number { 20 | if (s.length <= 1) return s.length 21 | 22 | let maxLen = 0 23 | const strArr = s.split('') 24 | 25 | strArr.reduce((total, value) => { 26 | const index = total.indexOf(value) 27 | 28 | // 拼接到 total 尾部 29 | total += value 30 | 31 | if (index === -1) { 32 | // 如果该字符没有在 total 中出现过,获取目前为止滑动窗口的最大值 33 | maxLen = Math.max(total.length, maxLen) 34 | } else { 35 | // 如果该字符有在 total 中出现过,则剔除掉 total 中 0 ~ index 的字符 36 | total = total.slice(index + 1) 37 | } 38 | 39 | return total 40 | }, '') 41 | 42 | return maxLen 43 | }; 44 | 45 | /** 46 | * 解法二:滑动窗口(双指针&哈希) 47 | * 思路: 48 | * (1)先判断字符串 s 的长度,如果 s.length <= 1 直接返回 s.length 49 | * (2)窗口左右界都从数组首部开始,每次窗口优先右移右界,并统计进入窗口的元素的出现频率。 50 | * (3)一旦右界元素出现频率大于1,就需要右移左界直到窗口内不再重复,将左边的元素移除窗口的时候 51 | * 同时需要将它在哈希表中的频率减1,保证哈希表中的频率都是窗口内的频率。 52 | * (4)每轮循环维护最长子串的长度 maxLen 53 | * 时间复杂度:O(n),外循环窗口右界从数组首右移到数组尾,内循环窗口左界同样如此,因此复杂度为O(n + n) = O(n) 54 | * 空间复杂度:O(n),最坏情况整个数组都是不重复的,哈希表的长度就是数组长度 55 | */ 56 | function lengthOfLongestSubstring(s: string): number { 57 | if (s.length <= 1) return s.length 58 | 59 | let maxLen = 0 60 | const map = new Map() 61 | 62 | // 设置窗口左右边界 63 | for (let left = 0, right = 0; right < s.length; right++) { 64 | if (map.has(s[right])) { 65 | // 窗口右移进入哈希表统计次数 66 | map.set(s[right], map.get(s[right]) + 1) 67 | } else { 68 | map.set(s[right], 1) 69 | } 70 | 71 | // 出现次数大于1,则窗口内有重复 72 | while (map.get(s[right]) > 1) { 73 | // 窗口左移,同时减去该数字出现的次数 74 | map.set(s[left], map.get(s[left++]) - 1) 75 | } 76 | 77 | maxLen = Math.max(maxLen, right - left + 1) 78 | } 79 | 80 | return maxLen 81 | }; 82 | -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/18-longest-palindromic-substring.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:最长回文子串 4 | * leetcode 题目: https://leetcode-cn.com/problems/longest-palindromic-substring/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/longest-palindromic-substring/solution/by-hovinghuang-0ru8/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/b4525d1d84934cf280439aeecc36f4af 7 | * 牛客网 题解: https://blog.nowcoder.net/n/2759f3a8d3d742a7aca16768d196fc21 8 | */ 9 | 10 | /** 11 | * 解法一:动态规划 12 | * 思路:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/ 13 | * 时间复杂度:O(n^2),其中 n 是字符串的长度。动态规划的状态总数为 O(n^2),对于每个状态,我们需要转移的时间为 O(1)。 14 | * 空间复杂度:O(n^2),即存储动态规划状态需要的空间。 15 | */ 16 | function longestPalindrome(s: string): string { 17 | const len = s.length 18 | if (len < 2) return s 19 | 20 | let maxLen = 1 21 | let begin = 0 22 | // dp[i][j] 表示 s[i..j] 是否是回文串 23 | const dp: boolean[][] = [] 24 | for (let i = 0; i < len; i++) { 25 | dp[i] = [] 26 | } 27 | // 初始化:所有长度为 1 的子串都是回文串 28 | for (let i = 0; i < len; i++) { 29 | dp[i][i] = true 30 | } 31 | const charArray = s.split('') 32 | // 递推开始 33 | // 先枚举子串长度 34 | for (let L = 2; L <= len; L++) { 35 | // 枚举左边界,左边界的上限设置可以宽松一些 36 | for (let i = 0; i < len; i++) { 37 | // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得 38 | let j = L + i - 1 39 | // 如果右边界越界,就可以退出当前循环 40 | if (j >= len) break 41 | 42 | if (charArray[i] != charArray[j]) { 43 | dp[i][j] = false 44 | } else { 45 | if (j - i < 3) { 46 | dp[i][j] = true 47 | } else { 48 | dp[i][j] = dp[i + 1][j - 1] 49 | } 50 | } 51 | 52 | // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置 53 | if (dp[i][j] && j - i + 1 > maxLen) { 54 | maxLen = j - i + 1 55 | begin = i 56 | } 57 | } 58 | } 59 | 60 | return s.substring(begin, begin + maxLen) 61 | }; 62 | 63 | /** 64 | * 解法二:中心扩展算法 65 | * 思路:如果是回文子串,那么它的左右两边的元素肯定是对称的,我们可以使用左右指针,从当前元素向两边扩散,以找到最长字串。 66 | * 时间复杂度:O(n^2)。 67 | * 空间复杂度:O(1)。 68 | */ 69 | function longestPalindrome(s: string): string { 70 | let res = '' 71 | for (let i = 0; i < s.length; i++) { 72 | const str1 = palindrome(s, i, i) 73 | const str2 = palindrome(s, i, i + 1) 74 | res = res.length > str1.length ? res : str1 75 | res = res.length > str2.length ? res : str2 76 | } 77 | return res 78 | }; 79 | function palindrome(s: string, left: number, right: number): string { 80 | // 左右指针,从s[l]和s[r]向两边扩散,找到最长回文串 81 | while (left >= 0 && right < s.length && s[left] === s[right]) { 82 | left-- 83 | right++ 84 | } 85 | return s.substr(left + 1, right - left - 1) 86 | } -------------------------------------------------------------------------------- /src/00-codetop-fontend-100/12-binary-tree-level-order-traversal.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /** 3 | * 题目名称:二叉树的层序遍历 4 | * leetcode 题目: https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ 5 | * leetcode 题解: https://leetcode-cn.com/problems/binary-tree-level-order-traversal/solution/by-hovinghuang-1hvt/ 6 | * 牛客网 题目: https://www.nowcoder.com/practice/04a5560e43e24e9db4595865dc9c63a3 7 | * 牛客网 题解: https://blog.nowcoder.net/n/10b0073f1d0043eba3d0f9646e43bbb4 8 | */ 9 | 10 | /** 11 | * 解法一:非递归(BFS) 12 | * 思路: 13 | * (1)首先判断二叉树是否为空,空树没有遍历结果。 14 | * (2)建立辅助队列,根节点首先进入队列。不管层次怎么访问,根节点一定是.第一个,那它肯定排在队伍的最前面。 15 | * (3)每次进入一层,统计队列中元素的个数。因为每当访问完一一层,下一-层作为这一层的子节点, 16 | * 一定都加入队列,而再下一层还没有加入,因此此时队列中的 17 | * (4)每次遍历这一层这么多的节点数,将其依次从队列中弹出,然后加入这一行的一维数组中,如果它们有子节点, 18 | * 依次加入队列排队等待访问。元素个数就是这-层的元素个数。 19 | * (5)访问完这-层的元素后,将这个一维数组加入二维数组中,再访问下一层。 20 | * 时间复杂度: O(n),其中n为二叉树的节点数,每个节点访问一次 21 | * 空间复杂度: O(n),队列的空间为二叉树的一-层的节点数,最坏情况二叉树的一层为O(n)级 22 | */ 23 | function levelOrder(root: TreeNode | null): number[][] { 24 | const resArr: number[][] = new Array() 25 | const strArr: string[] = [] 26 | if (root == null) return resArr 27 | 28 | const queue: TreeNode[] = [] 29 | 30 | queue.unshift(root) 31 | 32 | while (queue.length) { 33 | const row: number[] = [] 34 | const len = queue.length 35 | for (let i = 0; i < len; i++) { 36 | const curNode = queue.pop() 37 | row.push(curNode.val) 38 | if (curNode.left != null) queue.unshift(curNode.left) 39 | if (curNode.right != null) queue.unshift(curNode.right) 40 | } 41 | strArr.push(row.toString()) 42 | } 43 | 44 | for (let i = 0; i < strArr.length; i++) { 45 | const rowNum: number[] = [] 46 | strArr[i].split(',').forEach((item) => { 47 | rowNum.push(parseInt(item)) 48 | }) 49 | resArr[i] = rowNum 50 | } 51 | 52 | return resArr 53 | }; 54 | 55 | /** 56 | * 解法二:递归 57 | * 思路: 58 | * 既然二叉树的前序、中序、后序遍历都可以轻松用递归实现,树型结构本来就是递归喜欢 59 | * 的形式,那我们的层次遍历是不是也可以尝试用递归来试试呢?按行遍历的关键是每一-行 60 | * 的深度对应了它输出在二维数组中的深度,即深度可以与二维数组的下标对应,那我们递 61 | * 归的时候记录深度就可以了啊。 62 | * 时间复杂度: O(n),其中n为二叉树的节点数,每个节点访问一次 63 | * 空间复杂度: O(n),最坏二叉树退化为链表,递归栈的最大深度为n 64 | */ 65 | function levelOrder(root: TreeNode | null): number[][] { 66 | const resArr: number[][] = new Array() 67 | if (root == null) return resArr 68 | traverse(root, 1, resArr) 69 | return resArr 70 | }; 71 | function traverse(root: TreeNode, depth: number, resArr: number[][]) { 72 | if (root != null) { 73 | if (resArr.length < depth) { 74 | const row: number[] = [] 75 | resArr.push(row) 76 | row.push(root.val) 77 | } else { 78 | const row = resArr[depth - 1] 79 | row.push(root.val) 80 | } 81 | } else { 82 | return 83 | } 84 | traverse(root.left, depth + 1, resArr) 85 | traverse(root.right, depth + 1, resArr) 86 | } 87 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

前端算法面试(高频题库&题目解析)

2 |
3 | 4 | > 一站式解决前端面试遇到的算法问题,咱们只专注于前端高频算法。 5 |
6 | 7 | #### 解决痛点: 8 | 9 | (1)LeetCode 题目太多,不知从何刷起?面试题目有些是前端常考,有些是后端常考? 10 |
11 | 答:本站参照 [CodeTop](https://codetop.cc/home)上的前端算法题目考察频度,抽取前 60 道题,知道你时间宝贵,咱们要把时间花在刀刃上。 12 |
13 | (2)LeetCode 上面的题解鱼龙混杂,有些直接题目直接贴代码,没有任何分析过程,看不懂? 14 |
15 | 答:本站会带你理解题目,并且给出解题思路,分析时间&空间复杂度,一题多解,带你彻底搞懂。 16 |
17 | (3)GitHub 有些仓库为了吸引关注数目,会尽量把所有题目列的很’全‘(刷不完那一种),根本没有照顾到求职心切的人的心情? 18 |
19 | 答:本站只做专精,不搞大而全。根据考试频率划分层次,让你做题时心里有数,减少求职者刷算法时的心理负担。 20 |
21 |
22 | 23 | #### 刷题顺序: 24 | 25 | 首先我们要做好一个心理准备,对于大多数算法小白或者平时没有刷算法题习惯的人来说,刷完第一遍肯定会忘的。
26 | 那么搞清楚刷题的目的(进大厂拿高薪)、要刷的次数(建议三次以上)、以及每一遍的刷题目的就很重要。
27 | 将知识梳理结构化有利于记忆,而且多刷几次可以加深记忆这是毋庸置疑的。
28 |
29 | 对于0基础小白,建议刷题前可先过一遍算法入门基础知识,以下是我梳理的一些基础知识点,
30 | 主要是:
31 | (1)JS基础(你知道数组的哪些操作是会改变自身的?sort方法你真的了解?)
32 | (2)大学计算机专业课之一`算法与数据结构`这门课的主要内容的总结。(非科班同学必看,科班同学也可以复习一下)
33 | - [前端算法入门一:刷算法题常用的JS基础扫盲](https://juejin.cn/post/7087134135193436197) 34 | - [前端算法入门二:时间空间复杂度&8大数据结构的JS实现](https://juejin.cn/post/7087286814230183943) 35 | - [前端算法入门三:5大排序算法&2大搜索&4大算法思想](https://juejin.cn/post/7088725301974269960) 36 | 37 | 38 | 推荐刷题顺序:
39 | 第一遍:
40 | 刷前端高频60,先把题目看懂,尝试自己解出来,实在想不出答案直接看题解,千万别浪费时间硬刚,
41 | 其次要把题解看透,每一种解法的时间复杂度是怎么来的搞清楚,每一种解法思路&优劣也要搞清楚
42 | 第二遍:
43 | 参考专题突破的分类,学习一些相应的解题技巧,自己要会总结记到本本上,比如遇到“二叉树”遍历相关题型,首先想到 DFS & BFS
44 | 第三遍:
45 | 自己不看答案,靠自己前面两遍的刷题记忆以及自己总结的解题技巧,认认真真把每道题做出来,做不出来的题就圈出来,分析一下做不出来的原因
46 | 更多遍:
47 | 针对于第三遍做题技巧和思路的查漏补缺
48 | 49 | #### 使用方法: 50 | 51 | Windows or Linux 可以用 (CTRL + click)题目 or 题解 打开一个新窗口。 52 |
53 | 这样当前页面可以保留,对于刷题比较友好。同理 MAC OS 可以用 CMD + click 54 | 55 |
56 | 57 | #### CodeTop 前端高频 60 (第1 ~ 20题) 58 |
59 | 60 | *已完成的题目我会将其序号加星号* 61 | 62 | | 序号 | 题目名称 | 考频 | LeetCode | 牛客 | 考点 | 难度 | 63 | | ---- | ---- | ---- | ---- | ---- | ---- | ---- | 64 | | 1* | [无重复字符的最长子串](./src/00-codetop-fontend-100/01-length-of-longest-substring.ts)| 58 | [题目](https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/) [题解](https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/by-hovinghuang-qugo/)| [题目](https://www.nowcoder.com/practice/b56799ebfd684fb394bd315e89324fb4?tpId=295&tqId=1008889&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295) [题解](https://blog.nowcoder.net/n/fce41b44190449f18c605a0a41db9c78) | `双指针` `哈希` | `medium` | 65 | | 2* | [合并两个有序数组](./src/00-codetop-fontend-100/02-merge-sorted-arr.ts)| 44 | [题目](https://leetcode-cn.com/problems/merge-sorted-array/) [题解](https://leetcode-cn.com/problems/merge-sorted-array/solution/by-hovinghuang-58f6/)| [题目](https://www.nowcoder.com/practice/89865d4375634fc484f3a24b7fe65665?tpId=295&tqId=658&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295) [题解](https://blog.nowcoder.net/n/950d8331e9004749adc1a3d98a5ec29f) | `双指针` | `easy` | 66 | | 3* | [字符串相加](./src/00-codetop-fontend-100/03-add-strings.ts)| 39 | [题目](https://leetcode-cn.com/problems/add-strings/) [题解](https://leetcode-cn.com/problems/add-strings/solution/by-hovinghuang-l59r/)| [题目](https://www.nowcoder.com/practice/11ae12e8c6fe48f883cad618c2e81475?tpId=295&tqId=1061819&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295) [题解](https://blog.nowcoder.net/n/1027295c5c8d44f7bbfe2b276e5adf20) | `双指针` `模拟` | `easy` | 67 | | 4* | [比较版本号](./src/00-codetop-fontend-100/04-compare-version.ts)| 38 | [题目](https://leetcode-cn.com/problems/compare-version-numbers/) [题解](https://leetcode-cn.com/problems/compare-version-numbers/solution/by-hovinghuang-rmlf/)| [题目](https://www.nowcoder.com/practice/2b317e02f14247a49ffdbdba315459e7) [题解](https://blog.nowcoder.net/n/5569dbf30e3e45ea977152a629d86439) | `字符串` | `medium` | 68 | | 5* | [有效的括号](./src/00-codetop-fontend-100/05-is-valid-brackets.ts)| 37 | [题目](https://leetcode-cn.com/problems/valid-parentheses/) [题解](https://leetcode-cn.com/problems/valid-parentheses/solution/by-hovinghuang-6gz1/)| [题目](https://www.nowcoder.com/practice/37548e94a270412c8b9fb85643c8ccc2?tpId=295&tqId=726&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295) [题解](https://blog.nowcoder.net/n/620e933e59534064a9722bfa6da0c3d0) | `栈` | `easy` | 69 | | 6* | [两数之和](./src/00-codetop-fontend-100/06-two-sum.ts)| 34 | [题目](https://leetcode-cn.com/problems/two-sum/) [题解](https://leetcode-cn.com/problems/two-sum/solution/by-hovinghuang-8jqr/)| [题目](https://www.nowcoder.com/practice/20ef0972485e41019e39543e8e895b7f?tpId=295&tqId=745&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3Ftab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D295) [题解](https://blog.nowcoder.net/n/61a9e5d2ac2f46db9f6f9e324faab016) | `哈希` | `easy` 70 | | 7* | [爬楼梯](./src/00-codetop-fontend-100/07-climb-stairs.ts)| 25 | [题目](https://leetcode-cn.com/problems/climbing-stairs/) [题解](https://leetcode-cn.com/problems/climbing-stairs/solution/by-hovinghuang-bl5r/)| [题目](https://www.nowcoder.com/practice/8c82a5b80378478f9484d87d1c5f12a4) [题解](https://blog.nowcoder.net/n/7057ccebe8fd452580442b74ffbb8d90) | `递归` `动态规划` | `easy` | 71 | | 8* | [全排列](./src/00-codetop-fontend-100/08-permutations.ts)| 25 | [题目](https://leetcode-cn.com/problems/permutations/) [题解](https://leetcode-cn.com/problems/permutations/solution/by-hovinghuang-ubrb/)| [题目](https://www.nowcoder.com/practice/4bcf3081067a4d028f95acee3ddcd2b1) [题解](https://blog.nowcoder.net/n/02102d26f1bb4026af9be0ec38984ec9) | `回溯` `递归` | `medium` | 72 | | 9* | [最大子序和](./src/00-codetop-fontend-100/09-max-sub-array.ts)| 26 | [题目](https://leetcode-cn.com/problems/maximum-subarray/) [题解](https://leetcode-cn.com/problems/maximum-subarray/solution/by-hovinghuang-exw9/)| [题目](https://www.nowcoder.com/practice/459bd355da1549fa8a49e350bf3df484) [题解](https://blog.nowcoder.net/n/8d36ffcdc332432197d9f44e6af0e78c) | `贪心` `动态规划` | `easy` | 73 | | 10*| [路径总和](./src/00-codetop-fontend-100/11-path-sum.ts)| 24 | [题目](https://leetcode-cn.com/problems/path-sum/) [题解](https://leetcode-cn.com/problems/path-sum/solution/by-hovinghuang-ax6m/)| [题目](https://www.nowcoder.com/practice/508378c0823c423baa723ce448cbfd0c) [题解](https://blog.nowcoder.net/n/b763226e0fd74c01a2a643a10db22c7b) | `递归` `DFS` | `easy` | 74 | | 11*| [反转链表](./src/00-codetop-fontend-100/10-reverse-linked-list.ts)| 22 | [题目](https://leetcode-cn.com/problems/reverse-linked-list/) [题解](https://leetcode-cn.com/problems/reverse-linked-list/solution/by-hovinghuang-zhkh/)| [题目](https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca) [题解](https://blog.nowcoder.net/n/087ff0e6f04c4ff699596619f7b4adfd) | `链表` `递归` | `easy` | 75 | | 12*| [三数之和](./src/00-codetop-fontend-100/14-three-sum.ts)| 22 | [题目](https://leetcode-cn.com/problems/3sum/) [题解](https://leetcode-cn.com/problems/3sum/solution/by-hovinghuang-mo14/)| [题目](https://www.nowcoder.com/practice/345e2ed5f81d4017bbb8cc6055b0b711) [题解](https://blog.nowcoder.net/n/c9e6f346004f4aedaf087cbdb099b2e6) | `双指针` | `medium` | 76 | | 13*| [二叉树的层序遍历](./src/00-codetop-fontend-100/12-binary-tree-level-order-traversal.ts)| 23 | [题目](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/) [题解](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/solution/by-hovinghuang-1hvt/)| [题目](https://www.nowcoder.com/practice/04a5560e43e24e9db4595865dc9c63a3) [题解](https://blog.nowcoder.net/n/10b0073f1d0043eba3d0f9646e43bbb4) | `二叉树` `BFS` | `medium` | 77 | | 14*| [数组中的第K个最大元素](./src/00-codetop-fontend-100/13-kth-largest-element-in-an-array.ts)| 22 | [题目](https://leetcode-cn.com/problems/kth-largest-element-in-an-array/) [题解](https://leetcode-cn.com/problems/kth-largest-element-in-an-array/solution/by-hovinghuang-mes5/)| [题目](https://www.nowcoder.com/practice/e016ad9b7f0b45048c58a9f27ba618bf) [题解](https://blog.nowcoder.net/n/ea1b2f2bf02b48d38c75a4e684b5471e) | `快速排序` `二分` | `medium` | 78 | | 15*| [买卖股票的最佳时机](./src/00-codetop-fontend-100/15-best-time-to-buy-and-sell-stock.ts)| 19 | [题目](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/) [题解](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/by-hovinghuang-6qhi/)| [题目](https://www.nowcoder.com/practice/64b4262d4e6d4f6181cd45446a5821ec) [题解](https://blog.nowcoder.net/n/4430ac0f65294e019d48345423b7e62f) | `贪心` `动态规划` | `easy` | 79 | | 16*| [手撕快速排序](./src/00-codetop-fontend-100/16-sort-an-array.ts)| 19 | [题目](https://leetcode-cn.com/problems/sort-an-array/) [题解](https://leetcode-cn.com/problems/sort-an-array/solution/by-hovinghuang-4j3t/)| [题目](https://www.nowcoder.com/practice/2baf799ea0594abd974d37139de27896) [题解](https://blog.nowcoder.net/n/ed60ab35639e4289bf51b7253d3a5c45) | `快速排序` `二分` | `medium` | 80 | | 17*| [环形链表](./src/00-codetop-fontend-100/17-linked-list-cycle.ts)| 20 | [题目](https://leetcode-cn.com/problems/linked-list-cycle/) [题解](https://leetcode-cn.com/problems/linked-list-cycle/solution/by-hovinghuang-ktep/)| [题目](https://www.nowcoder.com/practice/650474f313294468a4ded3ce0f7898b9) [题解](https://blog.nowcoder.net/n/ab8ae19d162a46c38761246e67aaf06f) | `双指针` `哈希` | `easy` | 81 | | 18*| [最长回文子串](./src/00-codetop-fontend-100/18-longest-palindromic-substring.ts)| 21 | [题目](https://leetcode-cn.com/problems/longest-palindromic-substring/) [题解](https://leetcode-cn.com/problems/longest-palindromic-substring/solution/by-hovinghuang-0ru8/)| [题目](https://www.nowcoder.com/practice/b4525d1d84934cf280439aeecc36f4af) [题解](https://blog.nowcoder.net/n/2759f3a8d3d742a7aca16768d196fc21) | `动态规划` | `medium` | 82 | | 19*| [求根节点到叶节点数字之和](./src/00-codetop-fontend-100/19-sum-root-to-leaf-numbers.ts)| 18 | [题目](https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/) [题解](https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/solution/by-hovinghuang-fq9e/)| [题目](https://www.nowcoder.com/practice/185a87cd29eb42049132aed873273e83) [题解](https://blog.nowcoder.net/n/08dbb5d39ecb4776889e7d8a7f31f736) | `DFS` `BFS` | `medium` | 83 | | 20*| [二分查找](./src/00-codetop-fontend-100/20-binary-search.ts)| 15 | [题目](https://leetcode-cn.com/problems/binary-search/) [题解](https://leetcode-cn.com/problems/binary-search/solution/by-hovinghuang-ks00/)| [题目](https://www.nowcoder.com/practice/d3df40bd23594118b57554129cadf47b?) [题解](https://blog.nowcoder.net/n/18779274e55745b682ab9be9bb9f438d) | `递归` | `easy` | 84 | 85 | #### CodeTop 前端高频 60 (第21 ~ 40题) 86 |
87 | 88 | *已完成的题目我会将其序号加星号* 89 | 90 | | 序号 | 题目名称 | 考频 | LeetCode | 牛客 | 考点 | 难度 | 91 | | ---- | ---- | ---- | ---- | ---- | ---- | ---- | 92 | | 21*| [岛屿数量](./src/00-codetop-fontend-100/21-number-of-islands.ts)| 15 | [题目](https://leetcode-cn.com/problems/number-of-islands/) [题解](https://leetcode-cn.com/problems/number-of-islands/solution/by-hovinghuang-d8tz/)| [题目](https://www.nowcoder.com/practice/0c9664d1554e466aa107d899418e814e) [题解](https://blog.nowcoder.net/n/73610fd87bd94e9590a4d71b9a898f79) | `DFS` `BFS` | `medium` | 93 | | 22*| [括号生成](./src/00-codetop-fontend-100/22-generate-parenthesis.ts)| 13 | [题目](https://leetcode-cn.com/problems/generate-parentheses/) [题解](https://leetcode-cn.com/problems/generate-parentheses/solution/by-hovinghuang-ueaq/)| [题目](https://www.nowcoder.com/practice/c9addb265cdf4cdd92c092c655d164ca) [题解](https://blog.nowcoder.net/n/14c439288cc944d397206965bcc2d0bc) | `递归` | `medium` | 94 | | 23*| [合并两个有序链表](./src/00-codetop-fontend-100/23-merge-two-sorted-linked-lists.ts)| 12 | [题目](https://leetcode-cn.com/problems/merge-two-sorted-lists/) [题解](https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/by-hovinghuang-zg0e/)| [题目](https://www.nowcoder.com/practice/d8b6b4358f774294a89de2a6ac4d9337) [题解](https://blog.nowcoder.net/n/ac49c082300d434898511f8c26bdc26d) | `链表` `递归` | `easy` | 95 | | 24*| [螺旋矩阵](./src/00-codetop-fontend-100/24-spiral-matrix.ts)| 13 | [题目](https://leetcode-cn.com/problems/spiral-matrix/) [题解](https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-hovinghuang-i1if/)| [题目](https://www.nowcoder.com/practice/7edf70f2d29c4b599693dc3aaeea1d31) [题解](https://blog.nowcoder.net/n/de3f4f8d4f504bc2b3b55ecde6295257) | `-` `-` | `medium` | 96 | | 25*| [最长上升子序列](./src/00-codetop-fontend-100/25-longest-increasing-subsequence.ts)| 12 | [题目](https://leetcode-cn.com/problems/longest-increasing-subsequence/) [题解](https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/by-hovinghuang-thvh/)| [题目](https://www.nowcoder.com/practice/5164f38b67f846fb8699e9352695cd2f) [题解](https://blog.nowcoder.net/n/df338bdebd0e4101b41b1978f6f3f98a) | `动态规划` `贪心` `二分` | `medium` | 97 | | 26*| [二叉树的中序遍历](./src/26-binary-tree-inorder-traversal.ts)| 13 | [题目](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/) [题解](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/by-hovinghuang-nd38/)| [题目](https://www.nowcoder.com/practice/0bf071c135e64ee2a027783b80bf781d) [题解](https://blog.nowcoder.net/n/e37c5bf59db341dab53094e6b43892eb) | `二叉树` `DFS` `BFS` | `easy` | 98 | | 27*| [二叉树的最大深度](./src/00-codetop-fontend-100/27-maximum-depth-of-binary-tree.ts)| 12 | [题目](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/) [题解](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/solution/by-hovinghuang-3sz3/)| [题目](https://www.nowcoder.com/practice/8a2b2bf6c19b4f23a9bdb9b233eefa73) [题解](https://blog.nowcoder.net/n/b3939da0dc6f4d7792b0551539892e72) | `二叉树` `-` | `easy` | 99 | | 28| [岛屿的最大面积]()| 11 | [题目]() [题解]()| [题目]() [题解]() | `DFS` `BFS` | `medium` | 100 | | 29| [LRU缓存机制]()| 11 | [题目]() [题解]()| [题目]() [题解]() | `-` `-` | `medium` | 101 | | 30| [零钱兑换]()| 12 | [题目]() [题解]()| [题目]() [题解]() | `-` `-` | `medium` | 102 | | 31| [链表中倒数第K个节点]()| 11 | [题目]() [题解]()| [题目]() [题解]() | `链表` `-` | `easy` | 103 | | 32| [斐波那契数列]()| 10 | [题目]() [题解]()| [题目]() [题解]() | `递归` `-` | `easy` | 104 | | 33| [翻转二叉树]()| 10 | [题目]() [题解]()| [题目]() [题解]() | `二叉树` `-` | `easy` | 105 | | 34| [长度最小的子数组]()| 9 | [题目]() [题解]()| [题目]() [题解]() | `-` `-` | `medium` | 106 | | 35| [接雨水]()| 9 | [题目]() [题解]()| [题目]() [题解]() | `-` `-` | `hard` | 107 | | 36| [最长重复子数组]()| 10 | [题目]() [题解]()| [题目]() [题解]() | `-` `-` | `medium` | 108 | | 37| [二叉树的前序遍历]()| 9 | [题目]() [题解]()| [题目]() [题解]() | `二叉树` `-` | `easy` | 109 | | 38| [合并区间]()| 10 | [题目]() [题解]()| [题目]() [题解]() | `-` `-` | `medium` | 110 | | 39| [二叉树的锯齿形层序遍历]()| 8 | [题目]() [题解]()| [题目]() [题解]() | `二叉树` `-` | `medium` | 111 | | 40| [由前序中序遍历构造二叉树]()| 8 | [题目]() [题解]()| [题目]() [题解]() | `二叉树` `-` | `medium` | 112 | 113 | #### CodeTop 前端高频 60 (第41 ~ 60题) 114 |
115 | 116 | *已完成的题目我会将其序号加星号* 117 | 118 | | 序号 | 题目名称 | 考频 | LeetCode | 牛客 | 考点 | 难度 | 119 | | ---- | ---- | ---- | ---- | ---- | ---- | ---- | 120 | | 41 | [不同路径]() | 8 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 121 | | 42 | [青蛙跳台阶问题]() | 8 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `easy` | 122 | | 43 | [打乱数组]() | 8 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 123 | | 44 | [相交链表]() | 8 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `easy` | 124 | | 45 | [旋转图像]() | 7 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 125 | | 46 | [复原IP地址]() | 7 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 126 | | 47 | [圆圈中最后剩下的数字]() | 7 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `easy` | 127 | | 48 | [K个一组翻转链表]() | 7 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `hard` | 128 | | 49 | [斐波那契数]() | 7 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `easy` | 129 | | 50 | [二叉树的右视图]() | 7 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 130 | | 51 | [最小栈]() | 7 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `easy` | 131 | | 52 | [打家劫舍]() | 7 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 132 | | 53 | [两数相加]() | 6 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 133 | | 54 | [移动零]() | 6 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `easy` | 134 | | 55 | [删除链表的倒数第 N 个结点]() | 6 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 135 | | 56 | [最长公共前缀]() | 6 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `easy` | 136 | | 57 | [字符串相乘]() | 6 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 137 | | 58 | [二叉搜索树中第K小的元素]() | 6 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 138 | | 59 | [最小路径和]() | 6 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 139 | | 60 | [阿拉伯数字转中文数字]() | 5 | [题目]() [题解]() | [题目]() [题解]() | `` `` | `medium` | 140 | 141 |
142 | 143 | TODO LIST (已完成的加星号) 144 | - [前端算法·专项攻破一:链表]() 145 | - [*前端算法·专项攻破二:二分查找&排序](https://juejin.cn/post/7093921550277181470) 146 | - [前端算法·专项攻破三:二叉树]() 147 | - [前端算法·专项攻破四:栈&队列]() 148 | - [前端算法·专项攻破五:哈希]() 149 | - [前端算法·专项攻破六:递归&回溯]() 150 | - [前端算法·专项攻破七:动态规划]() 151 | - [前端算法·专项攻破八:字符串]() 152 | - [前端算法·专项攻破九:双指针]() 153 | - [前端算法·专项攻破十:贪心]() 154 | - [前端算法·专项攻破十一:模拟]() 155 | 156 |
157 | 本站持续更新(每周一凌晨更新20份题解,每个月的1号同步CodeTop上的考频),敬请期待…… 158 |
159 |
160 | 每一个的一个小小的 star 都汇聚成我更新的动力,非常感谢您的关注。 --------------------------------------------------------------------------------