diff --git a/codes/javascript/chapter_searching/binary_search_edge.js b/codes/javascript/chapter_searching/binary_search_edge.js new file mode 100644 index 000000000..d82d60469 --- /dev/null +++ b/codes/javascript/chapter_searching/binary_search_edge.js @@ -0,0 +1,55 @@ +/** + * File: binary_search_edge.js + * Created Time: 2023-06-04 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 二分查找最左一个元素 */ +function binary_search_left_edge(nums, target) { + let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] + while (i <= j) { + let m = Math.floor((i + j) / 2); // 计算中点索引 m + if (nums[m] < target) { + i = m + 1; // target 在区间 [m+1, j] 中 + } else if (nums[m] > target) { + j = m - 1; // target 在区间 [i, m-1] 中 + } else { + j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中 + } + } + if (i == nums.length || nums[i] != target) { + return -1; // 未找到目标元素,返回 -1 + } + return i; +} + +/* 二分查找最右一个元素 */ +function binary_search_right_edge(nums, target) { + let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] + while (i <= j) { + let m = Math.floor((i + j) / 2); // 计算中点索引 m + if (nums[m] < target) { + i = m + 1; // target 在区间 [m+1, j] 中 + } else if (nums[m] > target) { + j = m - 1; // target 在区间 [i, m-1] 中 + } else { + i = m + 1; // 首个大于 target 的元素在区间 [m+1, j] 中 + } + } + if (j == nums.length || nums[j] != target) { + return -1; // 未找到目标元素,返回 -1 + } + return j; +} + +/* Driver Code */ +let target = 6; +const nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; + +// 二分查找最左一个元素 +let index_left = binary_search_left_edge(nums, target); +console.log("数组中最左一个元素 6 的索引 = ", index_left); + +// 二分查找最右一个元素 +let index_right = binary_search_right_edge(nums, target); +console.log("数组中最右一个元素 6 的索引 = ", index_right); diff --git a/codes/javascript/chapter_sorting/heap_sort.js b/codes/javascript/chapter_sorting/heap_sort.js new file mode 100644 index 000000000..2b83c3e73 --- /dev/null +++ b/codes/javascript/chapter_sorting/heap_sort.js @@ -0,0 +1,49 @@ +/** + * File: heap_sort.js + * Created Time: 2023-06-04 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */ +function sift_down(nums, n, i) { + while (true) { + // 判断节点 i, l, r 中值最大的节点,记为 ma + let l = 2 * i + 1; + let r = 2 * i + 2; + let ma = i; + if (l < n && nums[l] > nums[ma]) { + ma = l; + } + if (r < n && nums[r] > nums[ma]) { + ma = r; + } + // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if (ma === i) { + break; + } + // 交换两节点 + [nums[i], nums[ma]] = [nums[ma], nums[i]]; + // 循环向下堆化 + i = ma; + } +} + +/* 堆排序 */ +function heap_sort(nums) { + // 建堆操作:堆化除叶节点以外的其他所有节点 + for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) { + sift_down(nums, nums.length, i); + } + // 从堆中提取最大元素,循环 n-1 轮 + for (let i = nums.length - 1; i > 0; i--) { + // 交换根节点与最右叶节点(即交换首元素与尾元素) + [nums[0], nums[i]] = [nums[i], nums[0]]; + // 以根节点为起点,从顶至底进行堆化 + sift_down(nums, i, 0); + } +} + +/* Driver Code */ +const nums = [4, 1, 3, 1, 5, 2]; +heap_sort(nums); +console.log("堆排序完成后 nums =", nums); diff --git a/codes/javascript/chapter_sorting/selection_sort.js b/codes/javascript/chapter_sorting/selection_sort.js new file mode 100644 index 000000000..5afcfb418 --- /dev/null +++ b/codes/javascript/chapter_sorting/selection_sort.js @@ -0,0 +1,27 @@ +/** + * File: selection_sort.js + * Created Time: 2023-06-04 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 选择排序 */ +function selection_sort(nums) { + let n = nums.length; + // 外循环:未排序区间为 [i, n-1] + for (let i = 0; i < n - 1; i++) { + // 内循环:找到未排序区间内的最小元素 + let k = i; + for (let j = i + 1; j < n; j++) { + if (nums[j] < nums[k]) { + k = j; // 记录最小元素的索引 + } + } + // 将该最小元素与未排序区间的首个元素交换 + [nums[i], nums[k]] = [nums[k], nums[i]]; + } +} + +/* Driver Code */ +const nums = [4, 1, 3, 1, 5, 2]; +selection_sort(nums); +console.log("选择排序完成后 nums =", nums); diff --git a/codes/typescript/chapter_backtracking/n_queens.ts b/codes/typescript/chapter_backtracking/n_queens.ts index 62e4cc0ef..5234b148b 100644 --- a/codes/typescript/chapter_backtracking/n_queens.ts +++ b/codes/typescript/chapter_backtracking/n_queens.ts @@ -16,7 +16,7 @@ function backtrack( ): void { // 当放置完所有行时,记录解 if (row === n) { - res.push(state.map((row) => row.slice())); + res.push(state.map(row => row.slice())); return; } // 遍历所有列 @@ -27,12 +27,12 @@ function backtrack( // 剪枝:不允许该格子所在 (列 或 主对角线 或 副对角线) 包含皇后 if (!(cols[col] || diags1[diag1] || diags2[diag2])) { // 尝试:将皇后放置在该格子 - state[row][col] = 'Q'; + state[row][col] = "Q"; cols[col] = diags1[diag1] = diags2[diag2] = true; // 放置下一行 backtrack(row + 1, n, state, res, cols, diags1, diags2); // 回退:将该格子恢复为空位 - state[row][col] = '#'; + state[row][col] = "#"; cols[col] = diags1[diag1] = diags2[diag2] = false; } } @@ -41,7 +41,7 @@ function backtrack( /* 求解 N 皇后 */ function nQueens(n: number): string[][][] { // 初始化 n*n 大小的棋盘,其中 'Q' 代表皇后,'#' 代表空位 - const state = Array.from({ length: n }, () => Array(n).fill('#')); + const state = Array.from({ length: n }, () => Array(n).fill("#")); const cols = Array(n).fill(false); // 记录列是否有皇后 const diags1 = Array(2 * n - 1).fill(false); // 记录主对角线是否有皇后 const diags2 = Array(2 * n - 1).fill(false); // 记录副对角线是否有皇后 @@ -57,9 +57,7 @@ const res = nQueens(n); console.log(`输入棋盘长宽为 ${n}`); console.log(`皇后放置方案共有 ${res.length} 种`); -res.forEach((state) => { - console.log('--------------------'); - state.forEach((row) => console.log(row)); +res.forEach(state => { + console.log("--------------------"); + state.forEach(row => console.log(row)); }); - -export {}; diff --git a/codes/typescript/chapter_searching/binary_search_edge.ts b/codes/typescript/chapter_searching/binary_search_edge.ts new file mode 100644 index 000000000..f7136b1a4 --- /dev/null +++ b/codes/typescript/chapter_searching/binary_search_edge.ts @@ -0,0 +1,55 @@ +/** + * File: binary_search_edge.ts + * Created Time: 2023-06-04 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 二分查找最左一个元素 */ +function binary_search_left_edge(nums: number[], target: number): number { + let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] + while (i <= j) { + let m = Math.floor((i + j) / 2); // 计算中点索引 m + if (nums[m] < target) { + i = m + 1; // target 在区间 [m+1, j] 中 + } else if (nums[m] > target) { + j = m - 1; // target 在区间 [i, m-1] 中 + } else { + j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中 + } + } + if (i == nums.length || nums[i] != target) { + return -1; // 未找到目标元素,返回 -1 + } + return i; +} + +/* 二分查找最右一个元素 */ +function binary_search_right_edge(nums: number[], target: number): number { + let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] + while (i <= j) { + let m = Math.floor((i + j) / 2); // 计算中点索引 m + if (nums[m] < target) { + i = m + 1; // target 在区间 [m+1, j] 中 + } else if (nums[m] > target) { + j = m - 1; // target 在区间 [i, m-1] 中 + } else { + i = m + 1; // 首个大于 target 的元素在区间 [m+1, j] 中 + } + } + if (j == nums.length || nums[j] != target) { + return -1; // 未找到目标元素,返回 -1 + } + return j; +} + +/* Driver Code */ +let target: number = 6; +const nums: number[] = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; + +// 二分查找最左一个元素 +let index_left: number = binary_search_left_edge(nums, target); +console.log("数组中最左一个元素 6 的索引 = ", index_left); + +// 二分查找最右一个元素 +let index_right: number = binary_search_right_edge(nums, target); +console.log("数组中最右一个元素 6 的索引 = ", index_right); diff --git a/codes/typescript/chapter_sorting/heap_sort.ts b/codes/typescript/chapter_sorting/heap_sort.ts new file mode 100644 index 000000000..9023ee429 --- /dev/null +++ b/codes/typescript/chapter_sorting/heap_sort.ts @@ -0,0 +1,51 @@ +/** + * File: heap_sort.ts + * Created Time: 2023-06-04 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */ +function sift_down(nums: number[], n: number, i: number): void { + while (true) { + // 判断节点 i, l, r 中值最大的节点,记为 ma + let l = 2 * i + 1; + let r = 2 * i + 2; + let ma = i; + if (l < n && nums[l] > nums[ma]) { + ma = l; + } + if (r < n && nums[r] > nums[ma]) { + ma = r; + } + // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if (ma === i) { + break; + } + // 交换两节点 + [nums[i], nums[ma]] = [nums[ma], nums[i]]; + // 循环向下堆化 + i = ma; + } +} + +/* 堆排序 */ +function heap_sort(nums: number[]): void { + // 建堆操作:堆化除叶节点以外的其他所有节点 + for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) { + sift_down(nums, nums.length, i); + } + // 从堆中提取最大元素,循环 n-1 轮 + for (let i = nums.length - 1; i > 0; i--) { + // 交换根节点与最右叶节点(即交换首元素与尾元素) + [nums[0], nums[i]] = [nums[i], nums[0]]; + // 以根节点为起点,从顶至底进行堆化 + sift_down(nums, i, 0); + } +} + +/* Driver Code */ +const nums: number[] = [4, 1, 3, 1, 5, 2]; +heap_sort(nums); +console.log("堆排序完成后 nums =", nums); + +export { }; diff --git a/codes/typescript/chapter_sorting/selection_sort.ts b/codes/typescript/chapter_sorting/selection_sort.ts new file mode 100644 index 000000000..792f89ff5 --- /dev/null +++ b/codes/typescript/chapter_sorting/selection_sort.ts @@ -0,0 +1,29 @@ +/** + * File: selection_sort.ts + * Created Time: 2023-06-04 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 选择排序 */ +function selection_sort(nums: number[]): void { + let n = nums.length; + // 外循环:未排序区间为 [i, n-1] + for (let i = 0; i < n - 1; i++) { + // 内循环:找到未排序区间内的最小元素 + let k = i; + for (let j = i + 1; j < n; j++) { + if (nums[j] < nums[k]) { + k = j; // 记录最小元素的索引 + } + } + // 将该最小元素与未排序区间的首个元素交换 + [nums[i], nums[k]] = [nums[k], nums[i]]; + } +} + +/* Driver Code */ +const nums: number[] = [4, 1, 3, 1, 5, 2]; +selection_sort(nums); +console.log("选择排序完成后 nums =", nums); + +export { };