mirror of
https://github.com/krahets/hello-algo.git
synced 2024-12-26 00:06:28 +08:00
Fix some codes and a figure.
This commit is contained in:
parent
2532f06c7f
commit
698c2e7fe5
8 changed files with 48 additions and 46 deletions
|
@ -5,39 +5,41 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 二分查找最左一个元素 */
|
/* 二分查找最左一个元素 */
|
||||||
function binary_search_left_edge(nums, target) {
|
function binarySearchLeftEdge(nums, target) {
|
||||||
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
let i = 0,
|
||||||
|
j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
||||||
while (i <= j) {
|
while (i <= j) {
|
||||||
let m = Math.floor((i + j) / 2); // 计算中点索引 m
|
let m = Math.floor((i + j) / 2); // 计算中点索引 m
|
||||||
if (nums[m] < target) {
|
if (nums[m] < target) {
|
||||||
i = m + 1; // target 在区间 [m+1, j] 中
|
i = m + 1; // target 在区间 [m+1, j] 中
|
||||||
} else if (nums[m] > target) {
|
} else if (nums[m] > target) {
|
||||||
j = m - 1; // target 在区间 [i, m-1] 中
|
j = m - 1; // target 在区间 [i, m-1] 中
|
||||||
} else {
|
} else {
|
||||||
j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中
|
j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == nums.length || nums[i] != target) {
|
if (i == nums.length || nums[i] != target) {
|
||||||
return -1; // 未找到目标元素,返回 -1
|
return -1; // 未找到目标元素,返回 -1
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 二分查找最右一个元素 */
|
/* 二分查找最右一个元素 */
|
||||||
function binary_search_right_edge(nums, target) {
|
function binarySearchRightEdge(nums, target) {
|
||||||
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
let i = 0,
|
||||||
|
j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
||||||
while (i <= j) {
|
while (i <= j) {
|
||||||
let m = Math.floor((i + j) / 2); // 计算中点索引 m
|
let m = Math.floor((i + j) / 2); // 计算中点索引 m
|
||||||
if (nums[m] < target) {
|
if (nums[m] < target) {
|
||||||
i = m + 1; // target 在区间 [m+1, j] 中
|
i = m + 1; // target 在区间 [m+1, j] 中
|
||||||
} else if (nums[m] > target) {
|
} else if (nums[m] > target) {
|
||||||
j = m - 1; // target 在区间 [i, m-1] 中
|
j = m - 1; // target 在区间 [i, m-1] 中
|
||||||
} else {
|
} else {
|
||||||
i = m + 1; // 首个大于 target 的元素在区间 [m+1, j] 中
|
i = m + 1; // 首个大于 target 的元素在区间 [m+1, j] 中
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (j == nums.length || nums[j] != target) {
|
if (j == nums.length || nums[j] != target) {
|
||||||
return -1; // 未找到目标元素,返回 -1
|
return -1; // 未找到目标元素,返回 -1
|
||||||
}
|
}
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
@ -47,9 +49,9 @@ let target = 6;
|
||||||
const nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
|
const nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
|
||||||
|
|
||||||
// 二分查找最左一个元素
|
// 二分查找最左一个元素
|
||||||
let index_left = binary_search_left_edge(nums, target);
|
let index_left = binarySearchLeftEdge(nums, target);
|
||||||
console.log("数组中最左一个元素 6 的索引 = ", index_left);
|
console.log('数组中最左一个元素 6 的索引 = ', index_left);
|
||||||
|
|
||||||
// 二分查找最右一个元素
|
// 二分查找最右一个元素
|
||||||
let index_right = binary_search_right_edge(nums, target);
|
let index_right = binarySearchRightEdge(nums, target);
|
||||||
console.log("数组中最右一个元素 6 的索引 = ", index_right);
|
console.log('数组中最右一个元素 6 的索引 = ', index_right);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */
|
/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */
|
||||||
function sift_down(nums, n, i) {
|
function siftDown(nums, n, i) {
|
||||||
while (true) {
|
while (true) {
|
||||||
// 判断节点 i, l, r 中值最大的节点,记为 ma
|
// 判断节点 i, l, r 中值最大的节点,记为 ma
|
||||||
let l = 2 * i + 1;
|
let l = 2 * i + 1;
|
||||||
|
@ -29,21 +29,21 @@ function sift_down(nums, n, i) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 堆排序 */
|
/* 堆排序 */
|
||||||
function heap_sort(nums) {
|
function heapSort(nums) {
|
||||||
// 建堆操作:堆化除叶节点以外的其他所有节点
|
// 建堆操作:堆化除叶节点以外的其他所有节点
|
||||||
for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) {
|
for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) {
|
||||||
sift_down(nums, nums.length, i);
|
siftDown(nums, nums.length, i);
|
||||||
}
|
}
|
||||||
// 从堆中提取最大元素,循环 n-1 轮
|
// 从堆中提取最大元素,循环 n-1 轮
|
||||||
for (let i = nums.length - 1; i > 0; i--) {
|
for (let i = nums.length - 1; i > 0; i--) {
|
||||||
// 交换根节点与最右叶节点(即交换首元素与尾元素)
|
// 交换根节点与最右叶节点(即交换首元素与尾元素)
|
||||||
[nums[0], nums[i]] = [nums[i], nums[0]];
|
[nums[0], nums[i]] = [nums[i], nums[0]];
|
||||||
// 以根节点为起点,从顶至底进行堆化
|
// 以根节点为起点,从顶至底进行堆化
|
||||||
sift_down(nums, i, 0);
|
siftDown(nums, i, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Driver Code */
|
/* Driver Code */
|
||||||
const nums = [4, 1, 3, 1, 5, 2];
|
const nums = [4, 1, 3, 1, 5, 2];
|
||||||
heap_sort(nums);
|
heapSort(nums);
|
||||||
console.log("堆排序完成后 nums =", nums);
|
console.log('堆排序完成后 nums =', nums);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 选择排序 */
|
/* 选择排序 */
|
||||||
function selection_sort(nums) {
|
function selectionSort(nums) {
|
||||||
let n = nums.length;
|
let n = nums.length;
|
||||||
// 外循环:未排序区间为 [i, n-1]
|
// 外循环:未排序区间为 [i, n-1]
|
||||||
for (let i = 0; i < n - 1; i++) {
|
for (let i = 0; i < n - 1; i++) {
|
||||||
|
@ -13,7 +13,7 @@ function selection_sort(nums) {
|
||||||
let k = i;
|
let k = i;
|
||||||
for (let j = i + 1; j < n; j++) {
|
for (let j = i + 1; j < n; j++) {
|
||||||
if (nums[j] < nums[k]) {
|
if (nums[j] < nums[k]) {
|
||||||
k = j; // 记录最小元素的索引
|
k = j; // 记录最小元素的索引
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 将该最小元素与未排序区间的首个元素交换
|
// 将该最小元素与未排序区间的首个元素交换
|
||||||
|
@ -23,5 +23,5 @@ function selection_sort(nums) {
|
||||||
|
|
||||||
/* Driver Code */
|
/* Driver Code */
|
||||||
const nums = [4, 1, 3, 1, 5, 2];
|
const nums = [4, 1, 3, 1, 5, 2];
|
||||||
selection_sort(nums);
|
selectionSort(nums);
|
||||||
console.log("选择排序完成后 nums =", nums);
|
console.log('选择排序完成后 nums =', nums);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 二分查找最左一个元素 */
|
/* 二分查找最左一个元素 */
|
||||||
function binary_search_left_edge(nums: number[], target: number): number {
|
function binarySearchLeftEdge(nums: number[], target: number): number {
|
||||||
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
||||||
while (i <= j) {
|
while (i <= j) {
|
||||||
let m = Math.floor((i + j) / 2); // 计算中点索引 m
|
let m = Math.floor((i + j) / 2); // 计算中点索引 m
|
||||||
|
@ -24,7 +24,7 @@ function binary_search_left_edge(nums: number[], target: number): number {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 二分查找最右一个元素 */
|
/* 二分查找最右一个元素 */
|
||||||
function binary_search_right_edge(nums: number[], target: number): number {
|
function binarySearchRightEdge(nums: number[], target: number): number {
|
||||||
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
let i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
||||||
while (i <= j) {
|
while (i <= j) {
|
||||||
let m = Math.floor((i + j) / 2); // 计算中点索引 m
|
let m = Math.floor((i + j) / 2); // 计算中点索引 m
|
||||||
|
@ -47,9 +47,9 @@ let target: number = 6;
|
||||||
const nums: number[] = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
|
const nums: number[] = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
|
||||||
|
|
||||||
// 二分查找最左一个元素
|
// 二分查找最左一个元素
|
||||||
let index_left: number = binary_search_left_edge(nums, target);
|
let index_left: number = binarySearchLeftEdge(nums, target);
|
||||||
console.log("数组中最左一个元素 6 的索引 = ", index_left);
|
console.log("数组中最左一个元素 6 的索引 = ", index_left);
|
||||||
|
|
||||||
// 二分查找最右一个元素
|
// 二分查找最右一个元素
|
||||||
let index_right: number = binary_search_right_edge(nums, target);
|
let index_right: number = binarySearchRightEdge(nums, target);
|
||||||
console.log("数组中最右一个元素 6 的索引 = ", index_right);
|
console.log("数组中最右一个元素 6 的索引 = ", index_right);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */
|
/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */
|
||||||
function sift_down(nums: number[], n: number, i: number): void {
|
function siftDown(nums: number[], n: number, i: number): void {
|
||||||
while (true) {
|
while (true) {
|
||||||
// 判断节点 i, l, r 中值最大的节点,记为 ma
|
// 判断节点 i, l, r 中值最大的节点,记为 ma
|
||||||
let l = 2 * i + 1;
|
let l = 2 * i + 1;
|
||||||
|
@ -29,23 +29,23 @@ function sift_down(nums: number[], n: number, i: number): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 堆排序 */
|
/* 堆排序 */
|
||||||
function heap_sort(nums: number[]): void {
|
function heapSort(nums: number[]): void {
|
||||||
// 建堆操作:堆化除叶节点以外的其他所有节点
|
// 建堆操作:堆化除叶节点以外的其他所有节点
|
||||||
for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) {
|
for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) {
|
||||||
sift_down(nums, nums.length, i);
|
siftDown(nums, nums.length, i);
|
||||||
}
|
}
|
||||||
// 从堆中提取最大元素,循环 n-1 轮
|
// 从堆中提取最大元素,循环 n-1 轮
|
||||||
for (let i = nums.length - 1; i > 0; i--) {
|
for (let i = nums.length - 1; i > 0; i--) {
|
||||||
// 交换根节点与最右叶节点(即交换首元素与尾元素)
|
// 交换根节点与最右叶节点(即交换首元素与尾元素)
|
||||||
[nums[0], nums[i]] = [nums[i], nums[0]];
|
[nums[0], nums[i]] = [nums[i], nums[0]];
|
||||||
// 以根节点为起点,从顶至底进行堆化
|
// 以根节点为起点,从顶至底进行堆化
|
||||||
sift_down(nums, i, 0);
|
siftDown(nums, i, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Driver Code */
|
/* Driver Code */
|
||||||
const nums: number[] = [4, 1, 3, 1, 5, 2];
|
const nums: number[] = [4, 1, 3, 1, 5, 2];
|
||||||
heap_sort(nums);
|
heapSort(nums);
|
||||||
console.log("堆排序完成后 nums =", nums);
|
console.log('堆排序完成后 nums =', nums);
|
||||||
|
|
||||||
export { };
|
export {};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 选择排序 */
|
/* 选择排序 */
|
||||||
function selection_sort(nums: number[]): void {
|
function selectionSort(nums: number[]): void {
|
||||||
let n = nums.length;
|
let n = nums.length;
|
||||||
// 外循环:未排序区间为 [i, n-1]
|
// 外循环:未排序区间为 [i, n-1]
|
||||||
for (let i = 0; i < n - 1; i++) {
|
for (let i = 0; i < n - 1; i++) {
|
||||||
|
@ -13,7 +13,7 @@ function selection_sort(nums: number[]): void {
|
||||||
let k = i;
|
let k = i;
|
||||||
for (let j = i + 1; j < n; j++) {
|
for (let j = i + 1; j < n; j++) {
|
||||||
if (nums[j] < nums[k]) {
|
if (nums[j] < nums[k]) {
|
||||||
k = j; // 记录最小元素的索引
|
k = j; // 记录最小元素的索引
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 将该最小元素与未排序区间的首个元素交换
|
// 将该最小元素与未排序区间的首个元素交换
|
||||||
|
@ -23,7 +23,7 @@ function selection_sort(nums: number[]): void {
|
||||||
|
|
||||||
/* Driver Code */
|
/* Driver Code */
|
||||||
const nums: number[] = [4, 1, 3, 1, 5, 2];
|
const nums: number[] = [4, 1, 3, 1, 5, 2];
|
||||||
selection_sort(nums);
|
selectionSort(nums);
|
||||||
console.log("选择排序完成后 nums =", nums);
|
console.log('选择排序完成后 nums =', nums);
|
||||||
|
|
||||||
export { };
|
export {};
|
||||||
|
|
|
@ -592,7 +592,7 @@ $T(n)$ 是一次函数,说明时间增长趋势是线性的,因此可以得
|
||||||
|
|
||||||
根据定义,确定 $f(n)$ 之后,我们便可得到时间复杂度 $O(f(n))$ 。那么如何确定渐近上界 $f(n)$ 呢?总体分为两步:首先统计操作数量,然后判断渐近上界。
|
根据定义,确定 $f(n)$ 之后,我们便可得到时间复杂度 $O(f(n))$ 。那么如何确定渐近上界 $f(n)$ 呢?总体分为两步:首先统计操作数量,然后判断渐近上界。
|
||||||
|
|
||||||
### 1) 统计操作数量
|
### 第一步:统计操作数量
|
||||||
|
|
||||||
针对代码,逐行从上到下计算即可。然而,由于上述 $c \cdot f(n)$ 中的常数项 $c$ 可以取任意大小,**因此操作数量 $T(n)$ 中的各种系数、常数项都可以被忽略**。根据此原则,可以总结出以下计数简化技巧:
|
针对代码,逐行从上到下计算即可。然而,由于上述 $c \cdot f(n)$ 中的常数项 $c$ 可以取任意大小,**因此操作数量 $T(n)$ 中的各种系数、常数项都可以被忽略**。根据此原则,可以总结出以下计数简化技巧:
|
||||||
|
|
||||||
|
@ -808,7 +808,7 @@ $$
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2) 判断渐近上界
|
### 第二步:判断渐近上界
|
||||||
|
|
||||||
**时间复杂度由多项式 $T(n)$ 中最高阶的项来决定**。这是因为在 $n$ 趋于无穷大时,最高阶的项将发挥主导作用,其他项的影响都可以被忽略。
|
**时间复杂度由多项式 $T(n)$ 中最高阶的项来决定**。这是因为在 $n$ 趋于无穷大时,最高阶的项将发挥主导作用,其他项的影响都可以被忽略。
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 61 KiB |
Loading…
Reference in a new issue