Skip to content

Commit 88441c2

Browse files
committed
--wip-- [skip ci]
1 parent 6da8c62 commit 88441c2

13 files changed

+10802
-5954
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* @param {number} n
3+
* @param {number[][]} connections
4+
* @return {number[][]}
5+
*/
6+
function criticalConnections(n, connections) {
7+
const critical = [];
8+
const graph = buildGraph(n, connections);
9+
// console.log({graph})
10+
11+
for (let i = 0; i < connections.length; i++) { // O(|E| * [|V|^3 + |V|^2|E|]) = O(|V|^3|E| + |V|^2|E|^2)
12+
const link = connections[i];
13+
if (isLinkCritical(link, graph)) {
14+
critical.push(link);
15+
}
16+
}
17+
18+
return critical;
19+
}
20+
21+
function buildGraph(n, connections) {
22+
const graph = [...Array(n).keys()].reduce((map, i) => {
23+
map.set(i, new Set());
24+
return map;
25+
}, new Map());
26+
27+
connections.forEach(([i, j]) => {
28+
const iAdj = graph.get(i);
29+
iAdj.add(j);
30+
const jAdj = graph.get(j);
31+
jAdj.add(i);
32+
});
33+
34+
return graph;
35+
}
36+
37+
function isLinkCritical(link, graph) { // DFS: O(|V|^2 * |E|+|V|) = O(|V|^3 + |V|^2|E|)
38+
for (let i = 0; i < graph.size; i++) {
39+
for (let j = 0; j < graph.size; j++) {
40+
if (hasLink([i, j], link)) continue;
41+
if (!isConnected(i, j, link, graph)) { // DFS: O(|E|+|V|)
42+
// console.log({i, j, link});
43+
return true;
44+
}
45+
}
46+
}
47+
48+
return false;
49+
}
50+
51+
function hasLink(a, b) {
52+
return (a[0] === b[0] && a[1] === b[1]) || (a[0] === b[1] && a[1] === b[0]);
53+
}
54+
55+
// DFS: O(|E|+|V|)
56+
function isConnected(i, j, ignoreLink, graph, seen = new Set()) {
57+
if (i === j) return true;
58+
if (graph.get(i).has(j)) return true;
59+
60+
for (const adj of graph.get(i)) {
61+
if (hasLink([i, adj], ignoreLink)) continue;
62+
63+
if (seen.has(adj)) continue;
64+
seen.add(adj);
65+
66+
if (isConnected(adj, j, ignoreLink, graph, seen)) {
67+
return true;
68+
}
69+
}
70+
71+
return false;
72+
}
73+
74+
module.exports = criticalConnections;

lab/exercises/10-mixed/critical-connections.data.js

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @param {number} n
3+
* @param {number[][]} connections
4+
* @return {number[][]}
5+
*/
6+
function criticalConnections(n, connections) {
7+
const graph = buildGraph(n, connections);
8+
// console.log({graph})
9+
10+
return dfs(graph, 0);
11+
}
12+
13+
14+
function buildGraph(n, connections) {
15+
const graph = [...Array(n).keys()].reduce((map, i) => {
16+
map.set(i, new Set());
17+
return map;
18+
}, new Map());
19+
20+
connections.forEach(([i, j]) => {
21+
const iAdj = graph.get(i);
22+
iAdj.add(j);
23+
const jAdj = graph.get(j);
24+
jAdj.add(i);
25+
});
26+
27+
return graph;
28+
}
29+
30+
function dfs(graph, current, previous = null, rank = 1, group = []) {
31+
let criticalLinks = [];
32+
group[current] = rank;
33+
34+
for (const adj of graph.get(current)) {
35+
if (adj === previous) continue;
36+
37+
if (!group[adj]) { // if not visited (and not in a group yet)
38+
const links = dfs(graph, adj, current, rank + 1, group);
39+
if (links.length) {
40+
criticalLinks = criticalLinks.concat(links);
41+
}
42+
}
43+
44+
group[current] = Math.min(group[current], group[adj]);
45+
46+
if (group[adj] >= rank + 1) {
47+
criticalLinks.push([current, adj]);
48+
}
49+
}
50+
51+
return criticalLinks;
52+
}
53+
54+
module.exports = criticalConnections;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const assert = require('assert');
2+
3+
// const criticalConnections = require('./critical-connections');
4+
const criticalConnections = require('./critical-connections');
5+
const data = require('./critical-connections.data');
6+
7+
assert.deepEqual(criticalConnections(4, [
8+
[0, 1],
9+
[1, 2],
10+
[2, 0],
11+
[1, 3],
12+
]), [[1, 3]]);
13+
14+
const { n, connections } = data.test1000;
15+
assert.deepEqual(criticalConnections(n, connections), []);
16+
17+
console.log('All tests passed!');
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// npx jest lab/exercises/10-mixed/critical-connections.spec.js --watch
2+
const criticalConnections = require('./critical-connections');
3+
4+
describe('Critical Connections', () => {
5+
it('should work with 4 nodes', () => {
6+
const n = 4;
7+
const connections = [
8+
[0, 1],
9+
[1, 2],
10+
[2, 0],
11+
[1, 3],
12+
];
13+
expect(criticalConnections(n, connections)).toEqual([
14+
[1, 3],
15+
]);
16+
});
17+
18+
it('should work with nodes in line (all critical)', () => {
19+
const n = 4;
20+
const connections = [
21+
[0, 1],
22+
[1, 2],
23+
[2, 3],
24+
];
25+
expect(criticalConnections(n, connections)).toEqual(expect.arrayContaining([
26+
[0, 1],
27+
[1, 2],
28+
[2, 3],
29+
]));
30+
});
31+
32+
it('should work with nodes in daisy chain (no critical)', () => {
33+
const n = 4;
34+
const connections = [
35+
[0, 1],
36+
[1, 2],
37+
[2, 3],
38+
[3, 0],
39+
];
40+
expect(criticalConnections(n, connections)).toEqual(expect.arrayContaining([]));
41+
});
42+
});
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// npx jest lab/exercises/10-mixed/integer-to-words.spec.js --watch
2+
3+
const map = {
4+
0: 'Zero',
5+
1: 'One',
6+
2: 'Two',
7+
3: 'Three',
8+
4: 'Four',
9+
5: 'Five',
10+
6: 'Six',
11+
7: 'Seven',
12+
8: 'Eight',
13+
9: 'Nine',
14+
10: 'Ten',
15+
11: 'Eleven',
16+
12: 'Twelve',
17+
13: 'Thirteen',
18+
14: 'Fourteen',
19+
15: 'Fifteen',
20+
16: 'Sixteen',
21+
17: 'Seventeen',
22+
18: 'Eighteen',
23+
19: 'Nineteen',
24+
20: 'Twenty', // Twenty One
25+
26+
30: 'Thirty', // Thirty Four
27+
40: 'Forty',
28+
50: 'Fifty',
29+
60: 'Sixty', // Sixty Seven
30+
70: 'Seventy',
31+
80: 'Eighty',
32+
90: 'Ninety',
33+
100: 'Hundred', // One Hundred, Two Hundred
34+
35+
1_000: 'Thousand', // Four Thousand
36+
37+
1_000_000: 'Million', // One Million
38+
39+
1_000_000_000: 'Billion', // One Billion
40+
};
41+
42+
const keys = [
43+
// 1_000_000_000,
44+
// 1_000_000,
45+
// 1_000,
46+
// 100,
47+
10,
48+
];
49+
50+
/**
51+
* @param {number} num
52+
* @return {string}
53+
* @pomodoro II
54+
*/
55+
function numberToWords(num) {
56+
if (num < 21) return map[num];
57+
58+
let ans = [];
59+
// let i = 0;
60+
61+
// while (num && i < keys.length) {
62+
// // const div = keys[i++]; // 10
63+
// const div = 10;
64+
// const reminder = num % div; // 1
65+
// const left = num - reminder; // 20
66+
67+
// if (left && map[left] !== undefined) {
68+
// ans.push(map[left]);
69+
// num -= left;
70+
// }
71+
72+
// num = reminder;
73+
// }
74+
ans = ans.concat(numberToWords(Math.floor(num/10) * 10));
75+
ans = ans.concat(numberToWords(Math.floor(num % 10)))
76+
77+
return ans.join(' ');
78+
};
79+
80+
// convert a number into its English representation
81+
82+
// 21
83+
// Twenty One
84+
85+
// 1_234_567_891
86+
87+
console.log(process.version);
88+
89+
module.exports = numberToWords;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*eslint-disable */
2+
const assert = require('assert');
3+
4+
const numberToWords = require('./integer-to-words');
5+
6+
assert.equal(numberToWords(0), 'Zero');
7+
assert.equal(numberToWords(1), 'One');
8+
assert.equal(numberToWords(20), 'Twenty');
9+
assert.equal(numberToWords(21), 'Twenty One');
10+
assert.equal(numberToWords(99), 'Ninety Nine');
11+
12+
console.log('All tests passed!');
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const numberToWords = require('./integer-to-words');
2+
3+
describe('Integer to English Words', () => {
4+
it('should convert 0', () => {
5+
expect(numberToWords(0)).toEqual('Zero');
6+
});
7+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Compute how much water it is able to trap after raining.
3+
* @param {number[]} height Non-negative integers representing
4+
* an elevation map where the width of each bar is 1.
5+
*
6+
* @runtime O(n^2) - Brute force
7+
* @space O(1)
8+
*/
9+
function trap(height) {
10+
let ans = 0;
11+
12+
for (let i = 0; i < height.length; i++) {
13+
let leftMax = 0;
14+
let rightMax = 0;
15+
for (let j = i; j >= 0; j--) {
16+
leftMax = Math.max(leftMax, height[j]);
17+
}
18+
for (let j = i; j < height.length; j++) {
19+
rightMax = Math.max(rightMax, height[j]);
20+
}
21+
22+
ans += Math.min(leftMax, rightMax) - height[i];
23+
}
24+
25+
return ans;
26+
}
27+
28+
module.exports = trap;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Compute how much water it is able to trap after raining.
3+
* @param {number[]} height Non-negative integers representing
4+
* an elevation map where the width of each bar is 1.
5+
*
6+
* @runtime O(n) - using DP
7+
* @space O(n)
8+
*/
9+
function trap(height) {
10+
let ans = 0;
11+
const leftMax = [];
12+
const rightMax = [];
13+
14+
for (let j = height.length - 1; j >= 0; j--) {
15+
leftMax[j] = Math.max((leftMax[j + 1] || 0), height[j]);
16+
}
17+
for (let j = 0; j < height.length; j++) {
18+
rightMax[j] = Math.max((rightMax[j - 1] || 0), height[j]);
19+
}
20+
21+
for (let i = 0; i < height.length; i++) {
22+
ans += Math.min(leftMax[i], rightMax[i]) - height[i];
23+
}
24+
25+
return ans;
26+
}
27+
28+
module.exports = trap;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const trap = require('./trapping-rain-water');
2+
3+
describe('Trapping Rain Water', () => {
4+
it('should trap', () => {
5+
expect(trap([1, 0, 1])).toEqual(1);
6+
});
7+
8+
it('should not trap', () => {
9+
expect(trap([1, 1, 1])).toEqual(0);
10+
});
11+
12+
it('should not trap', () => {
13+
expect(trap([0, 0, 0])).toEqual(0);
14+
});
15+
16+
it('should trap', () => {
17+
expect(trap([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])).toEqual(6);
18+
});
19+
});

0 commit comments

Comments
 (0)