Skip to content

Commit bbac463

Browse files
committed
update the summary in topic
1 parent 7cf67d3 commit bbac463

25 files changed

+702
-61
lines changed

src/backtracking/combination.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
1-
function combine(n: number, k: number): number[][] {
2-
const ans: number[][] = [];
3-
const partial: number[] = [];
1+
const combine = (n: number, k: number): number[][] => {
2+
const ret: number[][] = [];
43

5-
const helper = (startNum = 1): void => {
6-
if (partial.length === k) {
7-
ans.push([...partial]);
4+
const backtracking = (start: number, prevRes: number[]): void => {
5+
if (prevRes.length === k) {
6+
ret.push(Array.from(prevRes));
87
return;
98
}
10-
for (let i = startNum; i <= n; i++) {
11-
partial.push(i);
12-
helper(i + 1);
13-
partial.pop();
9+
if (start > n) {
10+
return;
1411
}
15-
};
1612

17-
helper();
18-
return ans;
19-
}
13+
// pick or not pick
14+
15+
// pick
16+
prevRes.push(start);
17+
backtracking(start + 1, prevRes);
18+
prevRes.pop(); // resume
19+
20+
// not pick
21+
backtracking(start + 1, prevRes);
22+
};
23+
backtracking(1, []);
24+
return ret;
25+
};
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ function numIslands(grid: string[][]): number {
55
const M = grid.length;
66
const N = grid[0].length;
77

8-
const dfs = (i: number, j: number): void => {
8+
const backtracking = (i: number, j: number): void => {
99
// boundary
1010
if (i < 0 || i >= M || j < 0 || j >= N) return;
1111

@@ -14,18 +14,16 @@ function numIslands(grid: string[][]): number {
1414

1515
grid[i][j] = "0";
1616

17-
dfs(i + 1, j);
18-
dfs(i, j + 1);
19-
dfs(i - 1, j);
20-
dfs(i, j - 1);
17+
backtracking(i + 1, j);
18+
backtracking(i, j + 1);
19+
backtracking(i - 1, j);
20+
backtracking(i, j - 1);
2121
};
2222

2323
for (let i = 0; i < M; i++) {
2424
for (let j = 0; j < N; j++) {
25-
if (grid[i][j] === "1") {
26-
dfs(i, j);
27-
ret++;
28-
}
25+
if (grid[i][j] === "1") ret++;
26+
backtracking(i, j);
2927
}
3028
}
3129
return ret;

src/backtracking/permutations.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
function permute(nums: number[]): number[][] {
1+
const permute = (nums: number[]): number[][] => {
2+
const N = nums.length; // boundary
23
const ret: number[][] = [];
3-
const backtracking = (nums: number[], level: number): void => {
4-
if (level === nums.length - 1) {
5-
ret.push([...nums]);
4+
const backtracking = (start: number): void => {
5+
// for this case we update the nums, instead of preRes
6+
if (start === N) {
7+
ret.push(Array.from(nums)); // using Array.from to hard copy
68
return;
79
}
810

9-
for (let i = level; i < nums.length; i++) {
10-
[nums[i], nums[level]] = [nums[level], nums[i]];
11-
backtracking(nums, level + 1);
12-
[nums[i], nums[level]] = [nums[level], nums[i]];
11+
for (let i = start; i < N; i++) {
12+
// swap (i!==start) or not (i===start)
13+
[nums[i], nums[start]] = [nums[start], nums[i]];
14+
backtracking(start + 1);
15+
[nums[i], nums[start]] = [nums[start], nums[i]];
16+
// ^^ resume the change
1317
}
1418
};
15-
backtracking(nums, 0);
16-
19+
backtracking(0);
1720
return ret;
18-
}
21+
};

src/backtracking/readme.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Summary of Backtracking
2+
3+
## Backtracking pattern
4+
5+
A recursion-based pattern
6+
7+
Sort of the permutation / combination / recursion based question, keep trying and update the state.
8+
9+
## Impementation
10+
11+
```typescript
12+
const N = input.length; // boundary
13+
const ret:number[] = []
14+
15+
const backtracking = (index:number, preRes:number[]):void => {
16+
if(index === N) {
17+
// collect the prevResult when we touch the boundary
18+
ret.push(Array.from(preRes))
19+
return;
20+
}
21+
}
22+
backtracking(index, [])
23+
24+
return ret
25+
```
26+
27+
## Example
28+
29+
77.Combinations
30+
```
31+
Input: n = 4, k = 2
32+
Output: [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4]]
33+
```
34+
35+
```typescript
36+
const combine = (n:number, k:number):number[][]=> {
37+
const ret:number[][] = [];
38+
39+
const backtracking = (start:number, prevRes:number[]):void=> {
40+
if(prevRes.length === k) {
41+
// satisfied length
42+
ret.push(Array.from(prevRes));
43+
return;
44+
}
45+
if(start > n) {
46+
// boundary
47+
return;
48+
}
49+
// pick or not pick
50+
// pick
51+
prevRes.push(start);
52+
backtracking(start+1, prevRes);
53+
prevRes.pop(); // resume
54+
// not pick
55+
backtracking(start+1, prevRes);
56+
57+
}
58+
backtracking(1, []);
59+
return ret;
60+
}
61+
```
62+
63+
## Thinking process
64+
65+
While we keep doing the same things in each iteration, and there're two state, choose or not choose, and we do both, keep going foward.
66+
67+
Since we keep going forward, so we check the boundary.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
function convertBST(root: TreeNode | null): TreeNode | null {
2+
const findMax = (root: TreeNode | null): TreeNode | null => {
3+
if (root === null) return null;
4+
while (root.left) {
5+
root = root.left;
6+
}
7+
return root;
8+
};
9+
const greaterTree = (root: TreeNode | null, initialValue = 0): TreeNode | null => {
10+
if (root === null) return null;
11+
if (root.right !== null) {
12+
root.right = greaterTree(root.right, initialValue);
13+
root.val += findMax(root.right)!.val;
14+
} else {
15+
root.val += initialValue;
16+
}
17+
root.left = greaterTree(root.left, root.val);
18+
return root;
19+
};
20+
return greaterTree(root);
21+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
function deleteNode(root: TreeNode | null, key: number): TreeNode | null {
2+
if (root === null) return root;
3+
if (root.val === key) {
4+
const { left, right } = root;
5+
if (left === null) return right;
6+
else if (right === null) return left;
7+
let ptr = left;
8+
while (ptr.right !== null) ptr = ptr.right;
9+
ptr.right = right;
10+
return left;
11+
} else if (root.left && root.left.val === key) {
12+
const { left, right } = root.left;
13+
if (left === null) root.left = right;
14+
else {
15+
let ptr = left;
16+
while (ptr.right !== null) ptr = ptr.right;
17+
ptr.right = right;
18+
root.left = left;
19+
}
20+
} else if (root.right && root.right.val === key) {
21+
const { left, right } = root.right;
22+
if (left === null) root.right = right;
23+
else {
24+
let ptr = left;
25+
while (ptr.right !== null) ptr = ptr.right;
26+
ptr.right = right;
27+
root.right = left;
28+
}
29+
} else if (root.val < key) {
30+
root.right = deleteNode(root.right, key);
31+
} else {
32+
root.left = deleteNode(root.left, key);
33+
}
34+
return root;
35+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
function increasingBST(root: TreeNode | null): TreeNode | null {
2+
// do in order traversal first
3+
if (root === null) return null;
4+
5+
const inorder = (node: TreeNode | null): number[] => {
6+
return node === null ? [] : [...inorder(node.left), node.val, ...inorder(node.right)];
7+
};
8+
9+
const nodes = inorder(root);
10+
const firstNode = nodes.shift()!;
11+
12+
let _root = new TreeNode(firstNode);
13+
const _root_ref = _root;
14+
while (nodes.length !== 0) {
15+
const node = nodes.shift()!;
16+
_root.right = new TreeNode(node);
17+
_root = _root.right;
18+
}
19+
return _root_ref;
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function lowestCommonAncestor(
2+
root: TreeNode | null,
3+
p: TreeNode | null,
4+
q: TreeNode | null
5+
): TreeNode | null {
6+
if (root === null) return null;
7+
if (p!.val < root.val && q!.val < root.val) {
8+
return lowestCommonAncestor(root.left, p, q);
9+
}
10+
if (p!.val > root.val && q!.val > root.val) {
11+
return lowestCommonAncestor(root.right, p, q);
12+
}
13+
return root;
14+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function minDiffInBST(root: TreeNode | null): number {
2+
let ret = Number.MAX_SAFE_INTEGER;
3+
const inorder = (node: TreeNode | null): number[] => {
4+
if (node === null) return [];
5+
6+
const left = inorder(node.left);
7+
const right = inorder(node.right);
8+
9+
ret = Math.min(
10+
ret,
11+
left.length === 0 ? Number.MAX_SAFE_INTEGER : node.val - left[left.length - 1],
12+
right.length === 0 ? Number.MAX_SAFE_INTEGER : right[0] - node.val
13+
);
14+
return [...left, node.val, ...right];
15+
};
16+
17+
inorder(root);
18+
return ret;
19+
}

src/binary-search-tree/readme.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Summary Binary Search Tree
2+
3+
## Recall the definition
4+
5+
1. Each tree node n, `n.left.val` < `n.val` < `n.right.val`
6+
2. So all left sub-tree values should smaller than root
7+
3. So all right sub-tree values should bigger than root
8+
9+
## Deal with the BST prob
10+
11+
1. Recursion, just focus on `node` & `node.left` & `node.right`
12+
- eg. `trim-a-binary-search-tree.ts`
13+
2. Scope the min val and max val question
14+
- recursion and pass as params
15+
- for `root.left`, max bound should be `root.val`
16+
- for `root.right`, min bound should be `root.val`
17+
- eg. `validate-binary-search-tree.ts`
18+
3. Inorder (LDR) traversal would be increasing sorted array
19+
4. Inorder traversal could be replaced to Morris traversal (space O(1)), by raising up the L tree, concat the D(root) to `rightmost` of L.
20+
5. Delete node `n`
21+
- raise up the `n.left`
22+
- Put the `n.right` to the rightmost of `n.left`
23+
- if `n.left` is null, just raising up `n.right`

0 commit comments

Comments
 (0)