build
This commit is contained in:
parent
139e34bdb1
commit
7156a5f832
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -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<int> twoSum(vector<int>& 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<int> twoSumBruteForce(vector<int>& 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<Integer, Integer> 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<Integer, Integer> 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<int> twoSum(vector<int>& nums, int target) {
|
||||
int size = nums.size();
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
unordered_map<int, int> 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<int> twoSumHashTable(vector<int>& nums, int target) {
|
||||
int size = nums.size();
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
unordered_map<int, int> 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<number, number> = new Map();
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -279,9 +279,6 @@ comments: true
|
||||
=== "C++"
|
||||
|
||||
```cpp title="my_heap.cpp"
|
||||
// 使用动态数组,这样无需考虑扩容问题
|
||||
vector<int> 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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +88,6 @@ comments: true
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
=== "TypeScript"
|
||||
|
||||
@ -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; // 此轮冒泡未交换任何元素,直接跳出
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -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 赋值到正确位置
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<number>(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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user