Skip to content

Commit 73c5c1e

Browse files
committed
Adding Weighted Path CoderByte solution
1 parent a7b185f commit 73c5c1e

File tree

3 files changed

+109
-1
lines changed

3 files changed

+109
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ Solutions to various challenges published at www.hackerrank.com
464464

465465
* Binary Search Tree LCA
466466
* Shortest Path in Unweighted Graph with cycles
467-
467+
* Weighted Path
468468

469469
## Contributing
470470

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from typing import List
2+
from typing import Tuple
3+
from typing import Union
4+
5+
6+
class WeightedPath:
7+
INF = float('infinity')
8+
9+
@staticmethod
10+
def make_lists(vertices: List[str],
11+
triplets: List[Tuple[str, str, int]]) -> Tuple[dict, dict]:
12+
adj = {}
13+
edges = {}
14+
for v in vertices:
15+
adj[v] = {}
16+
edges[v] = {}
17+
for w in vertices:
18+
adj[v][w] = WeightedPath.INF
19+
edges[v][w] = {}
20+
for t in triplets:
21+
adj[t[0]][t[1]] = int(t[2])
22+
adj[t[1]][t[0]] = int(t[2])
23+
# graph will have cycles.
24+
edges[t[0]][t[1]] = [t[0], t[1], int(t[2])]
25+
edges[t[1]][t[0]] = [t[1], t[0], int(t[2])]
26+
return adj, edges
27+
28+
@classmethod
29+
def path(cls, s: str, t: str, edge_to: dict,
30+
distances: dict) -> List[str]:
31+
if not (distances[s][t] < cls.INF):
32+
return []
33+
paths = []
34+
e = edge_to[s][t]
35+
while e:
36+
paths.append(e)
37+
# graph is cyclic, should stop on cycle
38+
if e[0] == s:
39+
break
40+
e = edge_to[s][e[0]]
41+
return paths
42+
43+
@classmethod
44+
def fw_traverse(cls, vertices: List[str],
45+
triplets: List[Tuple[str, str, int]]) -> Tuple[dict, dict]:
46+
"""
47+
Floyd-Warshall traversal. Can handle negative weights,
48+
Dijkstra's algorithm works only with positive weights.
49+
"""
50+
distances, edge_to = cls.make_lists(vertices, triplets)
51+
nodes = distances.keys()
52+
for i in nodes:
53+
for v in nodes:
54+
if not edge_to[v][i]:
55+
continue
56+
for w in nodes:
57+
if distances[v][w] > distances[v][i] + distances[i][w]:
58+
distances[v][w] = distances[v][i] + distances[i][w]
59+
edge_to[v][w] = edge_to[i][w]
60+
return edge_to, distances
61+
62+
def __call__(self, str_arr: List[str]) -> Union[str, int]:
63+
node_len = int(str_arr[0])
64+
vertices = str_arr[1:node_len + 1]
65+
triplets = [x.split('|') for x in str_arr[node_len + 1:]]
66+
edges, distances = self.fw_traverse(vertices, triplets)
67+
# compute shortest paths using Floyd - Warshall algorithm.
68+
sp = self.path(vertices[0], vertices[node_len - 1], edges, distances)
69+
# if list is empty - no path
70+
if len(sp) == 0:
71+
return -1
72+
else:
73+
xs = [vertices[node_len - 1]]
74+
xs += [x[0] for x in sp]
75+
xs.reverse()
76+
return "-".join(xs)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from py_algorithms.challenges.coderbyte.weighted_path import WeightedPath
2+
3+
4+
class TestWeightedPath:
5+
def test_impl(self):
6+
inputs = {
7+
"A-B-C-D-F-G": ["7", "A", "B", "C", "D", "E", "F", "G",
8+
"A|B|1", "A|E|9", "B|C|2", "C|D|1", "D|F|2",
9+
"E|D|6", "F|G|2"],
10+
"A-B-C-D": ["4", "A", "B", "C", "D", "A|B|1", "B|D|9", "B|C|3",
11+
"C|D|4"],
12+
-1: ["4", "x", "y", "z", "w", "x|y|2", "y|z|14", "z|y|31"],
13+
"A-B-D": ["4", "A", "B", "C", "D", "A|B|2", "C|B|11", "C|D|3",
14+
"B|D|2"],
15+
"A-B-D-E-F": ["6", "A", "B", "C", "D", "E", "F", "B|A|2",
16+
"A|F|12", "A|C|4", "B|D|1", "D|E|1", "C|D|4",
17+
"F|E|1"],
18+
"D-B-A-F": ["6", "D", "B", "C", "A", "E", "F", "B|A|2",
19+
"A|F|3", "A|C|4", "B|D|1", "D|E|12", "C|D|4",
20+
"F|E|1"],
21+
"C-D-F-G-E-B-H": ["8", "C", "B", "A", "D", "E", "F", "G",
22+
"H", "C|D|1", "D|F|2", "G|F|2", "G|E|1", "E|B|1",
23+
"H|B|1", "C|A|13", "B|A|2", "C|E|9"],
24+
"GG-HH-JJ": ["3", "GG", "HH", "JJ", "GG|JJ|6", "GG|HH|2", "JJ|HH|2"],
25+
"C-E-B-H": ["8", "C", "B", "A", "D", "E", "F", "G", "H", "C|D|1",
26+
"D|F|2", "G|F|2", "G|E|1", "E|B|1", "H|B|1",
27+
"C|A|13", "B|A|2", "C|E|1"]
28+
}
29+
30+
f = WeightedPath()
31+
for key in inputs:
32+
assert f(inputs[key]) == key

0 commit comments

Comments
 (0)