diff --git a/chapter_array_and_linkedlist/array.md b/chapter_array_and_linkedlist/array.md index a361dc312..f88772ab0 100755 --- a/chapter_array_and_linkedlist/array.md +++ b/chapter_array_and_linkedlist/array.md @@ -313,6 +313,8 @@ elementAddr = firtstElementAddr + elementLength * elementIndex ```javascript title="array.js" /* 扩展数组长度 */ + // 请注意,JavaScript 的 Array 是动态数组,可以直接扩展 + // 为了方便学习,本函数将 Array 看作是长度不可变的数组 function extend(nums, enlarge) { // 初始化一个扩展长度后的数组 const res = new Array(nums.length + enlarge).fill(0); @@ -329,6 +331,8 @@ elementAddr = firtstElementAddr + elementLength * elementIndex ```typescript title="array.ts" /* 扩展数组长度 */ + // 请注意,TypeScript 的 Array 是动态数组,可以直接扩展 + // 为了方便学习,本函数将 Array 看作是长度不可变的数组 function extend(nums: number[], enlarge: number): number[] { // 初始化一个扩展长度后的数组 const res = new Array(nums.length + enlarge).fill(0); @@ -502,7 +506,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex // 将 num 赋给 index 处元素 nums[index] = num; } - + /* 删除索引 index 处元素 */ function remove(nums, index) { // 把索引 index 之后的所有元素向前移动一位 @@ -524,7 +528,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex // 将 num 赋给 index 处元素 nums[index] = num; } - + /* 删除索引 index 处元素 */ function remove(nums: number[], index: number): void { // 把索引 index 之后的所有元素向前移动一位 @@ -705,7 +709,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex count++; } // 直接遍历数组 - for(let num of nums){ + for (let num of nums) { count += 1; } } diff --git a/chapter_array_and_linkedlist/linked_list.md b/chapter_array_and_linkedlist/linked_list.md index 827a4c218..7e64bcdda 100755 --- a/chapter_array_and_linkedlist/linked_list.md +++ b/chapter_array_and_linkedlist/linked_list.md @@ -587,8 +587,9 @@ comments: true /* 访问链表中索引为 index 的结点 */ function access(head, index) { for (let i = 0; i < index; i++) { - if (!head) + if (!head) { return null; + } head = head.next; } return head; diff --git a/chapter_array_and_linkedlist/list.md b/chapter_array_and_linkedlist/list.md index 7e1e83f52..7897e5df8 100755 --- a/chapter_array_and_linkedlist/list.md +++ b/chapter_array_and_linkedlist/list.md @@ -1195,6 +1195,17 @@ comments: true // 更新列表容量 this.#capacity = this.#nums.length; } + + /* 将列表转换为数组 */ + toArray() { + let size = this.size(); + // 仅转换有效长度范围内的列表元素 + const nums = new Array(size); + for (let i = 0; i < size; i++) { + nums[i] = this.get(i); + } + return nums; + } } ``` @@ -1289,6 +1300,17 @@ comments: true // 更新列表容量 this._capacity = this.nums.length; } + + /* 将列表转换为数组 */ + public toArray(): number[] { + let size = this.size(); + // 仅转换有效长度范围内的列表元素 + let nums = new Array(size); + for (let i = 0; i < size; i++) { + nums[i] = this.get(i); + } + return nums; + } } ``` diff --git a/chapter_computational_complexity/space_time_tradeoff.md b/chapter_computational_complexity/space_time_tradeoff.md index c7f7b1952..b02c20043 100755 --- a/chapter_computational_complexity/space_time_tradeoff.md +++ b/chapter_computational_complexity/space_time_tradeoff.md @@ -34,18 +34,16 @@ comments: true ```java title="leetcode_two_sum.java" /* 方法一:暴力枚举 */ - class SolutionBruteForce { - public int[] twoSum(int[] nums, int target) { - int size = nums.length; - // 两层循环,时间复杂度 O(n^2) - for (int i = 0; i < size - 1; i++) { - for (int j = i + 1; j < size; j++) { - if (nums[i] + nums[j] == target) - return new int[] { i, j }; - } + int[] twoSumBruteForce(int[] nums, int target) { + int size = nums.length; + // 两层循环,时间复杂度 O(n^2) + for (int i = 0; i < size - 1; i++) { + for (int j = i + 1; j < size; j++) { + if (nums[i] + nums[j] == target) + return new int[] { i, j }; } - return new int[0]; } + return new int[0]; } ``` @@ -53,34 +51,30 @@ comments: true ```cpp title="leetcode_two_sum.cpp" /* 方法一:暴力枚举 */ - class SolutionBruteForce { - public: - vector twoSum(vector& nums, int target) { - int size = nums.size(); - // 两层循环,时间复杂度 O(n^2) - for (int i = 0; i < size - 1; i++) { - for (int j = i + 1; j < size; j++) { - if (nums[i] + nums[j] == target) - return { i, j }; - } + vector twoSumBruteForce(vector& nums, int target) { + int size = nums.size(); + // 两层循环,时间复杂度 O(n^2) + for (int i = 0; i < size - 1; i++) { + for (int j = i + 1; j < size; j++) { + if (nums[i] + nums[j] == target) + return { i, j }; } - return {}; } - }; + return {}; + } ``` === "Python" ```python title="leetcode_two_sum.py" """ 方法一:暴力枚举 """ - class SolutionBruteForce: - def twoSum(self, nums: List[int], target: int) -> List[int]: - # 两层循环,时间复杂度 O(n^2) - for i in range(len(nums) - 1): - for j in range(i + 1, len(nums)): - if nums[i] + nums[j] == target: - return i, j - return [] + def two_sum_brute_force(nums: List[int], target: int) -> List[int]: + # 两层循环,时间复杂度 O(n^2) + for i in range(len(nums) - 1): + for j in range(i + 1, len(nums)): + if nums[i] + nums[j] == target: + return i, j + return [] ``` === "Go" @@ -103,6 +97,7 @@ comments: true === "JavaScript" ```javascript title="leetcode_two_sum.js" + /* 方法一:暴力枚举 */ function twoSumBruteForce(nums, target) { const n = nums.length; // 两层循环,时间复杂度 O(n^2) @@ -120,6 +115,7 @@ comments: true === "TypeScript" ```typescript title="leetcode_two_sum.ts" + /* 方法一:暴力枚举 */ function twoSumBruteForce(nums: number[], target: number): number[] { const n = nums.length; // 两层循环,时间复杂度 O(n^2) @@ -210,20 +206,18 @@ comments: true ```java title="leetcode_two_sum.java" /* 方法二:辅助哈希表 */ - class SolutionHashMap { - public int[] twoSum(int[] nums, int target) { - int size = nums.length; - // 辅助哈希表,空间复杂度 O(n) - Map dic = new HashMap<>(); - // 单层循环,时间复杂度 O(n) - for (int i = 0; i < size; i++) { - if (dic.containsKey(target - nums[i])) { - return new int[] { dic.get(target - nums[i]), i }; - } - dic.put(nums[i], i); + int[] twoSumHashTable(int[] nums, int target) { + int size = nums.length; + // 辅助哈希表,空间复杂度 O(n) + Map dic = new HashMap<>(); + // 单层循环,时间复杂度 O(n) + for (int i = 0; i < size; i++) { + if (dic.containsKey(target - nums[i])) { + return new int[] { dic.get(target - nums[i]), i }; } - return new int[0]; + dic.put(nums[i], i); } + return new int[0]; } ``` @@ -231,38 +225,34 @@ comments: true ```cpp title="leetcode_two_sum.cpp" /* 方法二:辅助哈希表 */ - class SolutionHashMap { - public: - vector twoSum(vector& nums, int target) { - int size = nums.size(); - // 辅助哈希表,空间复杂度 O(n) - unordered_map dic; - // 单层循环,时间复杂度 O(n) - for (int i = 0; i < size; i++) { - if (dic.find(target - nums[i]) != dic.end()) { - return { dic[target - nums[i]], i }; - } - dic.emplace(nums[i], i); + vector twoSumHashTable(vector& nums, int target) { + int size = nums.size(); + // 辅助哈希表,空间复杂度 O(n) + unordered_map dic; + // 单层循环,时间复杂度 O(n) + for (int i = 0; i < size; i++) { + if (dic.find(target - nums[i]) != dic.end()) { + return { dic[target - nums[i]], i }; } - return {}; + dic.emplace(nums[i], i); } - }; + return {}; + } ``` === "Python" ```python title="leetcode_two_sum.py" """ 方法二:辅助哈希表 """ - class SolutionHashMap: - def twoSum(self, nums: List[int], target: int) -> List[int]: - # 辅助哈希表,空间复杂度 O(n) - dic = {} - # 单层循环,时间复杂度 O(n) - for i in range(len(nums)): - if target - nums[i] in dic: - return dic[target - nums[i]], i - dic[nums[i]] = i - return [] + def two_sum_hash_table(nums: List[int], target: int) -> List[int]: + # 辅助哈希表,空间复杂度 O(n) + dic = {} + # 单层循环,时间复杂度 O(n) + for i in range(len(nums)): + if target - nums[i] in dic: + return dic[target - nums[i]], i + dic[nums[i]] = i + return [] ``` === "Go" @@ -285,6 +275,7 @@ comments: true === "JavaScript" ```javascript title="leetcode_two_sum.js" + /* 方法二:辅助哈希表 */ function twoSumHashTable(nums, target) { // 辅助哈希表,空间复杂度 O(n) let m = {}; @@ -303,6 +294,7 @@ comments: true === "TypeScript" ```typescript title="leetcode_two_sum.ts" + /* 方法二:辅助哈希表 */ function twoSumHashTable(nums: number[], target: number): number[] { // 辅助哈希表,空间复杂度 O(n) let m: Map = new Map(); diff --git a/chapter_computational_complexity/time_complexity.md b/chapter_computational_complexity/time_complexity.md index 225fde3e5..14efe36b6 100755 --- a/chapter_computational_complexity/time_complexity.md +++ b/chapter_computational_complexity/time_complexity.md @@ -1705,7 +1705,6 @@ $$ // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1 return count; } - ``` === "TypeScript" @@ -1872,7 +1871,6 @@ $$ if (n == 1) return 1; return expRecur(n - 1) + expRecur(n - 1) + 1; } - ``` === "C" diff --git a/chapter_hashing/hash_map.md b/chapter_hashing/hash_map.md index 26a5d42eb..bc17df6e6 100755 --- a/chapter_hashing/hash_map.md +++ b/chapter_hashing/hash_map.md @@ -731,7 +731,7 @@ $$ this.val = val; } } - + /* 基于数组简易实现的哈希表 */ class ArrayHashMap { #bucket; @@ -739,12 +739,12 @@ $$ // 初始化一个长度为 100 的桶(数组) this.#bucket = new Array(100).fill(null); } - + /* 哈希函数 */ #hashFunc(key) { return key % 100; } - + /* 查询操作 */ get(key) { let index = this.#hashFunc(key); @@ -752,19 +752,61 @@ $$ if (entry === null) return null; return entry.val; } - + /* 添加操作 */ set(key, val) { let index = this.#hashFunc(key); this.#bucket[index] = new Entry(key, val); } - + /* 删除操作 */ delete(key) { let index = this.#hashFunc(key); // 置为 null ,代表删除 this.#bucket[index] = null; } + + /* 获取所有键值对 */ + entries() { + let arr = []; + for (let i = 0; i < this.#bucket.length; i++) { + if (this.#bucket[i]) { + arr.push(this.#bucket[i]); + } + } + return arr; + } + + /* 获取所有键 */ + keys() { + let arr = []; + for (let i = 0; i < this.#bucket.length; i++) { + if (this.#bucket[i]) { + arr.push(this.#bucket[i]?.key); + } + } + return arr; + } + + /* 获取所有值 */ + values() { + let arr = []; + for (let i = 0; i < this.#bucket.length; i++) { + if (this.#bucket[i]) { + arr.push(this.#bucket[i]?.val); + } + } + return arr; + } + + /* 打印哈希表 */ + print() { + let entrySet = this.entries(); + for (const entry of entrySet) { + if (!entry) continue; + console.info(`${entry.key} -> ${entry.val}`); + } + } } ``` @@ -773,30 +815,30 @@ $$ ```typescript title="array_hash_map.ts" /* 键值对 Number -> String */ class Entry { - public key: number; - public val: string; - + public key: number; + public val: string; + constructor(key: number, val: string) { this.key = key; this.val = val; } } - + /* 基于数组简易实现的哈希表 */ class ArrayHashMap { - + private readonly bucket: (Entry | null)[]; - + constructor() { // 初始化一个长度为 100 的桶(数组) this.bucket = (new Array(100)).fill(null); } - + /* 哈希函数 */ private hashFunc(key: number): number { return key % 100; } - + /* 查询操作 */ public get(key: number): string | null { let index = this.hashFunc(key); @@ -804,19 +846,61 @@ $$ if (entry === null) return null; return entry.val; } - + /* 添加操作 */ public set(key: number, val: string) { let index = this.hashFunc(key); this.bucket[index] = new Entry(key, val); } - + /* 删除操作 */ public delete(key: number) { let index = this.hashFunc(key); // 置为 null ,代表删除 this.bucket[index] = null; } + + /* 获取所有键值对 */ + public entries(): (Entry | null)[] { + let arr: (Entry | null)[] = []; + for (let i = 0; i < this.bucket.length; i++) { + if (this.bucket[i]) { + arr.push(this.bucket[i]); + } + } + return arr; + } + + /* 获取所有键 */ + public keys(): (number | undefined)[] { + let arr: (number | undefined)[] = []; + for (let i = 0; i < this.bucket.length; i++) { + if (this.bucket[i]) { + arr.push(this.bucket[i]?.key); + } + } + return arr; + } + + /* 获取所有值 */ + public values(): (string | undefined)[] { + let arr: (string | undefined)[] = []; + for (let i = 0; i < this.bucket.length; i++) { + if (this.bucket[i]) { + arr.push(this.bucket[i]?.val); + } + } + return arr; + } + + /* 打印哈希表 */ + public print() { + let entrySet = this.entries(); + for (const entry of entrySet) { + if (!entry) continue; + console.info(`${entry.key} -> ${entry.val}`); + } + } } ``` diff --git a/chapter_heap/heap.md b/chapter_heap/heap.md index 06481c28b..64fe23b9f 100644 --- a/chapter_heap/heap.md +++ b/chapter_heap/heap.md @@ -279,9 +279,6 @@ comments: true === "C++" ```cpp title="my_heap.cpp" - // 使用动态数组,这样无需考虑扩容问题 - vector maxHeap; - /* 获取左子结点索引 */ int left(int i) { return 2 * i + 1; @@ -339,18 +336,6 @@ comments: true === "JavaScript" ```javascript title="my_heap.js" - #maxHeap; - - /* 构造函数,建立空堆或根据输入列表建堆 */ - constructor(nums) { - // 将列表元素原封不动添加进堆 - this.#maxHeap = nums === undefined ? [] : [...nums]; - // 堆化除叶结点以外的其他所有结点 - for (let i = this.#parent(this.size() - 1); i >= 0; i--) { - this.#siftDown(i); - } - } - /* 获取左子结点索引 */ #left(i) { return 2 * i + 1; @@ -370,29 +355,18 @@ comments: true === "TypeScript" ```typescript title="my_heap.ts" - private maxHeap: number[]; - /* 构造函数,建立空堆或根据输入列表建堆 */ - constructor(nums?: number[]) { - // 将列表元素原封不动添加进堆 - this.maxHeap = nums === undefined ? [] : [...nums]; - // 堆化除叶结点以外的其他所有结点 - for (let i = this.parent(this.size() - 1); i >= 0; i--) { - this.siftDown(i); - } - } - /* 获取左子结点索引 */ - private left(i: number): number { + left(i: number): number { return 2 * i + 1; } /* 获取右子结点索引 */ - private right(i: number): number { + right(i: number): number { return 2 * i + 2; } /* 获取父结点索引 */ - private parent(i: number): number { + parent(i: number): number { return Math.floor((i - 1) / 2); // 向下整除 } ``` @@ -491,7 +465,7 @@ comments: true ```typescript title="my_heap.ts" /* 访问堆顶元素 */ - public peek(): number { + peek(): number { return this.maxHeap[0]; } ``` @@ -667,7 +641,7 @@ comments: true ```typescript title="my_heap.ts" /* 元素入堆 */ - public push(val: number): void { + push(val: number): void { // 添加结点 this.maxHeap.push(val); // 从底至顶堆化 @@ -675,7 +649,7 @@ comments: true } /* 从结点 i 开始,从底至顶堆化 */ - private siftUp(i: number): void { + siftUp(i: number): void { while (true) { // 获取结点 i 的父结点 const p = this.parent(i); @@ -944,7 +918,7 @@ comments: true ```typescript title="my_heap.ts" /* 元素出堆 */ - public poll(): number { + poll(): number { // 判空处理 if (this.isEmpty()) throw new RangeError("Heap is empty."); // 交换根结点与最右叶结点(即交换首元素与尾元素) @@ -958,7 +932,7 @@ comments: true } /* 从结点 i 开始,从顶至底堆化 */ - private siftDown(i: number): void { + siftDown(i: number): void { while (true) { // 判断结点 i, l, r 中值最大的结点,记为 ma const l = this.left(i), r = this.right(i); diff --git a/chapter_searching/binary_search.md b/chapter_searching/binary_search.md index 9f7918615..6d37fc916 100755 --- a/chapter_searching/binary_search.md +++ b/chapter_searching/binary_search.md @@ -162,17 +162,17 @@ $$ ```typescript title="binary_search.ts" /* 二分查找(双闭区间) */ - const binarySearch = function (nums: number[], target: number): number { + function binarySearch(nums: number[], target: number): number { // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 let i = 0, j = nums.length - 1; // 循环,当搜索区间为空时跳出(当 i > j 时为空) while (i <= j) { - const m = Math.floor(i + (j - i) / 2); // 计算中点索引 m - if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中 + const m = Math.floor(i + (j - i) / 2); // 计算中点索引 m + if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; - } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m-1] 中 + } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m-1] 中 j = m - 1; - } else { // 找到目标元素,返回其索引 + } else { // 找到目标元素,返回其索引 return m; } } @@ -356,17 +356,17 @@ $$ ```typescript title="binary_search.ts" /* 二分查找(左闭右开) */ - const binarySearch1 = function (nums: number[], target: number): number { + function binarySearch1(nums: number[], target: number): number { // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 let i = 0, j = nums.length; // 循环,当搜索区间为空时跳出(当 i = j 时为空) while (i < j) { - const m = Math.floor(i + (j - i) / 2); // 计算中点索引 m - if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j) 中 + const m = Math.floor(i + (j - i) / 2); // 计算中点索引 m + if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j) 中 i = m + 1; - } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m) 中 + } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m) 中 j = m; - } else { // 找到目标元素,返回其索引 + } else { // 找到目标元素,返回其索引 return m; } } diff --git a/chapter_searching/linear_search.md b/chapter_searching/linear_search.md index 72eca5a04..3a5d81cd0 100755 --- a/chapter_searching/linear_search.md +++ b/chapter_searching/linear_search.md @@ -88,7 +88,6 @@ comments: true // 未找到目标元素,返回 -1 return -1; } - ``` === "TypeScript" diff --git a/chapter_sorting/bubble_sort.md b/chapter_sorting/bubble_sort.md index 05fa04820..8b2ee71c2 100755 --- a/chapter_sorting/bubble_sort.md +++ b/chapter_sorting/bubble_sort.md @@ -374,10 +374,10 @@ comments: true let tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - flag = true; // 记录交换元素 + flag = true; // 记录交换元素 } } - if (!flag) break; // 此轮冒泡未交换任何元素,直接跳出 + if (!flag) break; // 此轮冒泡未交换任何元素,直接跳出 } } ``` diff --git a/chapter_sorting/insertion_sort.md b/chapter_sorting/insertion_sort.md index 51e511881..2852a8331 100755 --- a/chapter_sorting/insertion_sort.md +++ b/chapter_sorting/insertion_sort.md @@ -124,10 +124,10 @@ comments: true let j = i - 1; // 内循环:将 base 插入到左边的正确位置 while (j >= 0 && nums[j] > base) { - nums[j + 1] = nums[j]; // 1. 将 nums[j] 向右移动一位 + nums[j + 1] = nums[j]; // 1. 将 nums[j] 向右移动一位 j--; } - nums[j + 1] = base; // 2. 将 base 赋值到正确位置 + nums[j + 1] = base; // 2. 将 base 赋值到正确位置 } } ``` diff --git a/chapter_sorting/quick_sort.md b/chapter_sorting/quick_sort.md index e0334fbbc..49c32713a 100755 --- a/chapter_sorting/quick_sort.md +++ b/chapter_sorting/quick_sort.md @@ -139,7 +139,7 @@ comments: true === "JavaScript" - ``` js title="quick_sort.js" + ```javascript title="quick_sort.js" /* 元素交换 */ function swap(nums, i, j) { let tmp = nums[i]; @@ -349,14 +349,14 @@ comments: true ```javascript title="quick_sort.js" /* 快速排序 */ - function quickSort(nums, left, right) { + quickSort(nums, left, right) { // 子数组长度为 1 时终止递归 if (left >= right) return; // 哨兵划分 - const pivot = partition(nums, left, right); + const pivot = this.partition(nums, left, right); // 递归左子数组、右子数组 - quickSort(nums, left, pivot - 1); - quickSort(nums, pivot + 1, right); + this.quickSort(nums, left, pivot - 1); + this.quickSort(nums, pivot + 1, right); } ``` @@ -364,16 +364,16 @@ comments: true ```typescript title="quick_sort.ts" /* 快速排序 */ - function quickSort(nums: number[], left: number, right: number): void { + quickSort(nums: number[], left: number, right: number): void { // 子数组长度为 1 时终止递归 if (left >= right) { return; } // 哨兵划分 - const pivot = partition(nums, left, right); + const pivot = this.partition(nums, left, right); // 递归左子数组、右子数组 - quickSort(nums, left, pivot - 1); - quickSort(nums, pivot + 1, right); + this.quickSort(nums, left, pivot - 1); + this.quickSort(nums, pivot + 1, right); } ``` @@ -585,25 +585,29 @@ comments: true ```javascript title="quick_sort.js" /* 选取三个元素的中位数 */ - function medianThree(nums, left, mid, right) { + medianThree(nums, left, mid, right) { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) - return left; - else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) - return mid; - else - return right; + if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right])) return left; + else if ((nums[mid] < nums[left]) ^ (nums[mid] < nums[right])) return mid; + else return right; } - + /* 哨兵划分(三数取中值) */ - function partition(nums, left, right) { + partition(nums, left, right) { // 选取三个候选元素的中位数 - let med = medianThree(nums, left, Math.floor((left + right) / 2), right); + let med = this.medianThree(nums, left, Math.floor((left + right) / 2), right); // 将中位数交换至数组最左端 - swap(nums, left, med); + this.swap(nums, left, med); // 以 nums[left] 作为基准数 - // 下同省略... + let i = left, j = right; + while (i < j) { + while (i < j && nums[j] >= nums[left]) j--; // 从右向左找首个小于基准数的元素 + while (i < j && nums[i] <= nums[left]) i++; // 从左向右找首个大于基准数的元素 + this.swap(nums, i, j); // 交换这两个元素 + } + this.swap(nums, i, left); // 将基准数交换至两子数组的分界线 + return i; // 返回基准数的索引 } ``` @@ -611,7 +615,7 @@ comments: true ```typescript title="quick_sort.ts" /* 选取三个元素的中位数 */ - function medianThree(nums: number[], left: number, mid: number, right: number): number { + medianThree(nums: number[], left: number, mid: number, right: number): number { // 使用了异或操作来简化代码 // 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 if (Number(nums[left] < nums[mid]) ^ Number(nums[left] < nums[right])) { @@ -624,13 +628,25 @@ comments: true } /* 哨兵划分(三数取中值) */ - function partition(nums: number[], left: number, right: number): number { + partition(nums: number[], left: number, right: number): number { // 选取三个候选元素的中位数 - let med = medianThree(nums, left, Math.floor((left + right) / 2), right); + let med = this.medianThree(nums, left, Math.floor((left + right) / 2), right); // 将中位数交换至数组最左端 - swap(nums, left, med); + this.swap(nums, left, med); // 以 nums[left] 作为基准数 - // 下同省略... + let i = left, j = right; + while (i < j) { + while (i < j && nums[j] >= nums[left]) { + j--; // 从右向左找首个小于基准数的元素 + } + while (i < j && nums[i] <= nums[left]) { + i++; // 从左向右找首个大于基准数的元素 + } + this.swap(nums, i, j); // 交换这两个元素 + } + this.swap(nums, i, left); // 将基准数交换至两子数组的分界线 + return i; // 返回基准数的索引 + } ``` === "C" @@ -789,17 +805,17 @@ comments: true ```javascript title="quick_sort.js" /* 快速排序(尾递归优化) */ - function quickSort(nums, left, right) { + quickSort(nums, left, right) { // 子数组长度为 1 时终止 while (left < right) { // 哨兵划分操作 - let pivot = partition(nums, left, right); + let pivot = this.partition(nums, left, right); // 对两个子数组中较短的那个执行快排 if (pivot - left < right - pivot) { - quickSort(nums, left, pivot - 1); // 递归排序左子数组 - left = pivot + 1; // 剩余待排序区间为 [pivot + 1, right] + this.quickSort(nums, left, pivot - 1); // 递归排序左子数组 + left = pivot + 1; // 剩余待排序区间为 [pivot + 1, right] } else { - quickSort(nums, pivot + 1, right); // 递归排序右子数组 + this.quickSort(nums, pivot + 1, right); // 递归排序右子数组 right = pivot - 1; // 剩余待排序区间为 [left, pivot - 1] } } @@ -810,17 +826,17 @@ comments: true ```typescript title="quick_sort.ts" /* 快速排序(尾递归优化) */ - function quickSort(nums: number[], left: number, right: number): void { + quickSort(nums: number[], left: number, right: number): void { // 子数组长度为 1 时终止 while (left < right) { // 哨兵划分操作 - let pivot = partition(nums, left, right); + let pivot = this.partition(nums, left, right); // 对两个子数组中较短的那个执行快排 if (pivot - left < right - pivot) { - quickSort(nums, left, pivot - 1); // 递归排序左子数组 + this.quickSort(nums, left, pivot - 1); // 递归排序左子数组 left = pivot + 1; // 剩余待排序区间为 [pivot + 1, right] } else { - quickSort(nums, pivot + 1, right); // 递归排序右子数组 + this.quickSort(nums, pivot + 1, right); // 递归排序右子数组 right = pivot - 1; // 剩余待排序区间为 [left, pivot - 1] } } diff --git a/chapter_stack_and_queue/queue.md b/chapter_stack_and_queue/queue.md index cb0e5de62..943a7b05d 100755 --- a/chapter_stack_and_queue/queue.md +++ b/chapter_stack_and_queue/queue.md @@ -544,18 +544,22 @@ comments: true #front; // 头结点 #front #rear; // 尾结点 #rear #queSize = 0; + constructor() { this.#front = null; this.#rear = null; } + /* 获取队列的长度 */ get size() { return this.#queSize; } + /* 判断队列是否为空 */ isEmpty() { return this.size === 0; } + /* 入队 */ push(num) { // 尾结点后添加 num @@ -571,6 +575,7 @@ comments: true } this.#queSize++; } + /* 出队 */ poll() { const num = this.peek(); @@ -579,12 +584,24 @@ comments: true this.#queSize--; return num; } + /* 访问队首元素 */ peek() { if (this.size === 0) throw new Error("队列为空"); return this.#front.val; } + + /* 将链表转化为 Array 并返回 */ + toArray() { + let node = this.#front; + const res = new Array(this.size); + for (let i = 0; i < res.length; i++) { + res[i] = node.val; + node = node.next; + } + return res; + } } ``` @@ -596,18 +613,22 @@ comments: true private front: ListNode | null; // 头结点 front private rear: ListNode | null; // 尾结点 rear private queSize: number = 0; + constructor() { this.front = null; this.rear = null; } + /* 获取队列的长度 */ get size(): number { return this.queSize; } + /* 判断队列是否为空 */ isEmpty(): boolean { return this.size === 0; } + /* 入队 */ push(num: number): void { // 尾结点后添加 num @@ -623,6 +644,7 @@ comments: true } this.queSize++; } + /* 出队 */ poll(): number { const num = this.peek(); @@ -633,12 +655,24 @@ comments: true this.queSize--; return num; } + /* 访问队首元素 */ peek(): number { if (this.size === 0) throw new Error("队列为空"); return this.front!.val; } + + /* 将链表转化为 Array 并返回 */ + toArray(): number[] { + let node = this.front; + const res = new Array(this.size); + for (let i = 0; i < res.length; i++) { + res[i] = node!.val; + node = node!.next; + } + return res; + } } ``` @@ -1126,6 +1160,16 @@ comments: true throw new Error("队列为空"); return this.#nums[this.#front]; } + + /* 返回 Array */ + toArray() { + // 仅转换有效长度范围内的列表元素 + const arr = new Array(this.size); + for (let i = 0, j = this.#front; i < this.size; i++, j++) { + arr[i] = this.#nums[j % this.capacity]; + } + return arr; + } } ``` @@ -1187,6 +1231,16 @@ comments: true throw new Error("队列为空"); return this.nums[this.front]; } + + /* 返回 Array */ + toArray(): number[] { + // 仅转换有效长度范围内的列表元素 + const arr = new Array(this.size); + for (let i = 0, j = this.front; i < this.size; i++, j++) { + arr[i] = this.nums[j % this.capacity]; + } + return arr; + } } ``` diff --git a/chapter_stack_and_queue/stack.md b/chapter_stack_and_queue/stack.md index c72dff3f3..c85c325ad 100755 --- a/chapter_stack_and_queue/stack.md +++ b/chapter_stack_and_queue/stack.md @@ -513,23 +513,23 @@ comments: true ```javascript title="linkedlist_stack.js" /* 基于链表实现的栈 */ class LinkedListStack { - #stackPeek; // 将头结点作为栈顶 + #stackPeek; // 将头结点作为栈顶 #stkSize = 0; // 栈的长度 - + constructor() { this.#stackPeek = null; } - + /* 获取栈的长度 */ get size() { return this.#stkSize; } - + /* 判断栈是否为空 */ isEmpty() { return this.size == 0; } - + /* 入栈 */ push(num) { const node = new ListNode(num); @@ -537,26 +537,22 @@ comments: true this.#stackPeek = node; this.#stkSize++; } - + /* 出栈 */ pop() { const num = this.peek(); - if (!this.#stackPeek) { - throw new Error("栈为空!"); - } this.#stackPeek = this.#stackPeek.next; this.#stkSize--; return num; } - + /* 访问栈顶元素 */ peek() { - if (!this.#stackPeek) { - throw new Error("栈为空!"); - } + if (!this.#stackPeek) + throw new Error("栈为空"); return this.#stackPeek.val; } - + /* 将链表转化为 Array 并返回 */ toArray() { let node = this.#stackPeek; @@ -576,22 +572,22 @@ comments: true /* 基于链表实现的栈 */ class LinkedListStack { private stackPeek: ListNode | null; // 将头结点作为栈顶 - private stkSize: number = 0; // 栈的长度 - + private stkSize: number = 0; // 栈的长度 + constructor() { this.stackPeek = null; } - + /* 获取栈的长度 */ get size(): number { return this.stkSize; } - + /* 判断栈是否为空 */ isEmpty(): boolean { return this.size == 0; } - + /* 入栈 */ push(num: number): void { const node = new ListNode(num); @@ -599,26 +595,24 @@ comments: true this.stackPeek = node; this.stkSize++; } - + /* 出栈 */ pop(): number { const num = this.peek(); - if (!this.stackPeek) { - throw new Error("栈为空!"); - } + if (!this.stackPeek) + throw new Error("栈为空"); this.stackPeek = this.stackPeek.next; this.stkSize--; return num; } - + /* 访问栈顶元素 */ peek(): number { - if (!this.stackPeek) { - throw new Error("栈为空!"); - } + if (!this.stackPeek) + throw new Error("栈为空"); return this.stackPeek.val; } - + /* 将链表转化为 Array 并返回 */ toArray(): number[] { let node = this.stackPeek; @@ -941,30 +935,40 @@ comments: true constructor() { this.stack = []; } + /* 获取栈的长度 */ get size() { return this.stack.length; } + /* 判断栈是否为空 */ empty() { return this.stack.length === 0; } + /* 入栈 */ push(num) { this.stack.push(num); } + /* 出栈 */ pop() { if (this.empty()) throw new Error("栈为空"); return this.stack.pop(); } + /* 访问栈顶元素 */ top() { if (this.empty()) throw new Error("栈为空"); return this.stack[this.stack.length - 1]; } + + /* 返回 Array */ + toArray() { + return this.stack; + } }; ``` @@ -977,30 +981,40 @@ comments: true constructor() { this.stack = []; } + /* 获取栈的长度 */ get size(): number { return this.stack.length; } + /* 判断栈是否为空 */ empty(): boolean { return this.stack.length === 0; } + /* 入栈 */ push(num: number): void { this.stack.push(num); } + /* 出栈 */ pop(): number | undefined { if (this.empty()) throw new Error('栈为空'); return this.stack.pop(); } + /* 访问栈顶元素 */ top(): number | undefined { if (this.empty()) throw new Error('栈为空'); return this.stack[this.stack.length - 1]; } + + /* 返回 Array */ + toArray() { + return this.stack; + } }; ``` diff --git a/chapter_tree/binary_tree_traversal.md b/chapter_tree/binary_tree_traversal.md index b8752a818..0ce2c4b22 100755 --- a/chapter_tree/binary_tree_traversal.md +++ b/chapter_tree/binary_tree_traversal.md @@ -120,12 +120,13 @@ comments: true // 初始化一个列表,用于保存遍历序列 let list = []; while (queue.length) { - let node = queue.shift(); // 队列出队 - list.push(node.val); // 保存结点值 + let node = queue.shift(); // 队列出队 + list.push(node.val); // 保存结点值 if (node.left) - queue.push(node.left); // 左子结点入队 + queue.push(node.left); // 左子结点入队 if (node.right) - queue.push(node.right); // 右子结点入队 + queue.push(node.right); // 右子结点入队 + } return list; } @@ -368,14 +369,14 @@ comments: true ```javascript title="binary_tree_dfs.js" /* 前序遍历 */ - function preOrder(root){ + function preOrder(root) { if (root === null) return; // 访问优先级:根结点 -> 左子树 -> 右子树 list.push(root.val); preOrder(root.left); preOrder(root.right); } - + /* 中序遍历 */ function inOrder(root) { if (root === null) return; @@ -384,7 +385,7 @@ comments: true list.push(root.val); inOrder(root.right); } - + /* 后序遍历 */ function postOrder(root) { if (root === null) return; @@ -408,7 +409,7 @@ comments: true preOrder(root.left); preOrder(root.right); } - + /* 中序遍历 */ function inOrder(root: TreeNode | null): void { if (root === null) { @@ -419,7 +420,7 @@ comments: true list.push(root.val); inOrder(root.right); } - + /* 后序遍历 */ function postOrder(root: TreeNode | null): void { if (root === null) {