mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(curriculum): add shortest path algo to js v9 cert (#66681)
Co-authored-by: jdwilkin4 <jwilkin4@hotmail.com>
This commit is contained in:
@@ -5701,6 +5701,13 @@
|
||||
"In this lesson, you will learn about fundamental data structures like graphs, trees, and their practical applications in computer science."
|
||||
]
|
||||
},
|
||||
"workshop-shortest-path-algorithm-js": {
|
||||
"title": "Implement the Shortest Path Algorithm",
|
||||
"intro": [
|
||||
"The shortest path algorithm finds the minimum distance between nodes in a weighted graph.",
|
||||
"In this workshop, you'll implement the shortest path algorithm in JavaScript and return both the shortest distances and the paths taken."
|
||||
]
|
||||
},
|
||||
"lab-adjacency-list-to-matrix-converter-js": {
|
||||
"title": "Build an Adjacency List to Matrix Converter",
|
||||
"intro": [
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
---
|
||||
id: 0095d0567b6817114989a1dd
|
||||
title: Step 1
|
||||
challengeType: 1
|
||||
dashedName: step-1
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In this workshop, you will implement the shortest path algorithm in JavaScript. You will write a function that computes the shortest path between nodes in a weighted graph and returns both the distances and the paths taken.
|
||||
|
||||
For example, given a graph where cities are connected by roads with different distances, the algorithm will find the shortest route from one city to another. If you want to travel from City A to City D, the algorithm might find that going A ⇨ B ⇨ C ⇨ D (total: 15km) is shorter than going directly A ⇨ D (20km).
|
||||
|
||||
To get started, define a variable named `INF` and assign it the value `Infinity`. Later, you'll use it to indicate that there is no direct connection between two nodes.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should define a variable named `INF`.
|
||||
|
||||
```js
|
||||
assert.isDefined(INF);
|
||||
```
|
||||
|
||||
Your `INF` variable should have the value `Infinity`.
|
||||
|
||||
```js
|
||||
assert.strictEqual(INF, Infinity);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1baba
|
||||
title: Step 2
|
||||
challengeType: 1
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You will need a 2D array to represent the adjacency matrix of the graph. Each value represents the weight (distance) of the edge between two nodes. A value of `INF` means there is no direct edge.
|
||||
|
||||
Create another variable named `adjMatrix` and assign it a 2D array with the following values:
|
||||
|
||||
```js
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0]
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a variable named `adjMatrix`.
|
||||
|
||||
```js
|
||||
assert.isDefined(adjMatrix);
|
||||
```
|
||||
|
||||
`adjMatrix` should be a 2D array with 6 rows and 6 columns.
|
||||
|
||||
```js
|
||||
assert.isArray(adjMatrix);
|
||||
assert.lengthOf(adjMatrix, 6);
|
||||
adjMatrix.forEach(row => assert.lengthOf(row, 6));
|
||||
```
|
||||
|
||||
`adjMatrix` should contain the correct values.
|
||||
|
||||
```js
|
||||
assert.deepEqual(adjMatrix[0], [0, 5, 3, INF, 11, INF]);
|
||||
assert.deepEqual(adjMatrix[1], [5, 0, 1, INF, INF, 2]);
|
||||
assert.deepEqual(adjMatrix[2], [3, 1, 0, 1, 5, INF]);
|
||||
assert.deepEqual(adjMatrix[3], [INF, INF, 1, 0, 9, 3]);
|
||||
assert.deepEqual(adjMatrix[4], [11, INF, 5, 9, 0, INF]);
|
||||
assert.deepEqual(adjMatrix[5], [INF, 2, INF, 3, INF, 0]);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1babb
|
||||
title: Step 3
|
||||
challengeType: 1
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you will create the main function that does all the work.
|
||||
|
||||
Create a function named `shortestPath` that takes three parameters: `matrix`, `startNode`, and `targetNode`.
|
||||
|
||||
Over the next few steps, you will build out the logic for this function.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a function named `shortestPath`.
|
||||
|
||||
```js
|
||||
assert.isFunction(shortestPath);
|
||||
```
|
||||
|
||||
Your `shortestPath` function should have the parameters `matrix`, `startNode`, and `targetNode`.
|
||||
|
||||
```js
|
||||
const params = __helpers.getFunctionParams(shortestPath.toString());
|
||||
const names = params.map(p => p.name);
|
||||
assert.include(names, 'matrix');
|
||||
assert.include(names, 'startNode');
|
||||
assert.include(names, 'targetNode');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1babc
|
||||
title: Step 5
|
||||
challengeType: 1
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to store the number of nodes in the graph.
|
||||
|
||||
Inside the `shortestPath` function, create a variable named `n` and assign it `matrix.length`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a variable `n` inside the `shortestPath` function.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(const|let|var)\s+n\s*=/
|
||||
);
|
||||
```
|
||||
|
||||
Your `n` variable should have the value `matrix.length`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(const|let|var)\s+n\s*=\s*matrix\.length/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1babd
|
||||
title: Step 6
|
||||
challengeType: 1
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You need to keep track of the shortest known distance from the start node to every other node. To begin, you'll assume every node is infinitely far away.
|
||||
|
||||
In JavaScript, you can create an array pre-filled with a value using `new Array(n).fill(value)`. For example, `new Array(3).fill(0)` creates `[0, 0, 0]`.
|
||||
|
||||
Inside the `shortestPath` function, create a variable named `distances` and assign it `new Array(n).fill(INF)`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a variable named `distances` inside `shortestPath`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(const|let|var)\s+distances\s*=/
|
||||
);
|
||||
```
|
||||
|
||||
Your `distances` variable should be set to `new Array(n).fill(INF)`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/new\s+Array\s*\(\s*n\s*\)\s*\.fill\s*\(\s*INF\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1babe
|
||||
title: Step 7
|
||||
challengeType: 1
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The distance from the starting node to itself is always `0`. You have to update the `distances` array to reflect this.
|
||||
|
||||
After the `distances` array, set `distances[startNode]` to `0`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should set `distances[startNode]` to `0`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/distances\s*\[\s*startNode\s*\]\s*=\s*0/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1babf
|
||||
title: Step 8
|
||||
challengeType: 1
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You also need to track the actual path taken to reach each node. You will store a list of paths where each entry is an array of node indices representing the route taken.
|
||||
|
||||
Initially, each node's path will just contain itself. You can create this structure using `Array.from()`:
|
||||
|
||||
```js
|
||||
Array.from({ length: n }, (_, i) => [i]);
|
||||
```
|
||||
|
||||
This creates an array of `n` elements, where the element at index `i` is `[i]`.
|
||||
|
||||
Still within the `shortestPath` function, create a variable named `paths` and assign it `Array.from({ length: n }, (_, i) => [i])`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a variable `paths` inside the `shortestPath` function.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(const|let|var)\s+paths\s*=/
|
||||
);
|
||||
```
|
||||
|
||||
Your `paths` variable should be initialized using `Array.from`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/paths\s*=\s*Array\.from/
|
||||
);
|
||||
```
|
||||
|
||||
Your `paths` variable should use `{ length: n }` as the first argument to `Array.from`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/Array\.from\s*\(\s*\{\s*length\s*:\s*n\s*\}/
|
||||
);
|
||||
```
|
||||
|
||||
The second argument to `Array.from` should be a callback `(_, i) => [i]`, where `_` is a placeholder for the unused element and `i` is the index. It should return `[i]`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/Array\.from\s*\([\s\S]*?,\s*function\s*\(\s*\w+\s*,\s*(\w+)\s*\)\s*\{[\s\S]*?return\s*\[\s*\1\s*\]|Array\.from\s*\([\s\S]*?,\s*\(\s*\w+\s*,\s*\w+\s*\)\s*=>\s*\[\s*\w+\s*\]/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac0
|
||||
title: Step 9
|
||||
challengeType: 1
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
As the algorithm runs, you need to track which nodes have already been processed so you don't revisit them.
|
||||
|
||||
Create a variable named `visited` and assign it `new Array(n).fill(false)`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a variable named `visited`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(const|let|var)\s+visited\s*=/
|
||||
);
|
||||
```
|
||||
|
||||
Your `visited` variable should be set to `new Array(n).fill(false)`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/new\s+Array\s*\(\s*n\s*\)\s*\.fill\s*\(\s*false\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac1
|
||||
title: Step 10
|
||||
challengeType: 1
|
||||
dashedName: step-10
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you'll add the main loop that drives the algorithm. It runs once for each node in the graph, selecting the closest unvisited node each time.
|
||||
|
||||
Inside the `shortestPath` function, add a `for` loop that runs `n` times using `i` as the loop variable.
|
||||
|
||||
At the start of the loop body, using `let`, declare two variables `minDistance` and `current` set to `INF`, and `-1` respectively. These will track the closest unvisited node found in each iteration.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `for` loop inside `shortestPath` that runs `n` times. Don't forget to set `i` with `let` inside it.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/for\s*\(\s*(let|var)\s+i\s*=\s*0\s*;\s*i\s*<\s*n\s*;\s*i\+\+\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
You should have a `minDistance` variable set to `INF` inside the loop.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(let|var)\s+minDistance\s*=\s*INF/
|
||||
);
|
||||
```
|
||||
|
||||
You should have a `current` variable set to `-1` inside the loop.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(let|var)\s+current\s*=\s*-1/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac2
|
||||
title: Step 11
|
||||
challengeType: 1
|
||||
dashedName: step-11
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside the loop, you need to scan every node to find the one with the smallest known distance that hasn't been visited yet.
|
||||
|
||||
Add a `for` loop inside the main loop that iterates through each node. Use `nodeNo` as the loop variable going from `0` to `n`.
|
||||
|
||||
Leave the body empty for now.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a second (inner) `for` loop inside the main loop with `nodeNo` as its loop variable.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/for\s*\(\s*(let|var)\s+nodeNo\s*=\s*0\s*;\s*nodeNo\s*<\s*n\s*;\s*nodeNo\+\+\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
--fcc-editable-region--
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac3
|
||||
title: Step 12
|
||||
challengeType: 1
|
||||
dashedName: step-12
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Inside the inner `for` loop, you need to check whether the current node is unvisited and closer than the best you've found so far.
|
||||
|
||||
Add an `if` statement that checks if `nodeNo` has not been visited and `distances[nodeNo]` is less than `minDistance`.
|
||||
|
||||
Leave the body empty for now.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `if` statement with the condition `!visited[nodeNo] && distances[nodeNo] < minDistance` inside the inner `for` loop.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/if\s*\(\s*!visited\s*\[\s*nodeNo\s*\]\s*&&\s*distances\s*\[\s*nodeNo\s*\]\s*<\s*minDistance\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac4
|
||||
title: Step 13
|
||||
challengeType: 1
|
||||
dashedName: step-13
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
If the condition is true, the current node is the best unvisited candidate found so far. You need to update your tracking variables to reflect that.
|
||||
|
||||
Inside the `if` statement, update `minDistance` to `distances[nodeNo]` and `current` to `nodeNo`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should set `minDistance` to `distances[nodeNo]` inside the `if` block.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/minDistance\s*=\s*distances\s*\[\s*nodeNo\s*\]/
|
||||
);
|
||||
```
|
||||
|
||||
You should set `current` to `nodeNo` inside the `if` block.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/current\s*=\s*nodeNo/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac5
|
||||
title: Step 14
|
||||
challengeType: 1
|
||||
dashedName: step-14
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
After scanning all nodes to find the closest unvisited one, you need to handle the case where no valid node is found. This happens when all remaining nodes are unreachable.
|
||||
|
||||
After the inner `for` loop, but still inside the outer loop, add an `if` statement that checks if `current` is strictly equal to `-1`. If that is true, use `break` inside the `if` block to stop the outer loop early.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add an `if` statement that checks if `current === -1`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/if\s*\(\s*current\s*===\s*-1\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
You should use `break` inside the `if` block.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/if\s*\(\s*current\s*===\s*-1\s*\)[\s\S]*?break/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
```
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac6
|
||||
title: Step 15
|
||||
challengeType: 1
|
||||
dashedName: step-15
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Once you've confirmed a valid node was found, mark it as visited so the algorithm won't process it again.
|
||||
|
||||
After the `if` statement with the condition `current === -1`, set `visited[current]` to `true`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should set `visited[current]` to `true`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/visited\s*\[\s*current\s*\]\s*=\s*true/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
```
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac7
|
||||
title: Step 16
|
||||
challengeType: 1
|
||||
dashedName: step-16
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that the current node is marked as visited, you need to look at all its neighbors to see if you can reach them more efficiently through the current node.
|
||||
|
||||
After `visited[current] = true`, add a neighbor `for` loop that iterates through each `nodeNo` from `0` to `n`. Note that this is another inner loop on the same level as the first.
|
||||
|
||||
Inside the loop, declare a variable named `distance` and assign it `matrix[current][nodeNo]`. This gives you the edge weight between the current node and its neighbor.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a neighbor `for` loop after marking the current node as visited.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/visited\s*\[\s*current\s*\]\s*=\s*true[\s\S]*?for\s*\(/
|
||||
);
|
||||
```
|
||||
|
||||
The neighbor `for` loop should iterate from `0` to `n`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/visited\s*\[\s*current\s*\]\s*=\s*true[\s\S]*?for\s*\(\s*(var|let)\s+\w+\s*=\s*0\s*;\s*\w+\s*<\s*n\s*;\s*\w+\+\+\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
You should have a `distance` variable assigned to `matrix[current][nodeNo]` inside the neighbor loop.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(const|let|var)\s+distance\s*=\s*matrix\s*\[\s*current\s*\]\s*\[\s*\w+\s*\]/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
```
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac8
|
||||
title: Step 17
|
||||
challengeType: 1
|
||||
dashedName: step-17
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Before updating distances, you need to verify the neighbor is worth considering. There must be an actual edge to it (`distance !== INF`) and it must not have been visited yet.
|
||||
|
||||
Inside the neighbor `for` loop, add an `if` statement that checks if `distance` is not strictly equal to `INF` **and** if `nodeNo` is not visited.
|
||||
|
||||
Inside the `if` block, declare a variable `newDistance` assigned to `distances[current] + distance`. This is the total cost of reaching the neighbor through the current node.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add an `if` statement with the condition `distance !== INF && !visited[nodeNo]`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/if\s*\(\s*distance\s*!==\s*INF\s*&&\s*!\s*visited\s*\[\s*\w+\s*\]\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
You should declare a `newDistance` with the value `distances[current] + distance` inside the `if` block.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(const|let|var)\s+newDistance\s*=\s*distances\s*\[\s*current\s*\]\s*\+\s*distance/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bac9
|
||||
title: Step 18
|
||||
challengeType: 1
|
||||
dashedName: step-18
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you should check whether going through the current node gives a shorter route to the neighbor. If `newDistance` is better than what's already stored, then you should update it.
|
||||
|
||||
Inside the existing `if` block, add a nested `if` statement that checks if `newDistance` is less than `distances[nodeNo]`. Inside that nested `if` block, update `distances[nodeNo]` to `newDistance`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a nested `if` statement with the condition `newDistance < distances[nodeNo]`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/if\s*\(\s*newDistance\s*<\s*distances\s*\[\s*\w+\s*\]\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
You should update `distances[nodeNo]` to `newDistance` inside the nested `if` block.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/distances\s*\[\s*\w+\s*\]\s*=\s*newDistance/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1baca
|
||||
title: Step 19
|
||||
challengeType: 1
|
||||
dashedName: step-19
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
When you find a shorter path to a neighbor, you also need to update the recorded path to reach it.
|
||||
|
||||
In JavaScript, you can create a new array combining an existing array and a new element using the spread operator:
|
||||
|
||||
```js
|
||||
const newPath = [...existingArray, newElement];
|
||||
```
|
||||
|
||||
Inside the nested `if` block, update `paths[nodeNo]` to be the path to the current node with `nodeNo` appended at the end using spread syntax like so: `[...paths[current], nodeNo]`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should update `paths[nodeNo]` inside the nested `if` block.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/paths\s*\[\s*\w+\s*\]\s*=/
|
||||
);
|
||||
```
|
||||
|
||||
`paths[nodeNo]` should be set to `[...paths[current], nodeNo]`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/paths\s*\[\s*\w+\s*\]\s*=\s*\[\s*\.\.\.\s*paths\s*\[\s*current\s*\]\s*,\s*\w+\s*\]/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
if (newDistance < distances[nodeNo]) {
|
||||
distances[nodeNo] = newDistance;
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bacb
|
||||
title: Step 20
|
||||
challengeType: 1
|
||||
dashedName: step-20
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Once the main loop finishes, you need to decide which node(s) to display results for.
|
||||
|
||||
If a specific `targetNode` was provided, only show results for that node. Otherwise, show results for all nodes.
|
||||
|
||||
In JavaScript, you can get all indices of an array as an iterable using `[...Array(n).keys()]`.
|
||||
|
||||
After the outer `for` loop, create a variable named `targets`. Using a ternary expression, if `targetNode` is strictly not `null`, assign `[targetNode]`, otherwise assign `[...Array(n).keys()]`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a variable `targets` after the main loop.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/(const|let|var)\s+targets\s*=/
|
||||
);
|
||||
```
|
||||
|
||||
Your `targets` variable should use a ternary checking `targetNode !== null`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/targets\s*=\s*targetNode\s*!==\s*null\s*\?/
|
||||
);
|
||||
```
|
||||
|
||||
When a target is provided, `targets` should be `[targetNode]`, otherwise it should be `[...Array(n).keys()]`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/\?\s*\[\s*targetNode\s*\]\s*:\s*\[\s*\.\.\.\s*Array\s*\(\s*n\s*\)\s*\.keys\s*\(\s*\)\s*\]/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
if (newDistance < distances[nodeNo]) {
|
||||
distances[nodeNo] = newDistance;
|
||||
paths[nodeNo] = [...paths[current], nodeNo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bacc
|
||||
title: Step 21
|
||||
challengeType: 1
|
||||
dashedName: step-21
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now loop through the target nodes to display results for each one.
|
||||
|
||||
Add a `for...of` loop that iterates over `targets` using `nodeNo` as the loop variable. Leave the body empty for now.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should create a `for...of` loop with the variable `nodeNo` iterating over `targets`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(code),
|
||||
/for\s*\(\s*(const|let)\s+nodeNo\s+of\s+targets\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
if (newDistance < distances[nodeNo]) {
|
||||
distances[nodeNo] = newDistance;
|
||||
paths[nodeNo] = [...paths[current], nodeNo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const targets = targetNode !== null ? [targetNode] : [...Array(n).keys()];
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bacd
|
||||
title: Step 22
|
||||
challengeType: 1
|
||||
dashedName: step-22
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You only want to display results for nodes that are reachable and different from the start node.
|
||||
|
||||
Inside the `for...of` loop, add an `if` statement that checks if `nodeNo` is strictly equal to `startNode` **or** `distances[nodeNo]` is strictly equal to `INF`. If either is true, use `continue` inside the `if` block to skip to the next iteration.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `if` statement with the condition `nodeNo === startNode || distances[nodeNo] === INF` inside your `for...of` loop.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/if\s*\(\s*\w+\s*===\s*startNode\s*\|\|\s*distances\s*\[\s*\w+\s*\]\s*===\s*INF\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
You should use `continue` in the `if` block.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/if\s*\(\s*\w+\s*===\s*startNode\s*\|\|\s*distances\s*\[\s*\w+\s*\]\s*===\s*INF\s*\)[\s\S]*?continue/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
if (newDistance < distances[nodeNo]) {
|
||||
distances[nodeNo] = newDistance;
|
||||
paths[nodeNo] = [...paths[current], nodeNo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const targets = targetNode !== null ? [targetNode] : [...Array(n).keys()];
|
||||
--fcc-editable-region--
|
||||
for (const nodeNo of targets) {
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bace
|
||||
title: Step 23
|
||||
challengeType: 1
|
||||
dashedName: step-23
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that you know the node is reachable and not the start, format its path into a readable string.
|
||||
|
||||
The `paths[nodeNo]` array holds the sequence of node indices visited to reach `nodeNo`. You can turn that into a human-readable string like `0 -> 2 -> 3` using the `.join()` method.
|
||||
|
||||
Inside the `for...of` loop, after the `if` statement with `continue`, declare a variable named `path` and assign it the value `paths[nodeNo].join(' -> ')`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable named `path` inside the `for...of` loop.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(code),
|
||||
/for\s*\(\s*(const|let)\s+nodeNo\s+of\s+targets\s*\)[\s\S]*?(const|let)\s+path\s*=/
|
||||
);
|
||||
```
|
||||
|
||||
Your `path` variable should have the value `paths[nodeNo].join(' -> ')`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(code),
|
||||
/path\s*=\s*paths\s*\[\s*\w+\s*\]\s*\.\s*join\s*\(\s*['"]\s*->\s*['"]\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
if (newDistance < distances[nodeNo]) {
|
||||
distances[nodeNo] = newDistance;
|
||||
paths[nodeNo] = [...paths[current], nodeNo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const targets = targetNode !== null ? [targetNode] : [...Array(n).keys()];
|
||||
for (const nodeNo of targets) {
|
||||
if (nodeNo === startNode || distances[nodeNo] === INF) {
|
||||
continue;
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
```
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bacf
|
||||
title: Step 24
|
||||
challengeType: 1
|
||||
dashedName: step-24
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, you should print the result for each reachable node.
|
||||
|
||||
After the `path` variable, add a `console.log()` call with a template literal that outputs:
|
||||
|
||||
```md
|
||||
\n{startNode}-{nodeNo} distance: {distances[nodeNo]}\nPath: {path}
|
||||
```
|
||||
|
||||
For example, if `startNode` is `0` and `nodeNo` is `3`, the output should look like this:
|
||||
|
||||
```md
|
||||
0-3 distance: 4
|
||||
Path: 0 -> 2 -> 3
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `console.log()` inside the `for...of` loop.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(code),
|
||||
/for\s*\(\s*(const|let)\s+nodeNo\s+of\s+targets\s*\)[\s\S]*?console\s*\.\s*log\s*\(/
|
||||
);
|
||||
```
|
||||
|
||||
The `console.log()` should use a template literal containing `${startNode}-${nodeNo} distance: ${distances[nodeNo]}`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(code),
|
||||
/console\s*\.\s*log\s*\(\s*`[\s\S]*?\$\{\s*startNode\s*\}[\s\S]*?\$\{\s*nodeNo\s*\}[\s\S]*?\$\{\s*distances\s*\[\s*nodeNo\s*\]\s*\}[\s\S]*?`\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
The template literal should also include `${path}`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(code),
|
||||
/console\s*\.\s*log\s*\(\s*`[\s\S]*?\$\{\s*path\s*\}[\s\S]*?`\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
if (newDistance < distances[nodeNo]) {
|
||||
distances[nodeNo] = newDistance;
|
||||
paths[nodeNo] = [...paths[current], nodeNo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const targets = targetNode !== null ? [targetNode] : [...Array(n).keys()];
|
||||
for (const nodeNo of targets) {
|
||||
if (nodeNo === startNode || distances[nodeNo] === INF) {
|
||||
continue;
|
||||
}
|
||||
const path = paths[nodeNo].join(' -> ');
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
}
|
||||
```
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bad0
|
||||
title: Step 25
|
||||
challengeType: 1
|
||||
dashedName: step-25
|
||||
---
|
||||
|
||||
|
||||
# --description--
|
||||
|
||||
The function should return the computed data so callers can use it programmatically.
|
||||
|
||||
After the `for...of` loop, add a `return` statement that returns an array containing `distances` and `paths`, in that order.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should return `[distances, paths]` after the `for...of` loop.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(shortestPath.toString()),
|
||||
/return\s*\[\s*distances\,\s*paths\]/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
if (newDistance < distances[nodeNo]) {
|
||||
distances[nodeNo] = newDistance;
|
||||
paths[nodeNo] = [...paths[current], nodeNo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const targets = targetNode !== null ? [targetNode] : [...Array(n).keys()];
|
||||
for (const nodeNo of targets) {
|
||||
if (nodeNo === startNode || distances[nodeNo] === INF) {
|
||||
continue;
|
||||
}
|
||||
const path = paths[nodeNo].join(' -> ');
|
||||
console.log(`\n${startNode}-${nodeNo} distance: ${distances[nodeNo]}\nPath: ${path}`);
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
}
|
||||
```
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
---
|
||||
id: 69c918841987bf16c1d1bad1
|
||||
title: Step 26
|
||||
challengeType: 1
|
||||
dashedName: step-26
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The function is complete. Now call it to see the results.
|
||||
|
||||
At the bottom of the file (outside the function), call `shortestPath` with `adjMatrix` as the matrix, `0` as the start node, and `5` as the target node.
|
||||
|
||||
This will print the shortest path from node `0` to node `5` in the adjacency matrix.
|
||||
|
||||
With that, your shortest path algorithm workshop is complete!
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call the `shortestPath` function with `adjMatrix, 0, 5`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(code),
|
||||
/shortestPath\s*\(\s*adjMatrix\s*,\s*0\s*,\s*5\s*\)/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
if (newDistance < distances[nodeNo]) {
|
||||
distances[nodeNo] = newDistance;
|
||||
paths[nodeNo] = [...paths[current], nodeNo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const targets = targetNode !== null ? [targetNode] : [...Array(n).keys()];
|
||||
for (const nodeNo of targets) {
|
||||
if (nodeNo === startNode || distances[nodeNo] === INF) {
|
||||
continue;
|
||||
}
|
||||
const path = paths[nodeNo].join(' -> ');
|
||||
console.log(`\n${startNode}-${nodeNo} distance: ${distances[nodeNo]}\nPath: ${path}`);
|
||||
}
|
||||
return [distances, paths];
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
function shortestPath(matrix, startNode, targetNode = null) {
|
||||
const n = matrix.length;
|
||||
const distances = new Array(n).fill(INF);
|
||||
distances[startNode] = 0;
|
||||
const paths = Array.from({ length: n }, (_, i) => [i]);
|
||||
const visited = new Array(n).fill(false);
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
let minDistance = INF;
|
||||
let current = -1;
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
if (!visited[nodeNo] && distances[nodeNo] < minDistance) {
|
||||
minDistance = distances[nodeNo];
|
||||
current = nodeNo;
|
||||
}
|
||||
}
|
||||
if (current === -1) {
|
||||
break;
|
||||
}
|
||||
visited[current] = true;
|
||||
|
||||
for (let nodeNo = 0; nodeNo < n; nodeNo++) {
|
||||
const distance = matrix[current][nodeNo];
|
||||
if (distance !== INF && !visited[nodeNo]) {
|
||||
const newDistance = distances[current] + distance;
|
||||
if (newDistance < distances[nodeNo]) {
|
||||
distances[nodeNo] = newDistance;
|
||||
paths[nodeNo] = [...paths[current], nodeNo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const targets = targetNode !== null ? [targetNode] : [...Array(n).keys()];
|
||||
for (const nodeNo of targets) {
|
||||
if (nodeNo === startNode || distances[nodeNo] === INF) {
|
||||
continue;
|
||||
}
|
||||
const path = paths[nodeNo].join(' -> ');
|
||||
console.log(`\n${startNode}-${nodeNo} distance: ${distances[nodeNo]}\nPath: ${path}`);
|
||||
}
|
||||
return [distances, paths];
|
||||
}
|
||||
|
||||
shortestPath(adjMatrix, 0, 5);
|
||||
```
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: 69c937c73f23b1140bcd297a
|
||||
title: Step 4
|
||||
challengeType: 1
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `targetNode` parameter is optional. When not provided, the function will compute shortest paths from `startNode` to all other nodes in the graph.
|
||||
|
||||
Give the `targetNode` parameter a default value of `null`.
|
||||
|
||||
# --hints--
|
||||
|
||||
The `targetNode` parameter of your `shortestPath` function should default to `null`.
|
||||
|
||||
```js
|
||||
assert.match(
|
||||
__helpers.removeJSComments(code),
|
||||
/targetNode\s*=\s*null/
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
const INF = Infinity;
|
||||
const adjMatrix = [
|
||||
[0, 5, 3, INF, 11, INF],
|
||||
[5, 0, 1, INF, INF, 2],
|
||||
[3, 1, 0, 1, 5, INF],
|
||||
[INF, INF, 1, 0, 9, 3],
|
||||
[11, INF, 5, 9, 0, INF],
|
||||
[INF, 2, INF, 3, INF, 0],
|
||||
];
|
||||
|
||||
--fcc-editable-region--
|
||||
function shortestPath(matrix, startNode, targetNode) {
|
||||
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"isUpcomingChange": true,
|
||||
"dashedName": "workshop-shortest-path-algorithm-js",
|
||||
"helpCategory": "JavaScript",
|
||||
"blockLayout": "challenge-grid",
|
||||
"blockLabel": "workshop",
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true,
|
||||
"challengeOrder": [
|
||||
{ "id": "0095d0567b6817114989a1dd", "title": "Step 1" },
|
||||
{ "id": "69c918841987bf16c1d1baba", "title": "Step 2" },
|
||||
{ "id": "69c918841987bf16c1d1babb", "title": "Step 3" },
|
||||
{ "id": "69c937c73f23b1140bcd297a", "title": "Step 4" },
|
||||
{ "id": "69c918841987bf16c1d1babc", "title": "Step 5" },
|
||||
{ "id": "69c918841987bf16c1d1babd", "title": "Step 6" },
|
||||
{ "id": "69c918841987bf16c1d1babe", "title": "Step 7" },
|
||||
{ "id": "69c918841987bf16c1d1babf", "title": "Step 8" },
|
||||
{ "id": "69c918841987bf16c1d1bac0", "title": "Step 9" },
|
||||
{ "id": "69c918841987bf16c1d1bac1", "title": "Step 10" },
|
||||
{ "id": "69c918841987bf16c1d1bac2", "title": "Step 11" },
|
||||
{ "id": "69c918841987bf16c1d1bac3", "title": "Step 12" },
|
||||
{ "id": "69c918841987bf16c1d1bac4", "title": "Step 13" },
|
||||
{ "id": "69c918841987bf16c1d1bac5", "title": "Step 14" },
|
||||
{ "id": "69c918841987bf16c1d1bac6", "title": "Step 15" },
|
||||
{ "id": "69c918841987bf16c1d1bac7", "title": "Step 16" },
|
||||
{ "id": "69c918841987bf16c1d1bac8", "title": "Step 17" },
|
||||
{ "id": "69c918841987bf16c1d1bac9", "title": "Step 18" },
|
||||
{ "id": "69c918841987bf16c1d1baca", "title": "Step 19" },
|
||||
{ "id": "69c918841987bf16c1d1bacb", "title": "Step 20" },
|
||||
{ "id": "69c918841987bf16c1d1bacc", "title": "Step 21" },
|
||||
{ "id": "69c918841987bf16c1d1bacd", "title": "Step 22" },
|
||||
{ "id": "69c918841987bf16c1d1bace", "title": "Step 23" },
|
||||
{ "id": "69c918841987bf16c1d1bacf", "title": "Step 24" },
|
||||
{ "id": "69c918841987bf16c1d1bad0", "title": "Step 25" },
|
||||
{ "id": "69c918841987bf16c1d1bad1", "title": "Step 26" }
|
||||
]
|
||||
}
|
||||
@@ -329,6 +329,7 @@
|
||||
"comingSoon": true,
|
||||
"blocks": [
|
||||
"lecture-understanding-graphs-and-trees-js",
|
||||
"workshop-shortest-path-algorithm-js",
|
||||
"lab-adjacency-list-to-matrix-converter-js",
|
||||
"workshop-breadth-first-search-js",
|
||||
"lab-depth-first-search-js",
|
||||
|
||||
Reference in New Issue
Block a user