Skip to content

Feat/priority queue exercise #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 48 additions & 19 deletions book/interview-questions/network-delay-time.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,57 @@
// https://leetcode.com/problems/network-delay-time/solution/
function networkDelayTime(times: number[][], N: number, K: number): number {
const graph = new Map<number, [number, number][]>(Array(N).fill(0).map((_, i) => [i + 1, []]));
times.forEach(([u, v, w]) => graph.get(u)?.push([v, w]));
const { PriorityQueue, Queue } = require('../../src/index');

const queue = new Queue([[K, 0]]);
const seen = Array(N + 1).fill(Infinity);
// tag::description[]
function networkDelayTime(times, N, K) {
// end::description[]
// tag::placeholder[]
// write your code here...
// end::placeholder[]
// tag::solution[]
const graph = new Map(Array(N).fill(0).map((_, i) => [i + 1, []]));
times.forEach(([u, v, w]) => graph.get(u).push([v, w]));

while (queue.size()) {
const [node, dist] = queue.dequeue();
seen[node] = Math.min(seen[node], dist);
const q = new PriorityQueue([[0, K]]);
const dist = new Map();

for (const [adj, w] of graph.get(node) || []) {
if (seen[adj] > dist + w) queue.enqueue([adj, dist + w]);
while (q.size) {
const [d, n] = q.dequeue();

if (dist.has(n)) continue;
dist.set(n, d);

for (const [adj, w] of graph.get(n)) {
if (!dist.has(adj)) q.enqueue([d + w, adj]);
}
}

const max = Math.max(...seen.slice(1));
return max === Infinity ? -1 : max;
};
return dist.size === N ? Math.max(...dist.values()) : -1;
// end::solution[]
// tag::description[]
}
// end::description[]

// tag::networkDelayTimeQueue[]
function networkDelayTimeQueue(times, N, K) {
const graph = new Map(Array(N).fill(0).map((_, i) => [i + 1, []]));
times.forEach(([u, v, w]) => graph.get(u).push([v, w]));

const q = new Queue([[0, K]]);
const dist = new Map();

/*
[[2,1,1],[2,3,1],[3,4,1]]
4
2
while (q.size) {
const [d, n] = q.dequeue();

dist.set(n, dist.has(n) ? Math.min(dist.get(n), d) : d);

for (const [adj, w] of graph.get(n)) {
if (!dist.has(adj) || dist.get(adj) > d + w) {
q.enqueue([d + w, adj]);
}
}
}

return dist.size === N ? Math.max(...dist.values()) : -1;
}
// end::networkDelayTimeQueue[]

*/
module.exports = { networkDelayTime, networkDelayTimeQueue };
47 changes: 45 additions & 2 deletions book/interview-questions/network-delay-time.spec.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 12 additions & 8 deletions src/data-structures/heaps/heap.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
class Heap {
constructor(comparator = (a, b) => a - b) {
this.array = [];
this.comparator = (i1, i2) => comparator(this.array[i1], this.array[i2]);
this.comparator = (i1, i2) => {
const value = comparator(this.array[i1], this.array[i2]);
if (Number.isNaN(value)) { throw new Error(`Comparator should evaluate to a number. Got ${value} when comparing ${this.array[i1]} with ${this.array[i2]}`); }
return value;
};
}

/**
Expand All @@ -34,8 +38,8 @@ class Heap {
* @runtime O(log n)
*/
remove(index = 0) {
if (!this.size()) return null;
this.swap(index, this.size() - 1); // swap with last
if (!this.size) return null;
this.swap(index, this.size - 1); // swap with last
const value = this.array.pop(); // remove element
this.bubbleDown(index);
return value;
Expand All @@ -45,7 +49,7 @@ class Heap {
* Returns the number of elements in this collection.
* @runtime O(1)
*/
size() {
get size() {
return this.array.length;
}

Expand All @@ -54,7 +58,7 @@ class Heap {
* @runtime O(log n)
*/
bubbleUp() {
let index = this.size() - 1;
let index = this.size - 1;
const parent = (i) => Math.ceil(i / 2 - 1);
while (parent(index) >= 0 && this.comparator(parent(index), index) > 0) {
this.swap(parent(index), index);
Expand All @@ -70,18 +74,18 @@ class Heap {
let curr = index;
const left = (i) => 2 * i + 1;
const right = (i) => 2 * i + 2;
const getTopChild = (i) => (right(i) < this.size()
const getTopChild = (i) => (right(i) < this.size
&& this.comparator(left(i), right(i)) > 0 ? right(i) : left(i));

while (left(curr) < this.size() && this.comparator(curr, getTopChild(curr)) > 0) {
while (left(curr) < this.size && this.comparator(curr, getTopChild(curr)) > 0) {
const next = getTopChild(curr);
this.swap(curr, next);
curr = next;
}
}

/**
* "Private": Swap elements on the heap
* Swap elements on the heap
* @runtime O(1)
* @param {number} i1 index 1
* @param {number} i2 index 2
Expand Down
34 changes: 21 additions & 13 deletions src/data-structures/heaps/heap.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ const PriorityQueue = require('./priority-queue');
const MaxHeap = require('./max-heap');
const MinHeap = require('./min-heap');

[[Heap], [PriorityQueue], [MinHeap]].forEach(([DS, arg]) => {
describe('Min-Heap (Priority Queue)', () => {
[
[Heap],
[PriorityQueue, [], (a, b) => a - b],
[MinHeap],
].forEach(([DS, ...arg]) => {
describe('Min-Heap and Priority Queue', () => {
let heap;

beforeEach(() => {
heap = new DS(arg);
heap = new DS(...arg);
});

describe('#contructor', () => {
Expand All @@ -21,7 +25,7 @@ const MinHeap = require('./min-heap');
it('should add an element', () => {
expect(heap.add(1)).toBe(undefined);
expect(heap.array).toEqual([1]);
expect(heap.size()).toBe(1);
expect(heap.size).toBe(1);
});

it('should keep things in order', () => {
Expand All @@ -31,7 +35,7 @@ const MinHeap = require('./min-heap');
expect(heap.array[0]).toEqual(2);
heap.add(1);
expect(heap.array[0]).toEqual(1);
expect(heap.size()).toEqual(3);
expect(heap.size).toEqual(3);
});
});

Expand All @@ -40,7 +44,7 @@ const MinHeap = require('./min-heap');
heap.add(1);
heap.add(0);
expect(heap.remove()).toBe(0);
expect(heap.size()).toBe(1);
expect(heap.size).toBe(1);
expect(heap.array).toEqual([1]);
});

Expand Down Expand Up @@ -70,19 +74,23 @@ const MinHeap = require('./min-heap');
expect(heap.remove()).toEqual(1);
expect(heap.remove()).toEqual(2);
expect(heap.remove()).toEqual(3);
expect(heap.size()).toBe(0);
expect(heap.size).toBe(0);
});
});
});
});
});

[[Heap, (a, b) => b - a], [PriorityQueue, (a, b) => b - a], [MaxHeap]].forEach(([DS, arg]) => {
[
[Heap, (a, b) => b - a],
[PriorityQueue, [], (a, b) => b - a],
[MaxHeap],
].forEach(([DS, ...arg]) => {
describe('Max-Heap (Priority Queue)', () => {
let heap;

beforeEach(() => {
heap = new DS(arg);
heap = new DS(...arg);
});

describe('#contructor', () => {
Expand All @@ -95,7 +103,7 @@ const MinHeap = require('./min-heap');
it('should add an element', () => {
expect(heap.add(1)).toBe(undefined);
expect(heap.array).toEqual([1]);
expect(heap.size()).toBe(1);
expect(heap.size).toBe(1);
});

it('should keep things in order', () => {
Expand All @@ -105,7 +113,7 @@ const MinHeap = require('./min-heap');
expect(heap.array[0]).toEqual(2);
heap.add(3);
expect(heap.array[0]).toEqual(3);
expect(heap.size()).toEqual(3);
expect(heap.size).toEqual(3);
});
});

Expand All @@ -114,7 +122,7 @@ const MinHeap = require('./min-heap');
heap.add(1);
heap.add(0);
expect(heap.remove()).toBe(1);
expect(heap.size()).toBe(1);
expect(heap.size).toBe(1);
expect(heap.array).toEqual([0]);
});

Expand Down Expand Up @@ -156,7 +164,7 @@ const MinHeap = require('./min-heap');
expect(heap.remove()).toEqual(2);
expect(heap.remove()).toEqual(1);
expect(heap.remove()).toEqual(0);
expect(heap.size()).toBe(0);
expect(heap.size).toBe(0);
});
});
});
Expand Down
12 changes: 6 additions & 6 deletions src/data-structures/heaps/median-heap.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ class MedianHeap {
}

// rebalance if the sizes of the heaps differ by more than one element
if (Math.abs(this.min.size() - this.max.size()) > 1) {
if (Math.abs(this.min.size - this.max.size) > 1) {
// extract the min/max from the heap with more elements and insert it into the other heap.
if (this.min.size() > this.max.size()) {
if (this.min.size > this.max.size) {
this.max.add(this.min.remove());
} else {
this.min.add(this.max.remove());
Expand All @@ -47,12 +47,12 @@ class MedianHeap {
findMedian() {
let median;

if (this.max.size() === this.min.size()) {
if (this.max.size === this.min.size) {
// When both heaps contain the same number of elements,
// the total number of elements is even.
// The median is the mean of the two middle elements.
median = (this.max.peek() + this.min.peek()) / 2;
} else if (this.max.size() > this.min.size()) {
} else if (this.max.size > this.min.size) {
// when the max-heap contains one more element than the min-heap,
// the median is in the top of the max-heap.
median = this.max.peek();
Expand All @@ -67,8 +67,8 @@ class MedianHeap {
/**
* Return size of the heap.
*/
size() {
return this.min.size() + this.max.size();
get size() {
return this.min.size + this.max.size;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/data-structures/heaps/median-heap.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ describe('Median Heap', () => {
describe('#add', () => {
it('should work', () => {
expect(medianHeap.add(1)).toEqual(undefined);
expect(medianHeap.size()).toEqual(1);
expect(medianHeap.size).toEqual(1);
});

it('should work', () => {
expect(medianHeap.add(1)).toEqual(undefined);
expect(medianHeap.add(1)).toEqual(undefined);
expect(medianHeap.size()).toEqual(2);
expect(medianHeap.size).toEqual(2);
});
});

Expand Down
25 changes: 24 additions & 1 deletion src/data-structures/heaps/priority-queue.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
const Heap = require('./heap');

class PriorityQueue extends Heap { }
class PriorityQueue extends Heap {
constructor(iterable = [], comparator = (a, b) => a[0] - b[0]) {
super(comparator);
Array.from(iterable).forEach((el) => this.add(el));
}

/**
* Add data to the Queue with Priority
* @param {[number, any]|any} value - Pair with [priority, value]
* any object as value is also possible if a custom comparator is passed in.
* @returns {void}
*/
enqueue(value) {
super.add(value);
}

/**
* Remove from the queue the element with the highest priority.
* @returns {[number, any]|any}
*/
dequeue() {
return super.remove();
}
}

module.exports = PriorityQueue;
Loading