Skip to content

Commit

Permalink
240th Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Shyam-Chen committed Oct 23, 2024
1 parent 7fcf57f commit cafcf39
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 12 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,13 @@ Ace Coding Interview with 75 Qs
[162]: ./src/page-2/162.%20Find%20Peak%20Element/findPeakElement.ts
[875]: ./src/page-9/875.%20Koko%20Eating%20Bananas/minEatingSpeed.ts

| Backtracking | | |
| ----------------------------------------- | -------------- | ------ |
| 17. Letter Combinations of a Phone Number | [Solution][17] | Medium |
| 216. Combination Sum III | Solution | Medium |
| Backtracking | | |
| ----------------------------------------- | --------------- | ------ |
| 17. Letter Combinations of a Phone Number | [Solution][17] | Medium |
| 216. Combination Sum III | [Solution][216] | Medium |

[17]: ./src/page-1/17.%20Letter%20Combinations%20of%20a%20Phone%20Number/letterCombinations.ts
[216]: ./src/page-2/216.%20Combination%20Sum%20III/combinationSum3.ts

| DP - 1D | | |
| ------------------------------ | ---------------- | ------ |
Expand Down
6 changes: 3 additions & 3 deletions algorithms/1.array/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ for (let i = 0; i < nums.length; i++) {

## 滑動視窗 (Sliding Window)

維持一個固定大小的視窗,並在陣列中移動這個視窗來進行計算。
維持一個固定長度的視窗,並在陣列中移動這個視窗來進行計算。

問題:找出連續子陣列長度為 `k` 的最大和。

Expand Down Expand Up @@ -158,13 +158,13 @@ const rows = matrix.length;
const cols = matrix[0].length;
```

建立一個與原本矩陣橫行和縱列互換的空白新矩陣
建立一個與原矩陣橫行和縱列互換的空白新矩陣

```ts
const newMatrix = Array.from({ length: cols }, () => Array(rows));
```

迴圈走訪原本矩陣的所有元素,將其分配到新矩陣上:
迴圈走訪原矩陣的所有元素,將其分配到新矩陣上:

```ts
for (let r = 0; r < rows; r++) {
Expand Down
168 changes: 167 additions & 1 deletion algorithms/13.backtracking/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,171 @@
# 回溯 (Backtracking)

- 狀態
- 嘗試
- 回退
- 紀錄解
- 剪枝

```ts
const result = [];

function backtrack(state) {
// 紀錄解
if (x) {
push([...state]);
return;
}

for (y) {
// 剪枝
if (z) continue;

// 嘗試
push();

// 下一個
backtrack(state);

// 回退
pop();
}
}

backtrack([]);
```

問題:給定一個不同數字的候選陣列 `candidates` 和一個整數目標 `target`,根據候選陣列內的值加總等於整數目標的所有唯一組合的排列。

```ts
const candidates = [2, 3, 6, 7];
const target = 7;
```

```
2 + 2 + 3 = 7
7 = 7
```

使用當前和:不能提早預判是否超過目標,必須先累加到「當前和」後再進行比較,少了剪枝的機會。

<details>
<summary>使用當前和</summary>

```ts
function combinationSum(candidates: number[], target: number): number[][] {
const result: number[][] = [];

function backtrack(sum: number, combination: number[], start: number): void {
// 如果當前的和等於目標值,表示找到了一個有效組合
if (sum === target) {
result.push([...combination]);
return;
}

// 如果當前和超過目標值,則返回
if (sum > target) return;

// 走訪候選數字
for (let i = start; i < candidates.length; i++) {
// 加入當前候選數字到組合中
combination.push(candidates[i]);

// 繼續遞迴探索,注意這裡還是傳遞 i,因為同一個數字可以被重複使用
backtrack(sum + candidates[i], combination, i);

// 回退,移除當前加入的數字 (回溯)
combination.pop();
}
}

// 初始呼叫 backtrack,從 0 開始累加
backtrack(0, [], 0);

return result;
}
```

</details>

使用剩餘值:能夠提早根據「剩餘的目標值」來決定是否可以剪枝。

- 用減法減到剩餘 0
- 當前候選值 > 當前剩餘數,進行剪枝

```
7 // []
7 - 2 = 5 // [2]
5 - 2 = 3 // [2, 2]
3 - 2 = 1 // [2, 2, 2]
3 - 3 = 0 // [2, 2, 3],紀錄解
```

```ts
function combinationSum(candidates: number[], target: number): number[][] {
const result: number[][] = [];

function backtrack(/* ... */) {
// ...
}

backtrack(/* ... */);

return result;
}
```

狀態:

- `remaining`:當前剩餘值
- `combination`:當前有效組合
- `index`:當前索引

```ts
function backtrack(remaining: number, combination: number[], index: number) {
// ...
}

backtrack(target, [], 0);
```

當減至 0 時為解,紀錄解

```ts
if (remaining === 0) {
result.push([...combination]);
return;
}
```

當當前的候選值 > 當前剩餘數時,進行剪枝

```ts
// 走訪所有候選值
for (let i = start; i < candidates.length; i++) {
if (candidates[i] > remaining) continue;

// ...
}
```

嘗試

```ts
combination.push(candidates[i]);
```

遞迴繼續探索

```ts
backtrack(remaining - candidates[i], combination, i);
```

回退

```ts
combination.pop();
```

### 全排列 (Permutations)

```ts
Expand Down Expand Up @@ -37,7 +203,7 @@ function permute(nums: number[]): number[][] {
const selected: boolean[] = Array(nums.length).fill(false);

function backtrack(currentPermutation: number[]) {
// 如果當前排列的長度等於原數組長度,說明我們已經生成了一個完整排列
// 如果當前排列長度等於原陣列長度,說明我們已經生成了一個完整排列
if (currentPermutation.length === nums.length) {
result.push([...currentPermutation]);
return;
Expand Down
4 changes: 2 additions & 2 deletions algorithms/7.heap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ console.log(minHeap.pop()); // 1
console.log(minHeap.pop()); // 3
console.log(minHeap.pop()); // 5

// 取得堆積大小
// 取得堆積長度
console.log(minHeap.length); // 4

// 判斷堆積是否為空
Expand Down Expand Up @@ -81,7 +81,7 @@ console.log(maxHeap.pop()); // 15
console.log(maxHeap.pop()); // 9
console.log(maxHeap.pop()); // 8

// 取得堆積大小
// 取得堆積長度
console.log(maxHeap.length); // 4

// 判斷堆積是否為空
Expand Down
2 changes: 1 addition & 1 deletion algorithms/7.heap/maxHeap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ console.log(maxHeap.pop()); // 15
console.log(maxHeap.pop()); // 9
console.log(maxHeap.pop()); // 8

// 取得堆積大小
// 取得堆積長度
console.log(maxHeap.length); // 4

// 判斷堆積是否為空
Expand Down
2 changes: 1 addition & 1 deletion algorithms/7.heap/minHeap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ console.log(minHeap.pop()); // 1
console.log(minHeap.pop()); // 3
console.log(minHeap.pop()); // 5

// 取得堆積大小
// 取得堆積長度
console.log(minHeap.length); // 4

// 判斷堆積是否為空
Expand Down
15 changes: 15 additions & 0 deletions src/page-2/216. Combination Sum III/combinationSum3.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { combinationSum3 } from './combinationSum3';

describe('216. Combination Sum III', () => {
test('combinationSum3', () => {
expect(combinationSum3(3, 7)).toStrictEqual([[1, 2, 4]]);

expect(combinationSum3(3, 9)).toStrictEqual([
[1, 2, 6],
[1, 3, 5],
[2, 3, 4],
]);

expect(combinationSum3(4, 1)).toStrictEqual([]);
});
});
28 changes: 28 additions & 0 deletions src/page-2/216. Combination Sum III/combinationSum3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
type CombinationSum3 = (k: number, n: number) => number[][];

/**
* Accepted
*/
export const combinationSum3: CombinationSum3 = (k, n) => {
const result: number[][] = [];

function backtrack(start: number, remaining: number, combination: number[]) {
if (combination.length === k && remaining === 0) {
result.push([...combination]);
return;
}

if (combination.length > k || remaining < 0) return;

// Try all numbers from 'start' to 9
for (let i = start; i <= 9; i++) {
combination.push(i);
backtrack(i + 1, remaining - i, combination);
combination.pop();
}
}

backtrack(1, n, []);

return result;
};

0 comments on commit cafcf39

Please sign in to comment.