Initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
11
README.md
Normal file
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# test-kata-machine
|
||||
|
||||
Kata machine practice.
|
||||
|
||||
https://frontendmasters.com/courses/algorithms/
|
||||
|
||||
https://github.com/ThePrimeagen/kata-machine
|
||||
|
||||
1. `pnpm install`
|
||||
|
||||
2. `pnpm test`
|
||||
19
package.json
Normal file
19
package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "test-kata-machine",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"test": "vitest",
|
||||
"format": "prettier --write ./src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^7.0.5",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"prettier": "^3.6.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tsconfig-paths-jest": "^0.0.1",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
1666
pnpm-lock.yaml
generated
Normal file
1666
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
8
prettier.config.ts
Normal file
8
prettier.config.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export default {
|
||||
tabWidth: 4,
|
||||
printWidth: 80,
|
||||
proseWrap: "never",
|
||||
trailingComma: "all",
|
||||
singleQuote: false,
|
||||
semi: true,
|
||||
};
|
||||
101
src/array-test.ts
Normal file
101
src/array-test.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
const a: number[] = [];
|
||||
|
||||
function time(fn: () => void): number {
|
||||
const now = Date.now();
|
||||
fn();
|
||||
return Date.now() - now;
|
||||
}
|
||||
|
||||
function unshift(number: number) {
|
||||
for (let i = 0; i < number; ++i) {
|
||||
a.unshift(Math.random());
|
||||
}
|
||||
}
|
||||
|
||||
function shift(number: number) {
|
||||
for (let i = 0; i < number; ++i) {
|
||||
a.shift();
|
||||
}
|
||||
}
|
||||
|
||||
function push(number: number) {
|
||||
for (let i = 0; i < number; ++i) {
|
||||
a.push(Math.random());
|
||||
}
|
||||
}
|
||||
|
||||
function pop(number: number) {
|
||||
for (let i = 0; i < number; ++i) {
|
||||
a.pop();
|
||||
}
|
||||
}
|
||||
|
||||
function get(idx: number) {
|
||||
return function () {
|
||||
return a[idx];
|
||||
};
|
||||
}
|
||||
|
||||
function push_arr(count: number) {
|
||||
return function () {
|
||||
push(count);
|
||||
};
|
||||
}
|
||||
|
||||
function pop_arr(count: number) {
|
||||
return function () {
|
||||
pop(count);
|
||||
};
|
||||
}
|
||||
|
||||
function unshift_arr(count: number) {
|
||||
return function () {
|
||||
unshift(count);
|
||||
};
|
||||
}
|
||||
|
||||
function shift_arr(count: number) {
|
||||
return function () {
|
||||
shift(count);
|
||||
};
|
||||
}
|
||||
|
||||
const tests = [10, 100, 1000, 10000, 100000, 1_000_000, 10_000_000];
|
||||
console.log("Testing get");
|
||||
tests.forEach((t) => {
|
||||
a.length = 0;
|
||||
push(t);
|
||||
console.log(t, time(get(t - 1)));
|
||||
});
|
||||
|
||||
console.log("push");
|
||||
tests.forEach((t) => {
|
||||
a.length = 0;
|
||||
push(t);
|
||||
|
||||
console.log(t, time(push_arr(1000)));
|
||||
});
|
||||
|
||||
console.log("pop");
|
||||
tests.forEach((t) => {
|
||||
a.length = 0;
|
||||
push(t);
|
||||
|
||||
console.log(t, time(pop_arr(1000)));
|
||||
});
|
||||
|
||||
console.log("unshift");
|
||||
tests.forEach((t) => {
|
||||
a.length = 0;
|
||||
push(t);
|
||||
|
||||
console.log(t, time(unshift_arr(1000)));
|
||||
});
|
||||
|
||||
console.log("shift");
|
||||
tests.forEach((t) => {
|
||||
a.length = 0;
|
||||
push(t);
|
||||
|
||||
console.log(t, time(shift_arr(1000)));
|
||||
});
|
||||
7
src/day1/ArrayList.test.ts
Normal file
7
src/day1/ArrayList.test.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import ArrayList from "@code/ArrayList";
|
||||
import { test_list } from "./ListTest";
|
||||
|
||||
test("array-list", function () {
|
||||
const list = new ArrayList<number>(3);
|
||||
test_list(list);
|
||||
});
|
||||
93
src/day1/ArrayList.ts
Normal file
93
src/day1/ArrayList.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
export default class ArrayList<T> {
|
||||
public length: number;
|
||||
private array: Array<T>;
|
||||
private capacity: number;
|
||||
|
||||
constructor(capacity: number = 5) {
|
||||
this.capacity = capacity;
|
||||
this.array = [];
|
||||
this.array.length = this.capacity;
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
private grow() {
|
||||
const old = this.array;
|
||||
this.capacity *= 2;
|
||||
this.array = [];
|
||||
this.array.length = this.capacity;
|
||||
|
||||
let i = 0;
|
||||
for (; i < this.length; ++i) {
|
||||
this.array[i] = old[i];
|
||||
}
|
||||
}
|
||||
|
||||
// ShiftRight manages the size of the array and shifts everything
|
||||
// from array[idx] one to the right. Creating free space at array[idx].
|
||||
private shiftRight(idx: number) {
|
||||
if (this.length == this.capacity) {
|
||||
this.grow();
|
||||
}
|
||||
|
||||
let i = this.length;
|
||||
for (; i > idx; --i) {
|
||||
this.array[i] = this.array[i - 1];
|
||||
}
|
||||
this.length++;
|
||||
}
|
||||
|
||||
// ShiftLeft manages the size of the array and shifts everything to the
|
||||
// right of array[idx] one to the left. Overwriting array[idx].
|
||||
private ShiftLeft(idx: number) {
|
||||
this.length--;
|
||||
let i = idx;
|
||||
for (; i < this.length; ++i) {
|
||||
this.array[i] = this.array[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
prepend(item: T): void {
|
||||
this.shiftRight(0);
|
||||
this.array[0] = item;
|
||||
}
|
||||
|
||||
insertAt(item: T, idx: number): void {
|
||||
this.shiftRight(idx);
|
||||
this.array[idx] = item;
|
||||
}
|
||||
|
||||
append(item: T): void {
|
||||
if (this.length == this.capacity) {
|
||||
this.grow();
|
||||
}
|
||||
|
||||
this.array[this.length] = item;
|
||||
this.length++;
|
||||
}
|
||||
|
||||
remove(item: T): T | undefined {
|
||||
let i = 0;
|
||||
for (; i < this.length; ++i) {
|
||||
if (this.array[i] == item) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// item was not found
|
||||
if (i == this.length) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.removeAt(i);
|
||||
}
|
||||
|
||||
get(idx: number): T | undefined {
|
||||
return idx >= this.length ? undefined : this.array[idx];
|
||||
}
|
||||
|
||||
removeAt(idx: number): T | undefined {
|
||||
const item = this.get(idx);
|
||||
this.ShiftLeft(idx);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
8
src/day1/BFSGraphList.test.ts
Normal file
8
src/day1/BFSGraphList.test.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import bfs from "@code/BFSGraphList";
|
||||
import { list2 } from "./graph";
|
||||
|
||||
test("bfs - graph", function () {
|
||||
expect(bfs(list2, 0, 6)).toEqual([0, 1, 4, 5, 6]);
|
||||
|
||||
expect(bfs(list2, 6, 0)).toEqual(null);
|
||||
});
|
||||
45
src/day1/BFSGraphList.ts
Normal file
45
src/day1/BFSGraphList.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
export default function bfs(
|
||||
graph: WeightedAdjacencyList,
|
||||
source: number,
|
||||
needle: number,
|
||||
): number[] | null {
|
||||
const seen = new Array(graph.length).fill(false);
|
||||
const prev = new Array(graph.length).fill(-1);
|
||||
|
||||
const queue: number[] = [source];
|
||||
seen[source] = true;
|
||||
|
||||
while (queue.length > 0) {
|
||||
const curr = queue.shift() as number;
|
||||
|
||||
if (curr === needle) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (const edge of graph[curr]) {
|
||||
const neighbor = edge.to;
|
||||
|
||||
if (seen[neighbor]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seen[neighbor] = true;
|
||||
prev[neighbor] = curr;
|
||||
queue.push(neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
if (!seen[needle]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const path: number[] = [];
|
||||
let curr = needle;
|
||||
|
||||
while (curr !== -1) {
|
||||
path.push(curr);
|
||||
curr = prev[curr];
|
||||
}
|
||||
|
||||
return path.reverse();
|
||||
}
|
||||
8
src/day1/BFSGraphMatrix.test.ts
Normal file
8
src/day1/BFSGraphMatrix.test.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import bfs from "@code/BFSGraphMatrix";
|
||||
import { matrix2 } from "./graph";
|
||||
|
||||
test("bfs - graph matrix", function () {
|
||||
expect(bfs(matrix2, 0, 6)).toEqual([0, 1, 4, 5, 6]);
|
||||
|
||||
expect(bfs(matrix2, 6, 0)).toEqual(null);
|
||||
});
|
||||
43
src/day1/BFSGraphMatrix.ts
Normal file
43
src/day1/BFSGraphMatrix.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
export default function bfs(
|
||||
graph: number[][],
|
||||
source: number,
|
||||
needle: number,
|
||||
): number[] | null {
|
||||
const seen = new Array(graph.length).fill(false);
|
||||
const prev = new Array(graph.length).fill(-1);
|
||||
const q: number[] = [source];
|
||||
seen[source] = true;
|
||||
|
||||
do {
|
||||
const curr = q.shift() as number;
|
||||
|
||||
if (curr === needle) {
|
||||
break;
|
||||
}
|
||||
|
||||
const adjs = graph[curr];
|
||||
for (let i = 0; i < graph.length; i++) {
|
||||
if (adjs[i] === 0 || seen[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seen[i] = true;
|
||||
prev[i] = curr;
|
||||
q.push(i);
|
||||
}
|
||||
} while (q.length);
|
||||
|
||||
if (prev[needle] === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let curr = needle;
|
||||
const out: number[] = [];
|
||||
|
||||
while (prev[curr] !== -1) {
|
||||
out.push(curr);
|
||||
curr = prev[curr];
|
||||
}
|
||||
|
||||
return [source].concat(out.reverse());
|
||||
}
|
||||
8
src/day1/BTBFS.test.ts
Normal file
8
src/day1/BTBFS.test.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import bfs from "@code/BTBFS";
|
||||
import { tree } from "./tree";
|
||||
|
||||
test("bt bfs", function () {
|
||||
expect(bfs(tree, 45)).toEqual(true);
|
||||
expect(bfs(tree, 7)).toEqual(true);
|
||||
expect(bfs(tree, 69)).toEqual(false);
|
||||
});
|
||||
20
src/day1/BTBFS.ts
Normal file
20
src/day1/BTBFS.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export default function bfs(head: BinaryNode<number>, needle: number): boolean {
|
||||
const q: (BinaryNode<number> | null)[] = [head];
|
||||
|
||||
while (q.length) {
|
||||
const curr = q.shift() as BinaryNode<number> | undefined | null;
|
||||
if (!curr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// search
|
||||
if (curr.value === needle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
q.push(curr.left);
|
||||
q.push(curr.right);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
6
src/day1/BTInOrder.test.ts
Normal file
6
src/day1/BTInOrder.test.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import bt_in_order from "@code/BTInOrder";
|
||||
import { tree } from "./tree";
|
||||
|
||||
test("In order", function () {
|
||||
expect(bt_in_order(tree)).toEqual([5, 7, 10, 15, 20, 29, 30, 45, 50, 100]);
|
||||
});
|
||||
17
src/day1/BTInOrder.ts
Normal file
17
src/day1/BTInOrder.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
function walk(curr: BinaryNode<number> | null, path: number[]): number[] {
|
||||
if (!curr) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// recurse
|
||||
walk(curr.left, path);
|
||||
path.push(curr.value);
|
||||
walk(curr.right, path);
|
||||
|
||||
// post
|
||||
return path;
|
||||
}
|
||||
|
||||
export default function in_order_search(head: BinaryNode<number>): number[] {
|
||||
return walk(head, []);
|
||||
}
|
||||
8
src/day1/BTPostOrder.test.ts
Normal file
8
src/day1/BTPostOrder.test.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import bt_post_order from "@code/BTPostOrder";
|
||||
import { tree } from "./tree";
|
||||
|
||||
test("post order", function () {
|
||||
expect(bt_post_order(tree)).toEqual([
|
||||
7, 5, 15, 10, 29, 45, 30, 100, 50, 20,
|
||||
]);
|
||||
});
|
||||
17
src/day1/BTPostOrder.ts
Normal file
17
src/day1/BTPostOrder.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
function walk(curr: BinaryNode<number> | null, path: number[]): number[] {
|
||||
if (!curr) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// recurse
|
||||
walk(curr.left, path);
|
||||
walk(curr.right, path);
|
||||
|
||||
// post
|
||||
path.push(curr.value);
|
||||
return path;
|
||||
}
|
||||
|
||||
export default function post_order_search(head: BinaryNode<number>): number[] {
|
||||
return walk(head, []);
|
||||
}
|
||||
6
src/day1/BTPreOrder.test.ts
Normal file
6
src/day1/BTPreOrder.test.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import bt_pre_order from "@code/BTPreOrder";
|
||||
import { tree } from "./tree";
|
||||
|
||||
test("Pre order", function () {
|
||||
expect(bt_pre_order(tree)).toEqual([20, 10, 5, 7, 15, 50, 30, 29, 45, 100]);
|
||||
});
|
||||
19
src/day1/BTPreOrder.ts
Normal file
19
src/day1/BTPreOrder.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
function walk(curr: BinaryNode<number> | null, path: number[]): number[] {
|
||||
if (!curr) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// pre
|
||||
path.push(curr.value);
|
||||
|
||||
// recurse
|
||||
walk(curr.left, path);
|
||||
walk(curr.right, path);
|
||||
|
||||
// post
|
||||
return path;
|
||||
}
|
||||
|
||||
export default function pre_order_search(head: BinaryNode<number>): number[] {
|
||||
return walk(head, []);
|
||||
}
|
||||
11
src/day1/BinarySearchList.test.ts
Normal file
11
src/day1/BinarySearchList.test.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import binary_fn from "@code/BinarySearchList";
|
||||
|
||||
test("binary search array", function () {
|
||||
const foo = [1, 3, 4, 69, 71, 81, 90, 99, 420, 1337, 69420];
|
||||
expect(binary_fn(foo, 69)).toEqual(true);
|
||||
expect(binary_fn(foo, 1336)).toEqual(false);
|
||||
expect(binary_fn(foo, 69420)).toEqual(true);
|
||||
expect(binary_fn(foo, 69421)).toEqual(false);
|
||||
expect(binary_fn(foo, 1)).toEqual(true);
|
||||
expect(binary_fn(foo, 0)).toEqual(false);
|
||||
});
|
||||
19
src/day1/BinarySearchList.ts
Normal file
19
src/day1/BinarySearchList.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export default function bs_list(haystack: number[], needle: number): boolean {
|
||||
let lo = 0;
|
||||
let hi = haystack.length;
|
||||
|
||||
while (lo < hi) {
|
||||
const m = Math.floor(lo + (hi - lo) / 2);
|
||||
const v = haystack[m];
|
||||
|
||||
if (v === needle) {
|
||||
return true;
|
||||
} else if (v > needle) {
|
||||
hi = m;
|
||||
} else {
|
||||
lo = m + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
9
src/day1/BubbleSort.test.ts
Normal file
9
src/day1/BubbleSort.test.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import bubble_sort from "@code/BubbleSort";
|
||||
|
||||
test("bubble-sort", function () {
|
||||
const arr = [9, 3, 7, 4, 69, 420, 42];
|
||||
|
||||
debugger;
|
||||
bubble_sort(arr);
|
||||
expect(arr).toEqual([3, 4, 7, 9, 42, 69, 420]);
|
||||
});
|
||||
11
src/day1/BubbleSort.ts
Normal file
11
src/day1/BubbleSort.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export default function bubble_sort(arr: number[]): void {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
for (let j = 0; j < arr.length - 1 - i; j++) {
|
||||
if (arr[j] > arr[j + 1]) {
|
||||
const tmp = arr[j];
|
||||
arr[j] = arr[j + 1];
|
||||
arr[j + 1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/day1/CompareBinaryTrees.test.ts
Normal file
7
src/day1/CompareBinaryTrees.test.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import compare from "@code/CompareBinaryTrees";
|
||||
import { tree, tree2 } from "./tree";
|
||||
|
||||
test("Compare Binary Trees", function () {
|
||||
expect(compare(tree, tree)).toEqual(true);
|
||||
expect(compare(tree, tree2)).toEqual(false);
|
||||
});
|
||||
21
src/day1/CompareBinaryTrees.ts
Normal file
21
src/day1/CompareBinaryTrees.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export default function compare(
|
||||
a: BinaryNode<number> | null,
|
||||
b: BinaryNode<number> | null,
|
||||
): boolean {
|
||||
// structual check
|
||||
if (a === null && b === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// structual check
|
||||
if (a === null || b === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// value check
|
||||
if (a?.value !== b?.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return compare(a.left, b.left) && compare(a.right, b.right);
|
||||
}
|
||||
8
src/day1/DFSGraphList.test.ts
Normal file
8
src/day1/DFSGraphList.test.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import dfs from "@code/DFSGraphList";
|
||||
import { list2 } from "./graph";
|
||||
|
||||
test("dfs - graph", function () {
|
||||
expect(dfs(list2, 0, 6)).toEqual([0, 1, 4, 5, 6]);
|
||||
|
||||
expect(dfs(list2, 6, 0)).toEqual(null);
|
||||
});
|
||||
50
src/day1/DFSGraphList.ts
Normal file
50
src/day1/DFSGraphList.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
function walk(
|
||||
graph: WeightedAdjacencyList,
|
||||
curr: number,
|
||||
needle: number,
|
||||
seen: boolean[],
|
||||
path: number[],
|
||||
): boolean {
|
||||
if (seen[curr]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
seen[curr] = true;
|
||||
|
||||
// pre
|
||||
path.push(curr);
|
||||
if (curr === needle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// recurse
|
||||
const list = graph[curr];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const edge = list[i];
|
||||
|
||||
if (walk(graph, edge.to, needle, seen, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// post
|
||||
path.pop();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export default function dfs(
|
||||
graph: WeightedAdjacencyList,
|
||||
source: number,
|
||||
needle: number,
|
||||
): number[] | null {
|
||||
const seen: boolean[] = new Array(graph.length).fill(false);
|
||||
const path: number[] = [];
|
||||
walk(graph, source, needle, seen, path);
|
||||
|
||||
if (path.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
8
src/day1/DFSOnBST.test.ts
Normal file
8
src/day1/DFSOnBST.test.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import dfs from "@code/DFSOnBST";
|
||||
import { tree } from "./tree";
|
||||
|
||||
test("DFS on BST", function () {
|
||||
expect(dfs(tree, 45)).toEqual(true);
|
||||
expect(dfs(tree, 7)).toEqual(true);
|
||||
expect(dfs(tree, 69)).toEqual(false);
|
||||
});
|
||||
19
src/day1/DFSOnBST.ts
Normal file
19
src/day1/DFSOnBST.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
function search(curr: BinaryNode<number> | null, needle: number): boolean {
|
||||
if (!curr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (curr.value === needle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (curr.value < needle) {
|
||||
return search(curr.right, needle);
|
||||
}
|
||||
|
||||
return search(curr.left, needle);
|
||||
}
|
||||
|
||||
export default function dfs(head: BinaryNode<number>, needle: number): boolean {
|
||||
return search(head, needle);
|
||||
}
|
||||
9
src/day1/DijkstraList.test.ts
Normal file
9
src/day1/DijkstraList.test.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import dijkstra_list from "@code/DijkstraList";
|
||||
import { list1 } from "./graph";
|
||||
|
||||
test("dijkstra via adj list", function () {
|
||||
/// waht?
|
||||
// what..
|
||||
// what...
|
||||
expect(dijkstra_list(0, 6, list1)).toEqual([0, 1, 4, 5, 6]);
|
||||
});
|
||||
61
src/day1/DijkstraList.ts
Normal file
61
src/day1/DijkstraList.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
function hasUnvisited(seen: boolean[], dists: number[]): boolean {
|
||||
return seen.some((s, i) => !s && dists[i] < Infinity);
|
||||
}
|
||||
|
||||
function getLowestUnvisited(seen: boolean[], dists: number[]): number {
|
||||
let idx = -1;
|
||||
let lowestDistance = Infinity;
|
||||
|
||||
for (let i = 0; i < seen.length; i++) {
|
||||
if (seen[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lowestDistance > dists[i]) {
|
||||
lowestDistance = dists[i];
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
export default function dijkstra_list(
|
||||
source: number,
|
||||
sink: number,
|
||||
arr: WeightedAdjacencyList,
|
||||
): number[] {
|
||||
const seen = new Array(arr.length).fill(false);
|
||||
const prev = new Array(arr.length).fill(-1);
|
||||
const dists = new Array(arr.length).fill(Infinity);
|
||||
dists[source] = 0;
|
||||
|
||||
while (hasUnvisited(seen, dists)) {
|
||||
const curr = getLowestUnvisited(seen, dists);
|
||||
seen[curr] = true;
|
||||
|
||||
const adjs = arr[curr];
|
||||
for (let i = 0; i < adjs.length; i++) {
|
||||
const edge = adjs[i];
|
||||
if (seen[edge.to]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const dist = dists[curr] + edge.weight;
|
||||
if (dist < dists[edge.to]) {
|
||||
dists[edge.to] = dist;
|
||||
prev[edge.to] = curr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let curr = sink;
|
||||
const out: number[] = [];
|
||||
|
||||
while (prev[curr] !== -1) {
|
||||
out.push(curr);
|
||||
curr = prev[curr];
|
||||
}
|
||||
|
||||
return [source].concat(out.reverse());
|
||||
}
|
||||
7
src/day1/DoublyLinkedList.test.ts
Normal file
7
src/day1/DoublyLinkedList.test.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import LinkedList from "@code/DoublyLinkedList";
|
||||
import { test_list } from "./ListTest";
|
||||
|
||||
test("DoublyLinkedList", function () {
|
||||
const list = new LinkedList<number>();
|
||||
test_list(list);
|
||||
});
|
||||
136
src/day1/DoublyLinkedList.ts
Normal file
136
src/day1/DoublyLinkedList.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
class Node<T> {
|
||||
public value: T;
|
||||
public prev?: Node<T>;
|
||||
public next?: Node<T>;
|
||||
}
|
||||
|
||||
export default class DoublyLinkedList<T> {
|
||||
public length: number;
|
||||
public head?: Node<T>;
|
||||
public tail?: Node<T>;
|
||||
|
||||
constructor() {
|
||||
this.length = 0;
|
||||
this.head = undefined;
|
||||
}
|
||||
|
||||
prepend(item: T): void {
|
||||
const node = { value: item } as Node<T>;
|
||||
this.length++;
|
||||
|
||||
if (!this.head) {
|
||||
this.head = node;
|
||||
this.tail = node;
|
||||
return;
|
||||
}
|
||||
|
||||
node.next = this.head;
|
||||
this.head.prev = node;
|
||||
this.head = node;
|
||||
}
|
||||
|
||||
insertAt(item: T, idx: number): void {
|
||||
if (idx > this.length) {
|
||||
throw new Error("oh no");
|
||||
} else if (idx === this.length) {
|
||||
this.append(item);
|
||||
return;
|
||||
} else if (idx === 0) {
|
||||
this.prepend(item);
|
||||
}
|
||||
|
||||
this.length++;
|
||||
const curr = this.getAt(idx) as Node<T>;
|
||||
const node = { value: item } as Node<T>;
|
||||
|
||||
node.next = curr;
|
||||
node.prev = curr.prev;
|
||||
curr.prev = node;
|
||||
|
||||
if (node.prev) {
|
||||
node.prev.next = node;
|
||||
}
|
||||
}
|
||||
|
||||
append(item: T): void {
|
||||
const node = { value: item } as Node<T>;
|
||||
this.length++;
|
||||
|
||||
if (!this.tail) {
|
||||
this.head = node;
|
||||
this.tail = node;
|
||||
return;
|
||||
}
|
||||
|
||||
node.prev = this.tail;
|
||||
this.tail.next = node;
|
||||
this.tail = node;
|
||||
}
|
||||
|
||||
remove(item: T): T | undefined {
|
||||
let curr = this.head;
|
||||
for (let i = 0; curr && i < this.length; i++) {
|
||||
if (curr.value === item) {
|
||||
break;
|
||||
}
|
||||
curr = curr.next;
|
||||
}
|
||||
|
||||
if (!curr) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.removeNode(curr);
|
||||
}
|
||||
|
||||
get(idx: number): T | undefined {
|
||||
return this.getAt(idx)?.value;
|
||||
}
|
||||
|
||||
removeAt(idx: number): T | undefined {
|
||||
const node = this.getAt(idx);
|
||||
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
return this.removeNode(node);
|
||||
}
|
||||
|
||||
private removeNode(node: Node<T>): T | undefined {
|
||||
this.length--;
|
||||
|
||||
if (this.length === 0) {
|
||||
const out = this.head?.value;
|
||||
this.head = undefined;
|
||||
this.tail = undefined;
|
||||
return out;
|
||||
}
|
||||
|
||||
if (node.prev) {
|
||||
node.prev.next = node.next;
|
||||
}
|
||||
if (node.next) {
|
||||
node.next.prev = node.prev;
|
||||
}
|
||||
|
||||
if (node === this.head) {
|
||||
this.head = node.next;
|
||||
}
|
||||
if (node === this.tail) {
|
||||
this.tail = node.prev;
|
||||
}
|
||||
|
||||
node.prev = undefined;
|
||||
node.next = undefined;
|
||||
|
||||
return node.value;
|
||||
}
|
||||
|
||||
private getAt(idx: number): Node<T> | undefined {
|
||||
let curr = this.head;
|
||||
for (let i = 0; curr && i < idx; i++) {
|
||||
curr = curr.next;
|
||||
}
|
||||
return curr;
|
||||
}
|
||||
}
|
||||
9
src/day1/InsertionSort.test.ts
Normal file
9
src/day1/InsertionSort.test.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import insertion_sort from "@code/InsertionSort";
|
||||
|
||||
test("insertion-sort", function () {
|
||||
const arr = [9, 3, 7, 4, 69, 420, 42];
|
||||
debugger;
|
||||
// where is my debugger
|
||||
insertion_sort(arr);
|
||||
expect(arr).toEqual([3, 4, 7, 9, 42, 69, 420]);
|
||||
});
|
||||
13
src/day1/InsertionSort.ts
Normal file
13
src/day1/InsertionSort.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export default function insertion_sort(arr: number[]): void {
|
||||
for (let i = 1; i < arr.length; i++) {
|
||||
const key = arr[i];
|
||||
let j = i - 1;
|
||||
|
||||
while (j >= 0 && arr[j] > key) {
|
||||
arr[j + 1] = arr[j];
|
||||
j--;
|
||||
}
|
||||
|
||||
arr[j + 1] = key;
|
||||
}
|
||||
}
|
||||
27
src/day1/LRU.test.ts
Normal file
27
src/day1/LRU.test.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import LRU from "@code/LRU";
|
||||
|
||||
test("LRU", function () {
|
||||
const lru = new LRU<string, number>(3) as ILRU<string, number>;
|
||||
|
||||
expect(lru.get("foo")).toEqual(undefined);
|
||||
lru.update("foo", 69);
|
||||
expect(lru.get("foo")).toEqual(69);
|
||||
|
||||
lru.update("bar", 420);
|
||||
expect(lru.get("bar")).toEqual(420);
|
||||
|
||||
lru.update("baz", 1337);
|
||||
expect(lru.get("baz")).toEqual(1337);
|
||||
|
||||
lru.update("ball", 69420);
|
||||
expect(lru.get("ball")).toEqual(69420);
|
||||
expect(lru.get("foo")).toEqual(undefined);
|
||||
expect(lru.get("bar")).toEqual(420);
|
||||
lru.update("foo", 69);
|
||||
expect(lru.get("bar")).toEqual(420);
|
||||
expect(lru.get("foo")).toEqual(69);
|
||||
|
||||
// shouldn't of been deleted, but since bar was get'd, bar was added to the
|
||||
// front of the list, so baz became the end
|
||||
expect(lru.get("baz")).toEqual(undefined);
|
||||
});
|
||||
99
src/day1/LRU.ts
Normal file
99
src/day1/LRU.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
function createNode<V>(value: V): Node<V> {
|
||||
return { value };
|
||||
}
|
||||
|
||||
export default class LRU<K, V> {
|
||||
private length: number;
|
||||
private capacity: number;
|
||||
private head?: Node<V>;
|
||||
private tail?: Node<V>;
|
||||
private lookup: Map<K, Node<V>>;
|
||||
private reverseLookup: Map<Node<V>, K>;
|
||||
|
||||
constructor(capacity: number) {
|
||||
this.length = 0;
|
||||
this.capacity = capacity;
|
||||
this.head = this.tail = undefined;
|
||||
this.lookup = new Map<K, Node<V>>();
|
||||
this.reverseLookup = new Map<Node<V>, K>();
|
||||
}
|
||||
|
||||
update(key: K, value: V): void {
|
||||
// check the cache for existence
|
||||
let node = this.lookup.get(key);
|
||||
if (!node) {
|
||||
node = createNode(value);
|
||||
this.length++;
|
||||
this.prepend(node);
|
||||
this.trimCache();
|
||||
|
||||
this.lookup.set(key, node);
|
||||
this.reverseLookup.set(node, key);
|
||||
} else {
|
||||
this.detach(node);
|
||||
this.prepend(node);
|
||||
node.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
get(key: K): V | undefined {
|
||||
// check the cache for existence
|
||||
const node = this.lookup.get(key);
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// update the value we found and move it to the front
|
||||
this.detach(node);
|
||||
this.prepend(node);
|
||||
|
||||
// return out the value found
|
||||
return node.value;
|
||||
}
|
||||
|
||||
private detach(node: Node<V>): void {
|
||||
if (node.prev) {
|
||||
node.prev.next = node.next;
|
||||
}
|
||||
|
||||
if (node.next) {
|
||||
node.next.prev = node.prev;
|
||||
}
|
||||
|
||||
if (this.head === node) {
|
||||
this.head = this.head.next;
|
||||
}
|
||||
|
||||
if (this.tail === node) {
|
||||
this.tail = this.tail.prev;
|
||||
}
|
||||
|
||||
node.next = undefined;
|
||||
node.prev = undefined;
|
||||
}
|
||||
|
||||
private prepend(node: Node<V>): void {
|
||||
if (!this.head) {
|
||||
this.head = this.tail = node;
|
||||
return;
|
||||
}
|
||||
|
||||
node.next = this.head;
|
||||
this.head.prev = node;
|
||||
this.head = node;
|
||||
}
|
||||
|
||||
private trimCache(): void {
|
||||
if (this.length <= this.capacity) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tail = this.tail as Node<V>;
|
||||
this.detach(this.tail as Node<V>);
|
||||
|
||||
const key = this.reverseLookup.get(tail) as K;
|
||||
this.lookup.delete(key);
|
||||
this.reverseLookup.delete(tail);
|
||||
this.length--;
|
||||
}
|
||||
}
|
||||
11
src/day1/LinearSearchList.test.ts
Normal file
11
src/day1/LinearSearchList.test.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import linear_fn from "@code/LinearSearchList";
|
||||
|
||||
test("linear search array", function () {
|
||||
const foo = [1, 3, 4, 69, 71, 81, 90, 99, 420, 1337, 69420];
|
||||
expect(linear_fn(foo, 69)).toEqual(true);
|
||||
expect(linear_fn(foo, 1336)).toEqual(false);
|
||||
expect(linear_fn(foo, 69420)).toEqual(true);
|
||||
expect(linear_fn(foo, 69421)).toEqual(false);
|
||||
expect(linear_fn(foo, 1)).toEqual(true);
|
||||
expect(linear_fn(foo, 0)).toEqual(false);
|
||||
});
|
||||
12
src/day1/LinearSearchList.ts
Normal file
12
src/day1/LinearSearchList.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export default function linear_search(
|
||||
haystack: number[],
|
||||
needle: number,
|
||||
): boolean {
|
||||
for (let i = 0; i < haystack.length; i++) {
|
||||
if (haystack[i] === needle) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
26
src/day1/ListTest.ts
Normal file
26
src/day1/ListTest.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
export function test_list(list: List<number>): void {
|
||||
list.append(5);
|
||||
list.append(7);
|
||||
list.append(9);
|
||||
|
||||
expect(list.get(2)).toEqual(9);
|
||||
expect(list.removeAt(1)).toEqual(7);
|
||||
expect(list.length).toEqual(2);
|
||||
|
||||
list.append(11);
|
||||
expect(list.removeAt(1)).toEqual(9);
|
||||
expect(list.remove(9)).toEqual(undefined);
|
||||
expect(list.removeAt(0)).toEqual(5);
|
||||
expect(list.removeAt(0)).toEqual(11);
|
||||
expect(list.length).toEqual(0);
|
||||
|
||||
list.prepend(5);
|
||||
list.prepend(7);
|
||||
list.prepend(9);
|
||||
|
||||
expect(list.get(2)).toEqual(5);
|
||||
expect(list.get(0)).toEqual(9);
|
||||
expect(list.remove(9)).toEqual(9);
|
||||
expect(list.length).toEqual(2);
|
||||
expect(list.get(0)).toEqual(7);
|
||||
}
|
||||
23
src/day1/Map.test.ts
Normal file
23
src/day1/Map.test.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import MyMap from "@code/Map";
|
||||
|
||||
test("Map", function () {
|
||||
const map = new MyMap<string, number>();
|
||||
map.set("foo", 55);
|
||||
expect(map.size()).toEqual(1);
|
||||
map.set("fool", 75);
|
||||
expect(map.size()).toEqual(2);
|
||||
map.set("foolish", 105);
|
||||
expect(map.size()).toEqual(3);
|
||||
map.set("bar", 69);
|
||||
expect(map.size()).toEqual(4);
|
||||
|
||||
expect(map.get("bar")).toEqual(69);
|
||||
expect(map.get("blaz")).toEqual(undefined);
|
||||
|
||||
map.delete("barblabr");
|
||||
expect(map.size()).toEqual(4);
|
||||
|
||||
map.delete("bar");
|
||||
expect(map.size()).toEqual(3);
|
||||
expect(map.get("bar")).toEqual(undefined);
|
||||
});
|
||||
34
src/day1/Map.ts
Normal file
34
src/day1/Map.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
export default class Map<T extends string | number, V> {
|
||||
private store: { [key: string]: V };
|
||||
private count: number;
|
||||
|
||||
constructor() {
|
||||
this.store = {};
|
||||
this.count = 0;
|
||||
}
|
||||
|
||||
get(key: T): V | undefined {
|
||||
return this.store.hasOwnProperty(key) ? this.store[key] : undefined;
|
||||
}
|
||||
|
||||
set(key: T, value: V): void {
|
||||
if (!this.store.hasOwnProperty(key)) {
|
||||
this.count++;
|
||||
}
|
||||
this.store[key] = value;
|
||||
}
|
||||
|
||||
delete(key: T): V | undefined {
|
||||
if (this.store.hasOwnProperty(key)) {
|
||||
const value = this.store[key];
|
||||
delete this.store[key];
|
||||
this.count--;
|
||||
return value;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
size(): number {
|
||||
return this.count;
|
||||
}
|
||||
}
|
||||
44
src/day1/MazeSolver.test.ts
Normal file
44
src/day1/MazeSolver.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import maze_solver from "@code/MazeSolver";
|
||||
|
||||
test("maze solver", function () {
|
||||
const maze = [
|
||||
"xxxxxxxxxx x",
|
||||
"x x x",
|
||||
"x x x",
|
||||
"x xxxxxxxx x",
|
||||
"x x",
|
||||
"x xxxxxxxxxx",
|
||||
];
|
||||
|
||||
const mazeResult = [
|
||||
{ x: 10, y: 0 },
|
||||
{ x: 10, y: 1 },
|
||||
{ x: 10, y: 2 },
|
||||
{ x: 10, y: 3 },
|
||||
{ x: 10, y: 4 },
|
||||
{ x: 9, y: 4 },
|
||||
{ x: 8, y: 4 },
|
||||
{ x: 7, y: 4 },
|
||||
{ x: 6, y: 4 },
|
||||
{ x: 5, y: 4 },
|
||||
{ x: 4, y: 4 },
|
||||
{ x: 3, y: 4 },
|
||||
{ x: 2, y: 4 },
|
||||
{ x: 1, y: 4 },
|
||||
{ x: 1, y: 5 },
|
||||
];
|
||||
|
||||
// there is only one path through
|
||||
const result = maze_solver(maze, "x", { x: 10, y: 0 }, { x: 1, y: 5 });
|
||||
expect(drawPath(maze, result)).toEqual(drawPath(maze, mazeResult));
|
||||
});
|
||||
|
||||
function drawPath(data: string[], path: Point[]) {
|
||||
const data2 = data.map((row) => row.split(""));
|
||||
path.forEach((p) => {
|
||||
if (data2[p.y] && data2[p.y][p.x]) {
|
||||
data2[p.y][p.x] = "*";
|
||||
}
|
||||
});
|
||||
return data2.map((d) => d.join(""));
|
||||
}
|
||||
57
src/day1/MazeSolver.ts
Normal file
57
src/day1/MazeSolver.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
export default function solve(
|
||||
maze: string[],
|
||||
wall: string,
|
||||
start: Point,
|
||||
end: Point,
|
||||
): Point[] {
|
||||
const numRows = maze.length;
|
||||
const numCols = maze[0].length;
|
||||
const visited = new Set<string>();
|
||||
const queue: { point: Point; path: Point[] }[] = [];
|
||||
|
||||
function isValid(x: number, y: number): boolean {
|
||||
return (
|
||||
x >= 0 &&
|
||||
x < numCols &&
|
||||
y >= 0 &&
|
||||
y < numRows &&
|
||||
maze[y][x] !== wall
|
||||
);
|
||||
}
|
||||
|
||||
const key = (p: Point) => `${p.x},${p.y}`;
|
||||
|
||||
queue.push({ point: start, path: [start] });
|
||||
visited.add(key(start));
|
||||
|
||||
const directions = [
|
||||
// up
|
||||
{ x: 0, y: -1 },
|
||||
// right
|
||||
{ x: 1, y: 0 },
|
||||
// down
|
||||
{ x: 0, y: 1 },
|
||||
// left
|
||||
{ x: -1, y: 0 },
|
||||
];
|
||||
|
||||
while (queue.length > 0) {
|
||||
const { point, path } = queue.shift()!;
|
||||
if (point.x === end.x && point.y === end.y) {
|
||||
return path;
|
||||
}
|
||||
|
||||
for (const dir of directions) {
|
||||
const next = { x: point.x + dir.x, y: point.y + dir.y };
|
||||
const nextKey = key(next);
|
||||
|
||||
if (isValid(next.x, next.y) && !visited.has(nextKey)) {
|
||||
visited.add(nextKey);
|
||||
queue.push({ point: next, path: [...path, next] });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No path found
|
||||
return [];
|
||||
}
|
||||
7
src/day1/MergeSort.test.ts
Normal file
7
src/day1/MergeSort.test.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import merge_sort from "@code/MergeSort";
|
||||
|
||||
test("merge-sort", function () {
|
||||
const arr = [9, 3, 7, 4, 69, 420, 42];
|
||||
merge_sort(arr);
|
||||
expect(arr).toEqual([3, 4, 7, 9, 42, 69, 420]);
|
||||
});
|
||||
36
src/day1/MergeSort.ts
Normal file
36
src/day1/MergeSort.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
function mergeSortHelper(arr: number[], start: number, end: number): void {
|
||||
if (start >= end) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mid = Math.floor((start + end) / 2);
|
||||
|
||||
mergeSortHelper(arr, start, mid);
|
||||
mergeSortHelper(arr, mid + 1, end);
|
||||
|
||||
merge(arr, start, mid, end);
|
||||
}
|
||||
|
||||
function merge(arr: number[], start: number, mid: number, end: number): void {
|
||||
const left = arr.slice(start, mid + 1);
|
||||
const right = arr.slice(mid + 1, end + 1);
|
||||
|
||||
let i = 0;
|
||||
let j = 0;
|
||||
let k = start;
|
||||
|
||||
while (i < left.length && j < right.length) {
|
||||
arr[k++] = left[i] <= right[j] ? left[i++] : right[j++];
|
||||
}
|
||||
|
||||
while (i < left.length) {
|
||||
arr[k++] = left[i++];
|
||||
}
|
||||
while (j < right.length) {
|
||||
arr[k++] = right[j++];
|
||||
}
|
||||
}
|
||||
|
||||
export default function merge_sort(arr: number[]): void {
|
||||
mergeSortHelper(arr, 0, arr.length - 1);
|
||||
}
|
||||
28
src/day1/MinHeap.test.ts
Normal file
28
src/day1/MinHeap.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import MinHeap from "@code/MinHeap";
|
||||
|
||||
test("min heap", function () {
|
||||
const heap = new MinHeap();
|
||||
|
||||
expect(heap.length).toEqual(0);
|
||||
|
||||
heap.insert(5);
|
||||
heap.insert(3);
|
||||
heap.insert(69);
|
||||
heap.insert(420);
|
||||
heap.insert(4);
|
||||
heap.insert(1);
|
||||
heap.insert(8);
|
||||
heap.insert(7);
|
||||
|
||||
expect(heap.length).toEqual(8);
|
||||
expect(heap.delete()).toEqual(1);
|
||||
expect(heap.delete()).toEqual(3);
|
||||
expect(heap.delete()).toEqual(4);
|
||||
expect(heap.delete()).toEqual(5);
|
||||
expect(heap.length).toEqual(4);
|
||||
expect(heap.delete()).toEqual(7);
|
||||
expect(heap.delete()).toEqual(8);
|
||||
expect(heap.delete()).toEqual(69);
|
||||
expect(heap.delete()).toEqual(420);
|
||||
expect(heap.length).toEqual(0);
|
||||
});
|
||||
89
src/day1/MinHeap.ts
Normal file
89
src/day1/MinHeap.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
export default class MinHeap {
|
||||
public length: number;
|
||||
private data: number[];
|
||||
|
||||
constructor() {
|
||||
this.data = [];
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
insert(value: number): void {
|
||||
this.data[this.length] = value;
|
||||
this.heapifyUp(this.length);
|
||||
this.length++;
|
||||
}
|
||||
|
||||
delete(): number {
|
||||
if (this.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const out = this.data[0];
|
||||
this.length--;
|
||||
|
||||
if (this.length === 0) {
|
||||
this.data = [];
|
||||
return out;
|
||||
}
|
||||
|
||||
this.data[0] = this.data[this.length];
|
||||
this.heapifyDown(0);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private heapifyDown(idx: number): void {
|
||||
const lIdx = this.leftChild(idx);
|
||||
const rIdx = this.rightChild(idx);
|
||||
|
||||
if (idx >= this.length || lIdx >= this.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lV = this.data[lIdx];
|
||||
const rV = this.data[rIdx];
|
||||
const v = this.data[idx];
|
||||
|
||||
if (lV > rV && v > rV) {
|
||||
this.data[idx] = rV;
|
||||
this.data[rIdx] = v;
|
||||
this.heapifyDown(rIdx);
|
||||
} else if (rV > lV && v > lV) {
|
||||
this.data[idx] = lV;
|
||||
this.data[lIdx] = v;
|
||||
this.heapifyDown(lIdx);
|
||||
} else if (lV == rV && v > rV) {
|
||||
this.data[idx] = rV;
|
||||
this.data[rIdx] = v;
|
||||
this.heapifyDown(rIdx);
|
||||
}
|
||||
}
|
||||
|
||||
private heapifyUp(idx: number): void {
|
||||
if (idx === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const p = this.parent(idx);
|
||||
const parentV = this.data[p];
|
||||
const v = this.data[idx];
|
||||
|
||||
if (parentV > v) {
|
||||
this.data[idx] = parentV;
|
||||
this.data[p] = v;
|
||||
this.heapifyUp(p);
|
||||
}
|
||||
}
|
||||
|
||||
private parent(idx: number): number {
|
||||
return Math.floor((idx - 1) / 2);
|
||||
}
|
||||
|
||||
private leftChild(idx: number): number {
|
||||
return idx * 2 + 1;
|
||||
}
|
||||
|
||||
private rightChild(idx: number): number {
|
||||
return idx * 2 + 2;
|
||||
}
|
||||
}
|
||||
58
src/day1/PrimsAlgorithm.ts
Normal file
58
src/day1/PrimsAlgorithm.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
export default function prims(
|
||||
list: WeightedAdjacencyList,
|
||||
): WeightedAdjacencyList | null {
|
||||
const n = list.length;
|
||||
if (n === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const inMST = new Array(n).fill(false);
|
||||
const mst: WeightedAdjacencyList = Array.from({ length: n }, () => []);
|
||||
|
||||
const minEdge: { to: number; from: number; weight: number }[] = new Array(
|
||||
n,
|
||||
).fill(null as any);
|
||||
minEdge[0] = { to: 0, from: -1, weight: 0 };
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let u = -1;
|
||||
|
||||
for (let v = 0; v < n; v++) {
|
||||
if (
|
||||
!inMST[v] &&
|
||||
(u === -1 ||
|
||||
(minEdge[v] && minEdge[v].weight < minEdge[u].weight))
|
||||
) {
|
||||
u = v;
|
||||
}
|
||||
}
|
||||
|
||||
if (u === -1 || minEdge[u] === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
inMST[u] = true;
|
||||
|
||||
const edge = minEdge[u];
|
||||
if (edge.from !== -1) {
|
||||
mst[edge.from].push({ to: u, weight: edge.weight });
|
||||
mst[u].push({ to: edge.from, weight: edge.weight });
|
||||
}
|
||||
|
||||
for (const neighbor of list[u]) {
|
||||
if (
|
||||
!inMST[neighbor.to] &&
|
||||
(!minEdge[neighbor.to] ||
|
||||
neighbor.weight < minEdge[neighbor.to].weight)
|
||||
) {
|
||||
minEdge[neighbor.to] = {
|
||||
to: neighbor.to,
|
||||
from: u,
|
||||
weight: neighbor.weight,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mst;
|
||||
}
|
||||
30
src/day1/PrimsList.test.ts
Normal file
30
src/day1/PrimsList.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import prims from "@code/PrimsAlgorithm";
|
||||
import { list1 } from "./graph";
|
||||
|
||||
test("PrimsAlgorithm", function () {
|
||||
// there is only one right answer for this graph
|
||||
expect(prims(list1)).toEqual([
|
||||
[
|
||||
{ to: 2, weight: 1 },
|
||||
{ to: 1, weight: 3 },
|
||||
],
|
||||
[
|
||||
{ to: 0, weight: 3 },
|
||||
{ to: 4, weight: 1 },
|
||||
],
|
||||
[{ to: 0, weight: 1 }],
|
||||
[{ to: 6, weight: 1 }],
|
||||
[
|
||||
{ to: 1, weight: 1 },
|
||||
{ to: 5, weight: 2 },
|
||||
],
|
||||
[
|
||||
{ to: 4, weight: 2 },
|
||||
{ to: 6, weight: 1 },
|
||||
],
|
||||
[
|
||||
{ to: 5, weight: 1 },
|
||||
{ to: 3, weight: 1 },
|
||||
],
|
||||
]);
|
||||
});
|
||||
31
src/day1/Queue.test.ts
Normal file
31
src/day1/Queue.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import Queue from "@code/Queue";
|
||||
|
||||
test("queue", function () {
|
||||
const list = new Queue<number>();
|
||||
|
||||
list.enqueue(5);
|
||||
list.enqueue(7);
|
||||
list.enqueue(9);
|
||||
|
||||
expect(list.deque()).toEqual(5);
|
||||
expect(list.length).toEqual(2);
|
||||
|
||||
// this must be wrong..?
|
||||
debugger;
|
||||
|
||||
// i hate using debuggers
|
||||
list.enqueue(11);
|
||||
debugger;
|
||||
expect(list.deque()).toEqual(7);
|
||||
expect(list.deque()).toEqual(9);
|
||||
expect(list.peek()).toEqual(11);
|
||||
expect(list.deque()).toEqual(11);
|
||||
expect(list.deque()).toEqual(undefined);
|
||||
expect(list.length).toEqual(0);
|
||||
|
||||
// just wanted to make sure that I could not blow up myself when i remove
|
||||
// everything
|
||||
list.enqueue(69);
|
||||
expect(list.peek()).toEqual(69);
|
||||
expect(list.length).toEqual(1);
|
||||
});
|
||||
50
src/day1/Queue.ts
Normal file
50
src/day1/Queue.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
type Node<T> = {
|
||||
value: T;
|
||||
next?: Node<T>;
|
||||
};
|
||||
|
||||
export default class Queue<T> {
|
||||
public length: number;
|
||||
private head?: Node<T>;
|
||||
private tail?: Node<T>;
|
||||
|
||||
constructor() {
|
||||
this.head = undefined;
|
||||
this.tail = undefined;
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
enqueue(item: T): void {
|
||||
const node = { value: item } as Node<T>;
|
||||
this.length++;
|
||||
if (!this.tail) {
|
||||
this.head = node;
|
||||
this.tail = node;
|
||||
return;
|
||||
}
|
||||
|
||||
this.tail.next = node;
|
||||
this.tail = node;
|
||||
}
|
||||
|
||||
deque(): T | undefined {
|
||||
if (!this.head) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this.length--;
|
||||
const head = this.head;
|
||||
this.head = this.head.next;
|
||||
head.next = undefined;
|
||||
|
||||
if (this.length === 0) {
|
||||
this.tail = undefined;
|
||||
}
|
||||
|
||||
return head.value;
|
||||
}
|
||||
|
||||
peek(): T | undefined {
|
||||
return this.head?.value;
|
||||
}
|
||||
}
|
||||
9
src/day1/QuickSort.test.ts
Normal file
9
src/day1/QuickSort.test.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import quick_sort from "@code/QuickSort";
|
||||
|
||||
test("quick-sort", function () {
|
||||
const arr = [9, 3, 7, 4, 69, 420, 42];
|
||||
|
||||
debugger;
|
||||
quick_sort(arr);
|
||||
expect(arr).toEqual([3, 4, 7, 9, 42, 69, 420]);
|
||||
});
|
||||
34
src/day1/QuickSort.ts
Normal file
34
src/day1/QuickSort.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
function qs(arr: number[], lo: number, hi: number): void {
|
||||
if (lo >= hi) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pivotIdx = partition(arr, lo, hi);
|
||||
|
||||
qs(arr, lo, pivotIdx - 1);
|
||||
qs(arr, pivotIdx + 1, hi);
|
||||
}
|
||||
|
||||
function partition(arr: number[], lo: number, hi: number): number {
|
||||
const pivot = arr[hi];
|
||||
let idx = lo - 1;
|
||||
|
||||
for (let i = lo; i < hi; i++) {
|
||||
if (arr[i] <= pivot) {
|
||||
idx++;
|
||||
const tmp = arr[i];
|
||||
arr[i] = arr[idx];
|
||||
arr[idx] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
idx++;
|
||||
arr[hi] = arr[idx];
|
||||
arr[idx] = pivot;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
export default function quick_sort(arr: number[]): void {
|
||||
qs(arr, 0, arr.length - 1);
|
||||
}
|
||||
22
src/day1/RingBuffer.test.ts
Normal file
22
src/day1/RingBuffer.test.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import RingBuffer from "@code/RingBuffer";
|
||||
|
||||
test("RingBuffer", function () {
|
||||
const buffer = new RingBuffer<number>();
|
||||
|
||||
buffer.push(5);
|
||||
expect(buffer.pop()).toEqual(5);
|
||||
expect(buffer.pop()).toEqual(undefined);
|
||||
|
||||
buffer.push(42);
|
||||
buffer.push(9);
|
||||
expect(buffer.pop()).toEqual(42);
|
||||
expect(buffer.pop()).toEqual(9);
|
||||
expect(buffer.pop()).toEqual(undefined);
|
||||
|
||||
buffer.push(42);
|
||||
buffer.push(9);
|
||||
buffer.push(12);
|
||||
expect(buffer.get(2)).toEqual(12);
|
||||
expect(buffer.get(1)).toEqual(9);
|
||||
expect(buffer.get(0)).toEqual(42);
|
||||
});
|
||||
59
src/day1/RingBuffer.ts
Normal file
59
src/day1/RingBuffer.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
export default class RingBuffer<T> {
|
||||
private items: T[] = [];
|
||||
private start: number = 0;
|
||||
private end: number = 0;
|
||||
private count: number = 0;
|
||||
|
||||
constructor(initialCapacity: number = 4) {
|
||||
this.items = new Array<T>(initialCapacity);
|
||||
}
|
||||
|
||||
public get length(): number {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
push(item: T): void {
|
||||
if (this.count === this.items.length) {
|
||||
this.resize();
|
||||
}
|
||||
|
||||
this.items[this.end] = item;
|
||||
this.end = (this.end + 1) % this.items.length;
|
||||
this.count++;
|
||||
}
|
||||
|
||||
pop(): T | undefined {
|
||||
if (this.count === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const item = this.items[this.start];
|
||||
this.items[this.start] = undefined as any;
|
||||
this.start = (this.start + 1) % this.items.length;
|
||||
this.count--;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
get(idx: number): T | undefined {
|
||||
if (idx < 0 || idx >= this.count) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const realIndex = (this.start + idx) % this.items.length;
|
||||
return this.items[realIndex];
|
||||
}
|
||||
|
||||
private resize(): void {
|
||||
const newCapacity = this.items.length * 2 || 4;
|
||||
const newItems = new Array<T>(newCapacity);
|
||||
|
||||
for (let i = 0; i < this.count; i++) {
|
||||
newItems[i] = this.get(i)!;
|
||||
}
|
||||
|
||||
this.items = newItems;
|
||||
this.start = 0;
|
||||
this.end = this.count;
|
||||
}
|
||||
}
|
||||
7
src/day1/SinglyLinkedList.test.ts
Normal file
7
src/day1/SinglyLinkedList.test.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import SinglyLinkedList from "@code/SinglyLinkedList";
|
||||
import { test_list } from "./ListTest";
|
||||
|
||||
test("linked-list", function () {
|
||||
const list = new SinglyLinkedList<number>();
|
||||
test_list(list);
|
||||
});
|
||||
138
src/day1/SinglyLinkedList.ts
Normal file
138
src/day1/SinglyLinkedList.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
class Node<T> {
|
||||
public value: T;
|
||||
public next?: Node<T>;
|
||||
|
||||
constructor(t: T) {
|
||||
this.value = t;
|
||||
}
|
||||
}
|
||||
|
||||
export default class SinglyLinkedList<T> {
|
||||
public length: number;
|
||||
public head?: Node<T>;
|
||||
public tail?: Node<T>;
|
||||
|
||||
constructor() {
|
||||
this.length = 0;
|
||||
this.head = undefined;
|
||||
}
|
||||
|
||||
prepend(item: T): void {
|
||||
let node = new Node<T>(item);
|
||||
if (this.head != null) {
|
||||
node.next = this.head;
|
||||
}
|
||||
this.head = node;
|
||||
this.length++;
|
||||
}
|
||||
|
||||
insertAt(item: T, idx: number): void {
|
||||
let current_node = this.head;
|
||||
let i = 0;
|
||||
|
||||
while (current_node?.next != null && i < idx) {
|
||||
current_node = current_node.next;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (current_node?.next != null) {
|
||||
let node = new Node<T>(item);
|
||||
node.next = current_node.next;
|
||||
current_node.next = node;
|
||||
this.length++;
|
||||
}
|
||||
}
|
||||
|
||||
append(item: T): void {
|
||||
if (this.length == 0) {
|
||||
let node = new Node<T>(item);
|
||||
this.head = node;
|
||||
this.length++;
|
||||
return;
|
||||
}
|
||||
|
||||
let current_node = this.head;
|
||||
|
||||
while (current_node?.next != null) {
|
||||
current_node = current_node.next;
|
||||
}
|
||||
|
||||
if (current_node != null) {
|
||||
let node = new Node<T>(item);
|
||||
current_node.next = node;
|
||||
this.length++;
|
||||
}
|
||||
}
|
||||
|
||||
remove(item: T): T | undefined {
|
||||
let current_node = this.head;
|
||||
let prev_node = this.head;
|
||||
let node_to_remove = null;
|
||||
|
||||
while (current_node != null) {
|
||||
if (current_node.value === item) {
|
||||
node_to_remove = current_node;
|
||||
break;
|
||||
}
|
||||
prev_node = current_node;
|
||||
current_node = current_node.next;
|
||||
}
|
||||
|
||||
if (node_to_remove == this.head) {
|
||||
this.head = node_to_remove.next;
|
||||
this.length--;
|
||||
} else if (prev_node?.next != null) {
|
||||
prev_node.next = node_to_remove?.next;
|
||||
this.length--;
|
||||
}
|
||||
|
||||
return current_node?.value;
|
||||
}
|
||||
|
||||
get(idx: number): T | undefined {
|
||||
let current_node = this.head;
|
||||
let i = 0;
|
||||
|
||||
while (current_node != null && i < idx) {
|
||||
current_node = current_node.next;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return current_node?.value;
|
||||
}
|
||||
|
||||
removeAt(idx: number): T | undefined {
|
||||
let current_node = this.head;
|
||||
|
||||
if (idx == 0 && current_node != null) {
|
||||
this.head = current_node.next;
|
||||
this.length--;
|
||||
return current_node.value;
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
while (current_node?.next != null && i < idx - 1) {
|
||||
current_node = current_node.next;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (current_node?.next != null) {
|
||||
let node_to_remove = current_node.next;
|
||||
current_node.next = node_to_remove.next;
|
||||
this.length--;
|
||||
return node_to_remove.value;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
debug() {
|
||||
let current_node = this.head;
|
||||
let result = "";
|
||||
while (current_node != null) {
|
||||
result += ` ${current_node.value},`;
|
||||
current_node = current_node.next;
|
||||
}
|
||||
console.log(result);
|
||||
}
|
||||
}
|
||||
25
src/day1/Stack.test.ts
Normal file
25
src/day1/Stack.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import Stack from "@code/Stack";
|
||||
|
||||
test("stack", function () {
|
||||
const list = new Stack<number>();
|
||||
|
||||
list.push(5);
|
||||
list.push(7);
|
||||
list.push(9);
|
||||
|
||||
expect(list.pop()).toEqual(9);
|
||||
expect(list.length).toEqual(2);
|
||||
|
||||
list.push(11);
|
||||
expect(list.pop()).toEqual(11);
|
||||
expect(list.pop()).toEqual(7);
|
||||
expect(list.peek()).toEqual(5);
|
||||
expect(list.pop()).toEqual(5);
|
||||
expect(list.pop()).toEqual(undefined);
|
||||
|
||||
// just wanted to make sure that I could not blow up myself when i remove
|
||||
// everything
|
||||
list.push(69);
|
||||
expect(list.peek()).toEqual(69);
|
||||
expect(list.length).toEqual(1);
|
||||
});
|
||||
43
src/day1/Stack.ts
Normal file
43
src/day1/Stack.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
type Node<T> = {
|
||||
value: T;
|
||||
prev?: Node<T>;
|
||||
};
|
||||
|
||||
export default class Stack<T> {
|
||||
public length: number;
|
||||
private head?: Node<T>;
|
||||
|
||||
constructor() {
|
||||
this.head = undefined;
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
push(item: T): void {
|
||||
const node = { value: item } as Node<T>;
|
||||
this.length++;
|
||||
if (!this.head) {
|
||||
this.head = node;
|
||||
return;
|
||||
}
|
||||
|
||||
node.prev = this.head;
|
||||
this.head = node;
|
||||
}
|
||||
|
||||
pop(): T | undefined {
|
||||
this.length = Math.max(0, this.length - 1);
|
||||
if (this.length === 0) {
|
||||
const head = this.head;
|
||||
this.head = undefined;
|
||||
return head?.value;
|
||||
}
|
||||
|
||||
const head = this.head as Node<T>;
|
||||
this.head = head.prev;
|
||||
return head?.value;
|
||||
}
|
||||
|
||||
peek(): T | undefined {
|
||||
return this.head?.value;
|
||||
}
|
||||
}
|
||||
15
src/day1/Trie.test.ts
Normal file
15
src/day1/Trie.test.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import Trie from "@code/Trie";
|
||||
|
||||
test("Trie", function () {
|
||||
const trie = new Trie();
|
||||
trie.insert("foo");
|
||||
trie.insert("fool");
|
||||
trie.insert("foolish");
|
||||
trie.insert("bar");
|
||||
|
||||
expect(trie.find("fo").sort()).toEqual(["foo", "fool", "foolish"]);
|
||||
|
||||
trie.delete("fool");
|
||||
|
||||
expect(trie.find("fo").sort()).toEqual(["foo", "foolish"]);
|
||||
});
|
||||
86
src/day1/Trie.ts
Normal file
86
src/day1/Trie.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
type TrieNode = {
|
||||
children: TrieNode[];
|
||||
isValue: boolean;
|
||||
value?: string;
|
||||
};
|
||||
|
||||
// Creates a new TrieNode with defaults
|
||||
function createTrieNode() {
|
||||
return {
|
||||
children: [],
|
||||
isValue: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Char code for 'a'.
|
||||
const start = "a".charCodeAt(0);
|
||||
|
||||
// Returns the distance from 'a' which can be used to index into an array.
|
||||
function getIdx(item: string, idx: number): number {
|
||||
return item.toLowerCase().charCodeAt(idx) - start;
|
||||
}
|
||||
|
||||
export default class Trie {
|
||||
private head: TrieNode;
|
||||
|
||||
constructor() {
|
||||
this.head = createTrieNode();
|
||||
}
|
||||
|
||||
insert(item: string): void {
|
||||
let current: TrieNode = this.head;
|
||||
for (let i = 0; i < item.length; ++i) {
|
||||
const letter = getIdx(item, i);
|
||||
if (!current.children[letter]) {
|
||||
current.children[letter] = createTrieNode();
|
||||
}
|
||||
current = current.children[letter];
|
||||
}
|
||||
|
||||
current.isValue = true;
|
||||
current.value = item;
|
||||
}
|
||||
|
||||
delete(item: string): void {
|
||||
let current: TrieNode = this.head;
|
||||
for (let i = 0; current && i < item.length; ++i) {
|
||||
current = current.children[getIdx(item, i)];
|
||||
}
|
||||
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
current.value = undefined;
|
||||
current.isValue = false;
|
||||
}
|
||||
|
||||
find(partial: string): string[] {
|
||||
let current = this.head;
|
||||
for (let i = 0; i < partial.length; ++i) {
|
||||
current = current.children[getIdx(partial, i)];
|
||||
}
|
||||
|
||||
return this.findRecursively(current, []);
|
||||
}
|
||||
|
||||
// Finds all the possible words to complete node.
|
||||
private findRecursively(
|
||||
node: TrieNode | undefined,
|
||||
out: string[],
|
||||
): string[] {
|
||||
if (!node) {
|
||||
return out;
|
||||
}
|
||||
|
||||
if (node.isValue) {
|
||||
out.push(node.value as string);
|
||||
}
|
||||
|
||||
for (let i = 0; i < node.children.length; ++i) {
|
||||
this.findRecursively(node.children[i], out);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
13
src/day1/TwoCrystalBalls.test.ts
Normal file
13
src/day1/TwoCrystalBalls.test.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import two_crystal_balls from "@code/TwoCrystalBalls";
|
||||
|
||||
test("two crystal balls", function () {
|
||||
let idx = Math.floor(Math.random() * 10000);
|
||||
const data = new Array(10000).fill(false);
|
||||
|
||||
for (let i = idx; i < 10000; ++i) {
|
||||
data[i] = true;
|
||||
}
|
||||
|
||||
expect(two_crystal_balls(data)).toEqual(idx);
|
||||
expect(two_crystal_balls(new Array(821).fill(false))).toEqual(-1);
|
||||
});
|
||||
20
src/day1/TwoCrystalBalls.ts
Normal file
20
src/day1/TwoCrystalBalls.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export default function two_crystal_balls(breaks: boolean[]): number {
|
||||
const jmpAmount = Math.floor(Math.sqrt(breaks.length));
|
||||
|
||||
let i = jmpAmount;
|
||||
for (; i < breaks.length; i += jmpAmount) {
|
||||
if (breaks[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i -= jmpAmount;
|
||||
|
||||
for (let j = 0; j < jmpAmount && i < breaks.length; j++, i++) {
|
||||
if (breaks[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
80
src/day1/graph.ts
Normal file
80
src/day1/graph.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
export const list1: WeightedAdjacencyList = [];
|
||||
|
||||
// (1) --- (4) ---- (5)
|
||||
// / | | /|
|
||||
// (0) | ------|------- |
|
||||
// \ |/ | |
|
||||
// (2) --- (3) ---- (6)
|
||||
list1[0] = [
|
||||
{ to: 1, weight: 3 },
|
||||
{ to: 2, weight: 1 },
|
||||
];
|
||||
list1[1] = [
|
||||
{ to: 0, weight: 3 },
|
||||
{ to: 2, weight: 4 },
|
||||
{ to: 4, weight: 1 },
|
||||
];
|
||||
list1[2] = [
|
||||
{ to: 1, weight: 4 },
|
||||
{ to: 3, weight: 7 },
|
||||
{ to: 0, weight: 1 },
|
||||
];
|
||||
list1[3] = [
|
||||
{ to: 2, weight: 7 },
|
||||
{ to: 4, weight: 5 },
|
||||
{ to: 6, weight: 1 },
|
||||
];
|
||||
list1[4] = [
|
||||
{ to: 1, weight: 1 },
|
||||
{ to: 3, weight: 5 },
|
||||
{ to: 5, weight: 2 },
|
||||
];
|
||||
list1[5] = [
|
||||
{ to: 6, weight: 1 },
|
||||
{ to: 4, weight: 2 },
|
||||
{ to: 2, weight: 18 },
|
||||
];
|
||||
list1[6] = [
|
||||
{ to: 3, weight: 1 },
|
||||
{ to: 5, weight: 1 },
|
||||
];
|
||||
|
||||
export const list2: WeightedAdjacencyList = [];
|
||||
|
||||
// >(1)<--->(4) ---->(5)
|
||||
// / | /|
|
||||
// (0) ------|------- |
|
||||
// \ v v v
|
||||
// >(2) --> (3) <----(6)
|
||||
list2[0] = [
|
||||
{ to: 1, weight: 3 },
|
||||
{ to: 2, weight: 1 },
|
||||
];
|
||||
list2[1] = [{ to: 4, weight: 1 }];
|
||||
list2[2] = [{ to: 3, weight: 7 }];
|
||||
list2[3] = [];
|
||||
list2[4] = [
|
||||
{ to: 1, weight: 1 },
|
||||
{ to: 3, weight: 5 },
|
||||
{ to: 5, weight: 2 },
|
||||
];
|
||||
list2[5] = [
|
||||
{ to: 2, weight: 18 },
|
||||
{ to: 6, weight: 1 },
|
||||
];
|
||||
list2[6] = [{ to: 3, weight: 1 }];
|
||||
|
||||
// >(1)<--->(4) ---->(5)
|
||||
// / | /|
|
||||
// (0) ------|------- |
|
||||
// \ v v v
|
||||
// >(2) --> (3) <----(6)
|
||||
export const matrix2: WeightedAdjacencyMatrix = [
|
||||
[0, 3, 1, 0, 0, 0, 0], // 0
|
||||
[0, 0, 0, 0, 1, 0, 0],
|
||||
[0, 0, 7, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 0, 5, 0, 2, 0],
|
||||
[0, 0, 18, 0, 0, 0, 1],
|
||||
[0, 0, 0, 1, 0, 0, 1],
|
||||
];
|
||||
87
src/day1/tree.ts
Normal file
87
src/day1/tree.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
export const tree: BinaryNode<number> = {
|
||||
value: 20,
|
||||
right: {
|
||||
value: 50,
|
||||
right: {
|
||||
value: 100,
|
||||
right: null,
|
||||
left: null,
|
||||
},
|
||||
left: {
|
||||
value: 30,
|
||||
right: {
|
||||
value: 45,
|
||||
right: null,
|
||||
left: null,
|
||||
},
|
||||
left: {
|
||||
value: 29,
|
||||
right: null,
|
||||
left: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
left: {
|
||||
value: 10,
|
||||
right: {
|
||||
value: 15,
|
||||
right: null,
|
||||
left: null,
|
||||
},
|
||||
left: {
|
||||
value: 5,
|
||||
right: {
|
||||
value: 7,
|
||||
right: null,
|
||||
left: null,
|
||||
},
|
||||
left: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const tree2: BinaryNode<number> = {
|
||||
value: 20,
|
||||
right: {
|
||||
value: 50,
|
||||
right: null,
|
||||
left: {
|
||||
value: 30,
|
||||
right: {
|
||||
value: 45,
|
||||
right: {
|
||||
value: 49,
|
||||
left: null,
|
||||
right: null,
|
||||
},
|
||||
left: null,
|
||||
},
|
||||
left: {
|
||||
value: 29,
|
||||
right: null,
|
||||
left: {
|
||||
value: 21,
|
||||
right: null,
|
||||
left: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
left: {
|
||||
value: 10,
|
||||
right: {
|
||||
value: 15,
|
||||
right: null,
|
||||
left: null,
|
||||
},
|
||||
left: {
|
||||
value: 5,
|
||||
right: {
|
||||
value: 7,
|
||||
right: null,
|
||||
left: null,
|
||||
},
|
||||
left: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
52
src/global.d.ts
vendored
Normal file
52
src/global.d.ts
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
declare type Point = {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
declare type ListNode<T> = {
|
||||
value: T;
|
||||
next?: ListNode<T>;
|
||||
prev?: ListNode<T>;
|
||||
};
|
||||
|
||||
declare interface List<T> {
|
||||
get length(): number;
|
||||
removeAt(index: number): T | undefined;
|
||||
remove(item: T): T | undefined;
|
||||
get(index: number): T | undefined;
|
||||
prepend(item: T): void;
|
||||
append(item: T): void;
|
||||
insertAt(item: T, idx: number): void;
|
||||
}
|
||||
|
||||
declare type CompleteGraphEdge = { from: number; to: number; weight: number };
|
||||
declare type GraphEdge = { to: number; weight: number };
|
||||
declare type WeightedAdjacencyList = GraphEdge[][];
|
||||
// A number means weight
|
||||
declare type WeightedAdjacencyMatrix = number[][];
|
||||
|
||||
declare type AdjacencyList = number[][];
|
||||
// A 1 means connected
|
||||
declare type AdjacencyMatrix = number[][];
|
||||
|
||||
declare type BinaryNode<T> = {
|
||||
value: T;
|
||||
left: BinaryNode<T> | null;
|
||||
right: BinaryNode<T> | null;
|
||||
};
|
||||
|
||||
declare type GeneralNode<T> = {
|
||||
value: T;
|
||||
children: GeneralNode<T>[];
|
||||
};
|
||||
|
||||
declare interface ILRU<K, V> {
|
||||
update(key: K, value: V): void;
|
||||
get(key: K): V | undefined;
|
||||
}
|
||||
|
||||
declare type BinaryNode<T> = {
|
||||
value: T;
|
||||
left: BinaryNode<T> | null;
|
||||
right: BinaryNode<T> | null;
|
||||
};
|
||||
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"resolveJsonModule": true,
|
||||
"noImplicitReturns": true,
|
||||
"esModuleInterop": true,
|
||||
"target": "esnext",
|
||||
"module": "commonjs",
|
||||
"baseUrl": "src",
|
||||
"paths": {
|
||||
"@code/*": ["day1/*"]
|
||||
}
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
15
vitest.config.ts
Normal file
15
vitest.config.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
import path from "path";
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
"@code": path.resolve(__dirname, "src/day1"),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: "node",
|
||||
include: ["src/**/*.test.{ts,js}"],
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user