Skip to content

Commit

Permalink
223rd Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Shyam-Chen committed Oct 17, 2024
1 parent 5806874 commit eaf6692
Show file tree
Hide file tree
Showing 11 changed files with 385 additions and 66 deletions.
25 changes: 20 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,34 @@ $ pnpm bench twoSum.bench.ts

解題前應該學會的思路與技巧

- 鏈結串列 (Linked List)
- [鏈結串列 (Linked List)](./algorithms/linked-list/README.md)
- 堆疊 (Stack)
- 佇列 (Queue)
- 雜湊表 (Hash Table)
- 堆積 (Heap)
- 樹 (Tree)
- 二元樹 (Binary Tree)
- 二元搜尋樹 (Binary Search Tree)
- 堆積 (Heap)
- [圖 (Graph)](./algorithms/graph/README.md)
- [二分搜尋 (Binary Search)](./algorithms/binary-search/README.md)
- 回溯 (Backtracking)
- 字典樹 (Trie)
- 排序 (Sorting)
- 冒泡排序 (Bubble Sort)
- 選擇排序 (Selection Sort)
- 插入排序 (Insertion Sort)
- 合併排序 (Merge Sort)
- 快速排序 (Quick Sort)
- 堆積排序 (Heap Sort)
- 搜尋 (Searching)
- [二分搜尋 (Binary Search)](./algorithms/searching/README.md)
- 動態規劃 (Dynamic Programming)
- [0-1 背包問題 (0-1 Knapsack Problem)](./algorithms/dynamic-programming/README.md)
- [0-1 背包問題 (0-1 Knapsack Problem)](./algorithms/dynamic-programming/README.md#0-1-背包問題-0-1-knapsack-problem)
- 完全背包問題 (Unbounded Knapsack Problem)
- 多維背包問題 (Multidimensional Knapsack Problem)
- 貪婪 (Greedy)
- 分數背包問題 (Fractional Knapsack Problem)
- 回溯 (Backtracking)
- 分治 (Divide and Conquer)
- 位元操作 (Bit Manipulation)

## Basic - LeetCode 75

Expand Down
52 changes: 51 additions & 1 deletion algorithms/dynamic-programming/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
# 動態規劃 (Dynamic Programming)

費波那契數:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...

```ts
F[0] = 0;
F[1] = 1;
if (n >= 2) F[n] = F[n - 1] + F[n - 2];
```

```ts
function fibonacci(n: number): number {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
```

一維動態規劃 (1D Dynamic Programming)

```ts
function fibonacci(n: number): number {
const dp = [0, 1];

for (let i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}

return dp[n];
}
```

## 0-1 背包問題 (0-1 Knapsack Problem)

問題:給定 n 個物品,每個物品有一定的重量和價值,並給定一個背包的容量。你需要在不超過背包容量的情況下選擇物品,使得所選物品的總價值最大。
Expand All @@ -9,6 +38,20 @@
- `values[]`: 物品的價值
- `capacity`: 背包的容量

每個物品的編號 (`i`) 及其對應的重量和價值:

| i | weights[i - 1] | values[i - 1] |
| --: | -------------: | ------------: |
| 1 | 1 | 5 |
| 2 | 2 | 11 |
| 3 | 3 | 15 |

遞推公式:

```ts
dp[i][c] = Math.max(dp[i - 1][c], dp[i - 1][c - weights[i - 1]] + values[i - 1]);
```

```ts
function knapsack(weights: number[], values: number[], capacity: number): number {
const n = weights.length;
Expand All @@ -19,7 +62,6 @@ function knapsack(weights: number[], values: number[], capacity: number): number
for (let i = 1; i <= n; i++) {
for (let c = 0; c <= capacity; c++) {
if (weights[i - 1] <= c) {
// 遞推公式
dp[i][c] = Math.max(
dp[i - 1][c], // 不選擇物品
dp[i - 1][c - weights[i - 1]] + values[i - 1], // 選擇物品
Expand Down Expand Up @@ -61,3 +103,11 @@ const values = [5, 11, 15];
const capacity = 4;
console.log(knapsack(weights, values, capacity)); // 20
```

## 完全背包問題 (Unbounded Knapsack Problem)

遞推公式:

```ts
dp[c] = Math.max(dp[c], dp[c - weights[i - 1]] + values[i - 1]);
```
45 changes: 45 additions & 0 deletions algorithms/linked-list/CircularLinkedList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ListNode } from './ListNode';

export class CircularLinkedList<T> {
head: ListNode<T> | null;

constructor() {
this.head = null;
}

// 在尾端新增節點並形成環狀鏈結串列
append(value: T): void {
const newNode = new ListNode(value);

if (this.head === null) {
// 如果是第一個節點,將其設為頭節點,並指向自己
this.head = newNode;
newNode.next = this.head; // 環狀結構
} else {
let current = this.head;

// 找到最後一個節點(指向頭節點的節點)
while (current.next !== null && current.next !== this.head) {
current = current.next;
}

current.next = newNode;
newNode.next = this.head; // 使其成為環狀結構
}
}

// 印出環狀鏈結串列
print(): void {
if (this.head === null) return;

let current = this.head;
const values: T[] = [];

do {
values.push(current.value);
current = current.next as ListNode<T>;
} while (current !== this.head);

console.log(`${values.join(' -> ')} -> (回到頭)`);
}
}
47 changes: 47 additions & 0 deletions algorithms/linked-list/LinkedList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ListNode } from './ListNode';

export class LinkedList<T> {
head: ListNode<T> | null;

constructor() {
this.head = null;
}

// 新增節點到鏈結串列的尾端
append(value: T): void {
const newNode = new ListNode(value);

if (this.head === null) {
// 如果鏈結串列為空,則將新節點設為頭節點
this.head = newNode;
} else {
let current = this.head;

while (current.next !== null) {
current = current.next;
}

current.next = newNode;
}
}

// 將節點插入到鏈結串列的開頭
prepend(value: T): void {
const newNode = new ListNode(value);
newNode.next = this.head;
this.head = newNode;
}

// 印出鏈結串列中的所有值
print(): void {
let current = this.head;
const values: T[] = [];

while (current !== null) {
values.push(current.value);
current = current.next;
}

console.log(values.join(' -> '));
}
}
9 changes: 9 additions & 0 deletions algorithms/linked-list/ListNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export class ListNode<T> {
value: T;
next: ListNode<T> | null;

constructor(value: T, next: ListNode<T> | null = null) {
this.value = value;
this.next = next;
}
}
Loading

0 comments on commit eaf6692

Please sign in to comment.